//// /// Copyright (c) 2016 Martin Donath /// /// Permission is hereby granted, free of charge, to any person obtaining a /// copy of this software and associated documentation files (the "Software"), /// to deal in the Software without restriction, including without limitation /// the rights to use, copy, modify, merge, publish, distribute, sublicense, /// and/or sell copies of the Software, and to permit persons to whom the /// Software is furnished to do so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in /// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL /// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING /// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER /// DEALINGS //// // ---------------------------------------------------------------------------- // Variables // ---------------------------------------------------------------------------- /// /// Device-specific breakpoints /// /// @example /// $break-devices: ( /// mobile: ( /// portrait: 220px 479px, /// landscape: 480px 719px /// ), /// tablet: ( /// portrait: 720px 959px, /// landscape: 960px 1199px /// ), /// screen: ( /// small: 1200px 1599px, /// medium: 1600px 1999px, /// large: 2000px /// ) /// ); /// /// @group helpers /// @access private /// @type Map /// $break-devices: () !default; // ---------------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------------- /// /// Choose minimum and maximum device widths /// /// @group helpers /// @access private /// @param {Map} $devices Map of devices /// @return {List} Minimum and maximum width /// @function break-select-min-max($devices) { $min: 1000000; $max: 0; @each $key, $value in $devices { @while type-of($value) == map { $value: break-select-min-max($value); } @if type-of($value) == list { @each $number in $value { @if type-of($number) == number { $min: min($number, $min); @if $max != null { $max: max($number, $max); } } @else { @error "Invalid number: #{$number}"; } } } @elseif type-of($value) == number { $min: min($value, $min); $max: null; } @else { @error "Invalid value: #{$value}"; } } @return $min, $max; } /// /// Select minimum and maximum widths for a device breakpoint /// /// @group helpers /// @access private /// @param {String} $device Device /// @return {List} Minimum and maximum width /// @function break-select-device($device) { $current: $break-devices; @for $n from 1 through length($device) { @if type-of($current) == map { $current: map-get($current, nth($device, $n)); } @else { @error "Invalid device map: #{$devices}"; } } @if type-of($current) == list or type-of($current) == number { $current: (default: $current); } @return break-select-min-max($current); } // ---------------------------------------------------------------------------- // Mixins // ---------------------------------------------------------------------------- /// /// A minimum-maximum media query breakpoint /// /// @group helpers /// @access public /// @param {Number|List} $breakpoint Number or number pair /// @mixin break-at($breakpoint) { @if type-of($breakpoint) == number { @media only screen and (min-width: $breakpoint) { @content; } } @elseif type-of($breakpoint) == list { $min: nth($breakpoint, 1); $max: nth($breakpoint, 2); @if type-of($min) == number and type-of($max) == number { @media only screen and (min-width: $min) and (max-width: $max) { @content; } } @else { @error "Invalid breakpoint: #{$breakpoint}"; } } @else { @error "Invalid breakpoint: #{$breakpoint}"; } } /// /// An orientation media query breakpoint /// /// @group helpers /// @access public /// @param {String} $breakpoint Orientation /// @mixin break-at-orientation($breakpoint) { @if type-of($breakpoint) == string { @media only screen and (orientation: $breakpoint) { @content; } } @else { @error "Invalid breakpoint: #{$breakpoint}"; } } /// /// A maximum-aspect-ratio media query breakpoint /// /// @group helpers /// @access public /// @param {Number} $breakpoint Ratio /// @mixin break-at-ratio($breakpoint) { @if type-of($breakpoint) == number { @media only screen and (max-aspect-ratio: $breakpoint) { @content; } } @else { @error "Invalid breakpoint: #{$breakpoint}"; } } /// /// A minimum-maximum media query device breakpoint /// /// @group helpers /// @access public /// @param {String|List} $breakpoint Device /// @mixin break-at-device($device) { @if type-of($device) == string { $device: $device,; } @if type-of($device) == list { $breakpoint: break-select-device($device); @if nth($breakpoint, 2) != null { $min: nth($breakpoint, 1); $max: nth($breakpoint, 2); @media only screen and (min-width: $min) and (max-width: $max) { @content; } } @else { @error "Invalid device: #{$device}"; } } @else { @error "Invalid device: #{$device}"; } } /// /// A minimum media query device breakpoint /// /// @group helpers /// @access public /// @param {String|List} $breakpoint Device /// @mixin break-from-device($device) { @if type-of($device) == string { $device: $device,; } @if type-of($device) == list { $breakpoint: break-select-device($device); $min: nth($breakpoint, 1); @media only screen and (min-width: $min) { @content; } } @else { @error "Invalid device: #{$device}"; } } /// /// A maximum media query device breakpoint /// /// @group helpers /// @access public /// @param {String|List} $breakpoint Device /// @mixin break-to-device($device) { @if type-of($device) == string { $device: $device,; } @if type-of($device) == list { $breakpoint: break-select-device($device); $max: nth($breakpoint, 2); @media only screen and (max-width: $max) { @content; } } @else { @error "Invalid device: #{$device}"; } }