|
- @charset "UTF-8";
-
- // _ _ _ _ _
- // (_) | | | | | (_)
- // _ _ __ ___| |_ _ __| | ___ _ __ ___ ___ __| |_ __ _
- // | | '_ \ / __| | | | |/ _` |/ _ \ | '_ ` _ \ / _ \/ _` | |/ _` |
- // | | | | | (__| | |_| | (_| | __/ | | | | | | __/ (_| | | (_| |
- // |_|_| |_|\___|_|\__,_|\__,_|\___| |_| |_| |_|\___|\__,_|_|\__,_|
- //
- // Simple, elegant and maintainable media queries in Sass
- // v1.4.9
- //
- // https://eduardoboucas.github.io/include-media
- //
- // Authors: Eduardo Boucas (@eduardoboucas)
- // Hugo Giraudel (@hugogiraudel)
- //
- // This project is licensed under the terms of the MIT license
- ////
- /// include-media library public configuration
- /// @author Eduardo Boucas
- /// @access public
- ////
-
-
- ///
- /// Creates a list of global breakpoints
- ///
- /// @example scss - Creates a single breakpoint with the label `phone`
- /// $breakpoints: ('phone': 320px);
- ///
- $breakpoints: (
- 'phone': 320px,
- 'tablet': 768px,
- 'desktop': 1024px
- ) !default;
-
-
- ///
- /// Creates a list of static expressions or media types
- ///
- /// @example scss - Creates a single media type (screen)
- /// $media-expressions: ('screen': 'screen');
- ///
- /// @example scss - Creates a static expression with logical disjunction (OR operator)
- /// $media-expressions: (
- /// 'retina2x': '(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)'
- /// );
- ///
- $media-expressions: (
- 'screen': 'screen',
- 'print': 'print',
- 'handheld': 'handheld',
- 'landscape': '(orientation: landscape)',
- 'portrait': '(orientation: portrait)',
- 'retina2x': '(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi), (min-resolution: 2dppx)',
- 'retina3x': '(-webkit-min-device-pixel-ratio: 3), (min-resolution: 350dpi), (min-resolution: 3dppx)'
- ) !default;
-
-
- ///
- /// Defines a number to be added or subtracted from each unit when declaring breakpoints with exclusive intervals
- ///
- /// @example scss - Interval for pixels is defined as `1` by default
- /// @include media('>128px') {}
- ///
- /// /* Generates: */
- /// @media (min-width: 129px) {}
- ///
- /// @example scss - Interval for ems is defined as `0.01` by default
- /// @include media('>20em') {}
- ///
- /// /* Generates: */
- /// @media (min-width: 20.01em) {}
- ///
- /// @example scss - Interval for rems is defined as `0.1` by default, to be used with `font-size: 62.5%;`
- /// @include media('>2.0rem') {}
- ///
- /// /* Generates: */
- /// @media (min-width: 2.1rem) {}
- ///
- $unit-intervals: (
- 'px': 1,
- 'em': 0.01,
- 'rem': 0.1,
- '': 0
- ) !default;
-
- ///
- /// Defines whether support for media queries is available, useful for creating separate stylesheets
- /// for browsers that don't support media queries.
- ///
- /// @example scss - Disables support for media queries
- /// $im-media-support: false;
- /// @include media('>=tablet') {
- /// .foo {
- /// color: tomato;
- /// }
- /// }
- ///
- /// /* Generates: */
- /// .foo {
- /// color: tomato;
- /// }
- ///
- $im-media-support: true !default;
-
- ///
- /// Selects which breakpoint to emulate when support for media queries is disabled. Media queries that start at or
- /// intercept the breakpoint will be displayed, any others will be ignored.
- ///
- /// @example scss - This media query will show because it intercepts the static breakpoint
- /// $im-media-support: false;
- /// $im-no-media-breakpoint: 'desktop';
- /// @include media('>=tablet') {
- /// .foo {
- /// color: tomato;
- /// }
- /// }
- ///
- /// /* Generates: */
- /// .foo {
- /// color: tomato;
- /// }
- ///
- /// @example scss - This media query will NOT show because it does not intercept the desktop breakpoint
- /// $im-media-support: false;
- /// $im-no-media-breakpoint: 'tablet';
- /// @include media('>=desktop') {
- /// .foo {
- /// color: tomato;
- /// }
- /// }
- ///
- /// /* No output */
- ///
- $im-no-media-breakpoint: 'desktop' !default;
-
- ///
- /// Selects which media expressions are allowed in an expression for it to be used when media queries
- /// are not supported.
- ///
- /// @example scss - This media query will show because it intercepts the static breakpoint and contains only accepted media expressions
- /// $im-media-support: false;
- /// $im-no-media-breakpoint: 'desktop';
- /// $im-no-media-expressions: ('screen');
- /// @include media('>=tablet', 'screen') {
- /// .foo {
- /// color: tomato;
- /// }
- /// }
- ///
- /// /* Generates: */
- /// .foo {
- /// color: tomato;
- /// }
- ///
- /// @example scss - This media query will NOT show because it intercepts the static breakpoint but contains a media expression that is not accepted
- /// $im-media-support: false;
- /// $im-no-media-breakpoint: 'desktop';
- /// $im-no-media-expressions: ('screen');
- /// @include media('>=tablet', 'retina2x') {
- /// .foo {
- /// color: tomato;
- /// }
- /// }
- ///
- /// /* No output */
- ///
- $im-no-media-expressions: ('screen', 'portrait', 'landscape') !default;
-
- ////
- /// Cross-engine logging engine
- /// @author Hugo Giraudel
- /// @access private
- ////
-
-
- ///
- /// Log a message either with `@error` if supported
- /// else with `@warn`, using `feature-exists('at-error')`
- /// to detect support.
- ///
- /// @param {String} $message - Message to log
- ///
- @function im-log($message) {
- @if feature-exists('at-error') {
- @error $message;
- } @else {
- @warn $message;
- $_: noop();
- }
-
- @return $message;
- }
-
-
- ///
- /// Wrapper mixin for the log function so it can be used with a more friendly
- /// API than `@if im-log('..') {}` or `$_: im-log('..')`. Basically, use the function
- /// within functions because it is not possible to include a mixin in a function
- /// and use the mixin everywhere else because it's much more elegant.
- ///
- /// @param {String} $message - Message to log
- ///
- @mixin log($message) {
- @if im-log($message) {}
- }
-
-
- ///
- /// Function with no `@return` called next to `@warn` in Sass 3.3
- /// to trigger a compiling error and stop the process.
- ///
- @function noop() {}
-
- ///
- /// Determines whether a list of conditions is intercepted by the static breakpoint.
- ///
- /// @param {Arglist} $conditions - Media query conditions
- ///
- /// @return {Boolean} - Returns true if the conditions are intercepted by the static breakpoint
- ///
- @function im-intercepts-static-breakpoint($conditions...) {
- $no-media-breakpoint-value: map-get($breakpoints, $im-no-media-breakpoint);
-
- @if not $no-media-breakpoint-value {
- @if im-log('`#{$im-no-media-breakpoint}` is not a valid breakpoint.') {}
- }
-
- @each $condition in $conditions {
- @if not map-has-key($media-expressions, $condition) {
- $operator: get-expression-operator($condition);
- $prefix: get-expression-prefix($operator);
- $value: get-expression-value($condition, $operator);
-
- @if ($prefix == 'max' and $value <= $no-media-breakpoint-value) or
- ($prefix == 'min' and $value > $no-media-breakpoint-value) {
- @return false;
- }
- } @else if not index($im-no-media-expressions, $condition) {
- @return false;
- }
- }
-
- @return true;
- }
-
- ////
- /// Parsing engine
- /// @author Hugo Giraudel
- /// @access private
- ////
-
-
- ///
- /// Get operator of an expression
- ///
- /// @param {String} $expression - Expression to extract operator from
- ///
- /// @return {String} - Any of `>=`, `>`, `<=`, `<`, `≥`, `≤`
- ///
- @function get-expression-operator($expression) {
- @each $operator in ('>=', '>', '<=', '<', '≥', '≤') {
- @if str-index($expression, $operator) {
- @return $operator;
- }
- }
-
- // It is not possible to include a mixin inside a function, so we have to
- // rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
- // functions cannot be called anywhere in Sass, we need to hack the call in
- // a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
- // Sass 3.3, change this line in `@if im-log(..) {}` instead.
- $_: im-log('No operator found in `#{$expression}`.');
- }
-
-
- ///
- /// Get dimension of an expression, based on a found operator
- ///
- /// @param {String} $expression - Expression to extract dimension from
- /// @param {String} $operator - Operator from `$expression`
- ///
- /// @return {String} - `width` or `height` (or potentially anything else)
- ///
- @function get-expression-dimension($expression, $operator) {
- $operator-index: str-index($expression, $operator);
- $parsed-dimension: str-slice($expression, 0, $operator-index - 1);
- $dimension: 'width';
-
- @if str-length($parsed-dimension) > 0 {
- $dimension: $parsed-dimension;
- }
-
- @return $dimension;
- }
-
-
- ///
- /// Get dimension prefix based on an operator
- ///
- /// @param {String} $operator - Operator
- ///
- /// @return {String} - `min` or `max`
- ///
- @function get-expression-prefix($operator) {
- @return if(index(('<', '<=', '≤'), $operator), 'max', 'min');
- }
-
-
- ///
- /// Get value of an expression, based on a found operator
- ///
- /// @param {String} $expression - Expression to extract value from
- /// @param {String} $operator - Operator from `$expression`
- ///
- /// @return {Number} - A numeric value
- ///
- @function get-expression-value($expression, $operator) {
- $operator-index: str-index($expression, $operator);
- $value: str-slice($expression, $operator-index + str-length($operator));
-
- @if map-has-key($breakpoints, $value) {
- $value: map-get($breakpoints, $value);
- } @else {
- $value: to-number($value);
- }
-
- $interval: map-get($unit-intervals, unit($value));
-
- @if not $interval {
- // It is not possible to include a mixin inside a function, so we have to
- // rely on the `im-log(..)` function rather than the `log(..)` mixin. Because
- // functions cannot be called anywhere in Sass, we need to hack the call in
- // a dummy variable, such as `$_`. If anybody ever raise a scoping issue with
- // Sass 3.3, change this line in `@if im-log(..) {}` instead.
- $_: im-log('Unknown unit `#{unit($value)}`.');
- }
-
- @if $operator == '>' {
- $value: $value + $interval;
- } @else if $operator == '<' {
- $value: $value - $interval;
- }
-
- @return $value;
- }
-
-
- ///
- /// Parse an expression to return a valid media-query expression
- ///
- /// @param {String} $expression - Expression to parse
- ///
- /// @return {String} - Valid media query
- ///
- @function parse-expression($expression) {
- // If it is part of $media-expressions, it has no operator
- // then there is no need to go any further, just return the value
- @if map-has-key($media-expressions, $expression) {
- @return map-get($media-expressions, $expression);
- }
-
- $operator: get-expression-operator($expression);
- $dimension: get-expression-dimension($expression, $operator);
- $prefix: get-expression-prefix($operator);
- $value: get-expression-value($expression, $operator);
-
- @return '(#{$prefix}-#{$dimension}: #{$value})';
- }
-
- ///
- /// Slice `$list` between `$start` and `$end` indexes
- ///
- /// @access private
- ///
- /// @param {List} $list - List to slice
- /// @param {Number} $start [1] - Start index
- /// @param {Number} $end [length($list)] - End index
- ///
- /// @return {List} Sliced list
- ///
- @function slice($list, $start: 1, $end: length($list)) {
- @if length($list) < 1 or $start > $end {
- @return ();
- }
-
- $result: ();
-
- @for $i from $start through $end {
- $result: append($result, nth($list, $i));
- }
-
- @return $result;
- }
-
- ////
- /// String to number converter
- /// @author Hugo Giraudel
- /// @access private
- ////
-
-
- ///
- /// Casts a string into a number
- ///
- /// @param {String | Number} $value - Value to be parsed
- ///
- /// @return {Number}
- ///
- @function to-number($value) {
- @if type-of($value) == 'number' {
- @return $value;
- } @else if type-of($value) != 'string' {
- $_: im-log('Value for `to-number` should be a number or a string.');
- }
-
- $first-character: str-slice($value, 1, 1);
- $result: 0;
- $digits: 0;
- $minus: ($first-character == '-');
- $numbers: ('0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9);
-
- // Remove +/- sign if present at first character
- @if ($first-character == '+' or $first-character == '-') {
- $value: str-slice($value, 2);
- }
-
- @for $i from 1 through str-length($value) {
- $character: str-slice($value, $i, $i);
-
- @if not (index(map-keys($numbers), $character) or $character == '.') {
- @return to-length(if($minus, -$result, $result), str-slice($value, $i))
- }
-
- @if $character == '.' {
- $digits: 1;
- } @else if $digits == 0 {
- $result: $result * 10 + map-get($numbers, $character);
- } @else {
- $digits: $digits * 10;
- $result: $result + map-get($numbers, $character) / $digits;
- }
- }
-
- @return if($minus, -$result, $result);
- }
-
-
- ///
- /// Add `$unit` to `$value`
- ///
- /// @param {Number} $value - Value to add unit to
- /// @param {String} $unit - String representation of the unit
- ///
- /// @return {Number} - `$value` expressed in `$unit`
- ///
- @function to-length($value, $unit) {
- $units: ('px': 1px, 'cm': 1cm, 'mm': 1mm, '%': 1%, 'ch': 1ch, 'pc': 1pc, 'in': 1in, 'em': 1em, 'rem': 1rem, 'pt': 1pt, 'ex': 1ex, 'vw': 1vw, 'vh': 1vh, 'vmin': 1vmin, 'vmax': 1vmax);
-
- @if not index(map-keys($units), $unit) {
- $_: im-log('Invalid unit `#{$unit}`.');
- }
-
- @return $value * map-get($units, $unit);
- }
-
- ///
- /// This mixin aims at redefining the configuration just for the scope of
- /// the call. It is helpful when having a component needing an extended
- /// configuration such as custom breakpoints (referred to as tweakpoints)
- /// for instance.
- ///
- /// @author Hugo Giraudel
- ///
- /// @param {Map} $tweakpoints [()] - Map of tweakpoints to be merged with `$breakpoints`
- /// @param {Map} $tweak-media-expressions [()] - Map of tweaked media expressions to be merged with `$media-expression`
- ///
- /// @example scss - Extend the global breakpoints with a tweakpoint
- /// @include media-context(('custom': 678px)) {
- /// .foo {
- /// @include media('>phone', '<=custom') {
- /// // ...
- /// }
- /// }
- /// }
- ///
- /// @example scss - Extend the global media expressions with a custom one
- /// @include media-context($tweak-media-expressions: ('all': 'all')) {
- /// .foo {
- /// @include media('all', '>phone') {
- /// // ...
- /// }
- /// }
- /// }
- ///
- /// @example scss - Extend both configuration maps
- /// @include media-context(('custom': 678px), ('all': 'all')) {
- /// .foo {
- /// @include media('all', '>phone', '<=custom') {
- /// // ...
- /// }
- /// }
- /// }
- ///
- @mixin media-context($tweakpoints: (), $tweak-media-expressions: ()) {
- // Save global configuration
- $global-breakpoints: $breakpoints;
- $global-media-expressions: $media-expressions;
-
- // Update global configuration
- $breakpoints: map-merge($breakpoints, $tweakpoints) !global;
- $media-expressions: map-merge($media-expressions, $tweak-media-expressions) !global;
-
- @content;
-
- // Restore global configuration
- $breakpoints: $global-breakpoints !global;
- $media-expressions: $global-media-expressions !global;
- }
-
- ////
- /// include-media public exposed API
- /// @author Eduardo Boucas
- /// @access public
- ////
-
-
- ///
- /// Generates a media query based on a list of conditions
- ///
- /// @param {Arglist} $conditions - Media query conditions
- ///
- /// @example scss - With a single set breakpoint
- /// @include media('>phone') { }
- ///
- /// @example scss - With two set breakpoints
- /// @include media('>phone', '<=tablet') { }
- ///
- /// @example scss - With custom values
- /// @include media('>=358px', '<850px') { }
- ///
- /// @example scss - With set breakpoints with custom values
- /// @include media('>desktop', '<=1350px') { }
- ///
- /// @example scss - With a static expression
- /// @include media('retina2x') { }
- ///
- /// @example scss - Mixing everything
- /// @include media('>=350px', '<tablet', 'retina3x') { }
- ///
- @mixin media($conditions...) {
- @if ($im-media-support and length($conditions) == 0) or
- (not $im-media-support and im-intercepts-static-breakpoint($conditions...)) {
- @content;
- } @else if ($im-media-support and length($conditions) > 0) {
- @media #{unquote(parse-expression(nth($conditions, 1)))} {
- // Recursive call
- @include media(slice($conditions, 2)...) {
- @content;
- }
- }
- }
- }
|