// Skip down to line 1204 in the SCSS to see how to apply. The top 1200 lines are just the Breakpoint library. ////////////////////////////// // Default Variables ////////////////////////////// $Breakpoint-Settings: ( 'default media': all, 'default feature': min-width, 'default pair': width, 'force all media type': false, 'to ems': false, 'transform resolutions': true, 'no queries': false, 'no query fallbacks': false, 'base font size': 16px, 'legacy syntax': false ); $breakpoint: () !default; ////////////////////////////// // Imports ////////////////////////////// ////////////////////////////// // Settings ////////////////////////////// ////////////////////////////// // Has Setting ////////////////////////////// @function breakpoint-has($setting) { @if map-has-key($breakpoint, $setting) { @return true; } @else { @return false; } } ////////////////////////////// // Get Settings ////////////////////////////// @function breakpoint-get($setting) { @if breakpoint-has($setting) { @return map-get($breakpoint, $setting); } @else { @return map-get($Breakpoint-Settings, $setting); } } ////////////////////////////// // Set Settings ////////////////////////////// @function breakpoint-set($setting, $value) { @if (str-index($setting, '-') or str-index($setting, '_')) and str-index($setting, ' ') == null { @warn "Words in Breakpoint settings should be separated by spaces, not dashes or underscores. Please replace dashes and underscores between words with spaces. Settings will not work as expected until changed."; } $breakpoint: map-merge($breakpoint, ($setting: $value)) !global; @return true; } @mixin breakpoint-change($setting, $value) { $breakpoint-change: breakpoint-set($setting, $value); } @mixin breakpoint-set($setting, $value) { @include breakpoint-change($setting, $value); } @mixin bkpt-change($setting, $value) { @include breakpoint-change($setting, $value); } @mixin bkpt-set($setting, $value) { @include breakpoint-change($setting, $value); } ////////////////////////////// // Remove Setting ////////////////////////////// @function breakpoint-reset($settings...) { @if length($settings) == 1 { $settings: nth($settings, 1); } @each $setting in $settings { $breakpoint: map-remove($breakpoint, $setting) !global; } @return true; } @mixin breakpoint-reset($settings...) { $breakpoint-reset: breakpoint-reset($settings); } @mixin bkpt-reset($settings...) { $breakpoint-reset: breakpoint-reset($settings); } ////////////////////////////// // Context ////////////////////////////// ////////////////////////////// // Private Breakpoint Variables ////////////////////////////// $private-breakpoint-context-holder: (); $private-breakpoint-query-count: 0 !default; ////////////////////////////// // Breakpoint Has Context // Returns whether or not you are inside a Breakpoint query ////////////////////////////// @function breakpoint-has-context() { @if length($private-breakpoint-query-count) { @return true; } @else { @return false; } } ////////////////////////////// // Breakpoint Get Context // $feature: Input feature to get it's current MQ context. Returns false if no context ////////////////////////////// @function breakpoint-get-context($feature) { @if map-has-key($private-breakpoint-context-holder, $feature) { $get: map-get($private-breakpoint-context-holder, $feature); // Special handling of no-query from get side so /false/ prepends aren't returned @if $feature == 'no-query' { @if type-of($get) == 'list' and length($get) > 1 and nth($get, 1) == false { $get: nth($get, length($get)); } } @return $get; } @else { @if breakpoint-has-context() and $feature == 'media' { @return breakpoint-get('default media'); } @else { @return false; } } } ////////////////////////////// // Private function to set context ////////////////////////////// @function private-breakpoint-set-context($feature, $value) { @if $value == 'monochrome' { $feature: 'monochrome'; } $current: map-get($private-breakpoint-context-holder, $feature); @if $current and length($current) == $private-breakpoint-query-count { @warn "You have already queried against `#{$feature}`. Unexpected things may happen if you query against the same feature more than once in the same `and` query. Breakpoint is overwriting the current context with `#{$value}`"; } @if not map-has-key($private-breakpoint-context-holder, $feature) { $v-holder: (); @for $i from 1 to $private-breakpoint-query-count { @if $feature == 'media' { $v-holder: append($v-holder, breakpoint-get('default media')); } @else { $v-holder: append($v-holder, false); } } $v-holder: append($v-holder, $value); $private-breakpoint-context-holder: map-merge($private-breakpoint-context-holder, ($feature: $v-holder)) !global; } @else { $v-holder: map-get($private-breakpoint-context-holder, $feature); $length: length($v-holder); @for $i from $length to $private-breakpoint-query-count - 1 { @if $feature == 'media' { $v-holder: append($v-holder, breakpoint-get('default media')); } @else { $v-holder: append($v-holder, false); } } $v-holder: append($v-holder, $value); $private-breakpoint-context-holder: map-merge($private-breakpoint-context-holder, ($feature: $v-holder)) !global; } @return true; } ////////////////////////////// // Private function to reset context ////////////////////////////// @mixin private-breakpoint-reset-contexts { $private-breakpoint-context-holder: () !global; $private-breakpoint-query-count: 0 !global; } ////////////////////////////// // Helpers ////////////////////////////// ////////////////////////////// // Converts the input value to Base EMs ////////////////////////////// @function breakpoint-to-base-em($value) { $value-unit: unit($value); // Will convert relative EMs into root EMs. @if breakpoint-get('base font size') and type-of(breakpoint-get('base font size')) == 'number' and $value-unit == 'em' { $base-unit: unit(breakpoint-get('base font size')); @if $base-unit == 'px' or $base-unit == '%' or $base-unit == 'em' or $base-unit == 'pt' { @return base-conversion($value) / base-conversion(breakpoint-get('base font size')) * 1em; } @else { @warn '#{breakpoint-get(\'base font size\')} is not set in valid units for font size!'; @return false; } } @else { @return base-conversion($value); } } @function base-conversion($value) { $unit: unit($value); @if $unit == 'px' { @return $value / 16px * 1em; } @else if $unit == '%' { @return $value / 100% * 1em; } @else if $unit == 'em' { @return $value; } @else if $unit == 'pt' { @return $value / 12pt * 1em; } @else { @return $value; // @warn 'Everything is terrible! What have you done?!'; } } ////////////////////////////// // Returns whether the feature can have a min/max pair ////////////////////////////// $breakpoint-min-max-features: 'color', 'color-index', 'aspect-ratio', 'device-aspect-ratio', 'device-height', 'device-width', 'height', 'monochrome', 'resolution', 'width'; @function breakpoint-min-max($feature) { @each $item in $breakpoint-min-max-features { @if $feature == $item { @return true; } } @return false; } ////////////////////////////// // Returns whether the feature can have a string value ////////////////////////////// $breakpoint-string-features: 'orientation', 'scan', 'color', 'aspect-ratio', 'device-aspect-ratio', 'pointer', 'luminosity'; @function breakpoint-string-value($feature) { @each $item in $breakpoint-string-features { @if breakpoint-min-max($item) { @if $feature == 'min-#{$item}' or $feature == 'max-#{$item}' { @return true; } } @else if $feature == $item { @return true; } } @return false; } ////////////////////////////// // Returns whether the feature is a media type ////////////////////////////// $breakpoint-media-types: 'all', 'braille', 'embossed', 'handheld', 'print', 'projection', 'screen', 'speech', 'tty', 'tv'; @function breakpoint-is-media($feature) { @each $media in $breakpoint-media-types { @if ($feature == $media) or ($feature == 'not #{$media}') or ($feature == 'only #{$media}') { @return true; } } @return false; } ////////////////////////////// // Returns whether the feature can stand alone ////////////////////////////// $breakpoint-single-string-features: 'color', 'color-index', 'grid', 'monochrome'; @function breakpoint-single-string($feature) { @each $item in $breakpoint-single-string-features { @if $feature == $item { @return true; } } @return false; } ////////////////////////////// // Returns whether the feature ////////////////////////////// @function breakpoint-is-resolution($feature) { $resolutions: 'device-pixel-ratio', 'dpr'; @if breakpoint-get('transform resolutions') { $resolutions: append($resolutions, 'resolution'); } @each $reso in $resolutions { @if index($feature, $reso) or index($feature, 'min-#{$reso}') or index($feature, 'max-#{$reso}') { @return true; } } @return false; } ////////////////////////////// // Parsers ////////////////////////////// ////////////////////////////// // Import Parser Pieces ////////////////////////////// // Import Parser - query ////////////////////////////// @function breakpoint-parse-query($query) { // Parse features out of an individual query $feature-holder: (); $query-holder: (); $length: length($query); @if $length == 2 { // If we've got a string/number, number/string, check to see if it's a valid string/number pair or two singles @if (type-of(nth($query, 1)) == 'string' and type-of(nth($query, 2)) == 'number') or (type-of(nth($query, 1)) == 'number' and type-of(nth($query, 2)) == 'string') { $number: ''; $value: ''; @if type-of(nth($query, 1)) == 'string' { $number: nth($query, 2); $value: nth($query, 1); } @else { $number: nth($query, 1); $value: nth($query, 2); } // If the string value can be a single value, check to see if the number passed in is a valid input for said single value. Fortunately, all current single-value options only accept unitless numbers, so this check is easy. @if breakpoint-single-string($value) { @if unitless($number) { $feature-holder: append($value, $number, space); $query-holder: append($query-holder, $feature-holder, comma); @return $query-holder; } } // If the string is a media type, split the query @if breakpoint-is-media($value) { $query-holder: append($query-holder, nth($query, 1)); $query-holder: append($query-holder, nth($query, 2)); @return $query-holder; } // If it's not a single feature, we're just going to assume it's a proper string/value pair, and roll with it. @else { $feature-holder: append($value, $number, space); $query-holder: append($query-holder, $feature-holder, comma); @return $query-holder; } } // If they're both numbers, we assume it's a double and roll with that @else if (type-of(nth($query, 1)) == 'number' and type-of(nth($query, 2)) == 'number') { $feature-holder: append(nth($query, 1), nth($query, 2), space); $query-holder: append($query-holder, $feature-holder, comma); @return $query-holder; } // If they're both strings and neither are singles, we roll with that. @else if (type-of(nth($query, 1)) == 'string' and type-of(nth($query, 2)) == 'string') { @if not breakpoint-single-string(nth($query, 1)) and not breakpoint-single-string(nth($query, 2)) { $feature-holder: append(nth($query, 1), nth($query, 2), space); $query-holder: append($query-holder, $feature-holder, comma); @return $query-holder; } } } @else if $length == 3 { // If we've got three items and none is a list, we check to see @if type-of(nth($query, 1)) != 'list' and type-of(nth($query, 2)) != 'list' and type-of(nth($query, 3)) != 'list' { // If none of the items are single string values and none of the values are media values, we're good. @if (not breakpoint-single-string(nth($query, 1)) and not breakpoint-single-string(nth($query, 2)) and not breakpoint-single-string(nth($query, 3))) and ((not breakpoint-is-media(nth($query, 1)) and not breakpoint-is-media(nth($query, 2)) and not breakpoint-is-media(nth($query, 3)))) { $feature-holder: append(nth($query, 1), nth($query, 2), space); $feature-holder: append($feature-holder, nth($query, 3), space); $query-holder: append($query-holder, $feature-holder, comma); @return $query-holder; } // let's check to see if the first item is a media type @else if breakpoint-is-media(nth($query, 1)) { $query-holder: append($query-holder, nth($query, 1)); $feature-holder: append(nth($query, 2), nth($query, 3), space); $query-holder: append($query-holder, $feature-holder); @return $query-holder; } } } // If it's a single item, or if it's not a special case double or triple, we can simply return the query. @return $query; } ////////////////////////////// // Import Parser - Single ////////////////////////////// @function breakpoint-parse-default($feature) { $default: breakpoint-get('default feature'); // Set Context $context-setter: private-breakpoint-set-context($default, $feature); @if (breakpoint-get('to ems') == true) and (type-of($feature) == 'number') { @return '#{$default}: #{breakpoint-to-base-em($feature)}'; } @else { @return '#{$default}: #{$feature}'; } } @function breakpoint-parse-single($feature, $empty-media, $first) { $parsed: ''; $leader: ''; // If we're forcing @if not ($empty-media) or not ($first) { $leader: 'and '; } // If it's a single feature that can stand alone, we let it @if (breakpoint-single-string($feature)) { $parsed: $feature; // Set Context $context-setter: private-breakpoint-set-context($feature, $feature); } // If it's not a stand alone feature, we pass it off to the default handler. @else { $parsed: breakpoint-parse-default($feature); } @return $leader + '(' + $parsed + ')'; } ////////////////////////////// // Import Parser Double ////////////////////////////// @function breakpoint-parse-default-pair($first, $second) { $default: breakpoint-get('default pair'); $min: ''; $max: ''; // Sort into min and max $min: min($first, $second); $max: max($first, $second); // Set Context $context-setter: private-breakpoint-set-context(min-#{$default}, $min); $context-setter: private-breakpoint-set-context(max-#{$default}, $max); // Make them EMs if need be @if (breakpoint-get('to ems') == true) { $min: breakpoint-to-base-em($min); $max: breakpoint-to-base-em($max); } @return '(min-#{$default}: #{$min}) and (max-#{$default}: #{$max})'; } // import double default-pair @function breakpoint-parse-double-default($first, $second) { $feature: ''; $value: ''; @if type-of($first) == 'string' { $feature: $first; $value: $second; } @else { $feature: $second; $value: $first; } // Set Context $context-setter: private-breakpoint-set-context($feature, $value); @if (breakpoint-get('to ems') == true) { $value: breakpoint-to-base-em($value); } @return '(#{$feature}: #{$value})' } // import double double-string @function breakpoint-parse-double-string($first, $second) { $feature: ''; $value: ''; // Test to see which is the feature and which is the value @if (breakpoint-string-value($first) == true) { $feature: $first; $value: $second; } @else { $feature: $second; $value: $first; } // Set Context $context-setter: private-breakpoint-set-context($feature, $value); @return '(#{$feature}: #{$value})'; } // import double default @function breakpoint-parse-double-default($first, $second) { $feature: ''; $value: ''; @if type-of($first) == 'string' { $feature: $first; $value: $second; } @else { $feature: $second; $value: $first; } // Set Context $context-setter: private-breakpoint-set-context($feature, $value); @if (breakpoint-get('to ems') == true) { $value: breakpoint-to-base-em($value); } @return '(#{$feature}: #{$value})' } @function breakpoint-parse-double($feature, $empty-media, $first) { $parsed: ''; $leader: ''; // If we're forcing @if not ($empty-media) or not ($first) { $leader: 'and '; } $first: nth($feature, 1); $second: nth($feature, 2); // If we've got two numbers, we know we need to use the default pair because there are no media queries that has a media feature that is a number @if type-of($first) == 'number' and type-of($second) == 'number' { $parsed: breakpoint-parse-default-pair($first, $second); } // If they are both strings, we send it through the string parser @else if type-of($first) == 'string' and type-of($second) == 'string' { $parsed: breakpoint-parse-double-string($first, $second); } // If it's a string/number pair, we parse it as a normal double @else { $parsed: breakpoint-parse-double-default($first, $second); } @return $leader + $parsed; } // import parsers/triple @function breakpoint-parse-triple-default($feature, $first, $second) { // Sort into min and max $min: min($first, $second); $max: max($first, $second); // Set Context $context-setter: private-breakpoint-set-context(min-#{$feature}, $min); $context-setter: private-breakpoint-set-context(max-#{$feature}, $max); // Make them EMs if need be @if (breakpoint-get('to ems') == true) { $min: breakpoint-to-base-em($min); $max: breakpoint-to-base-em($max); } @return '(min-#{$feature}: #{$min}) and (max-#{$feature}: #{$max})'; } @function breakpoint-parse-triple($feature, $empty-media, $first) { $parsed: ''; $leader: ''; // If we're forcing @if not ($empty-media) or not ($first) { $leader: 'and '; } // separate the string features from the value numbers $string: null; $numbers: null; @each $val in $feature { @if type-of($val) == string { $string: $val; } @else { @if type-of($numbers) == 'null' { $numbers: $val; } @else { $numbers: append($numbers, $val); } } } $parsed: breakpoint-parse-triple-default($string, nth($numbers, 1), nth($numbers, 2)); @return $leader + $parsed; } // import parsers/resolution @function breakpoint-make-resolutions($resolution) { $length: length($resolution); $output: (); @if $length == 2 { $feature: ''; $value: ''; // Find which is number @if type-of(nth($resolution, 1)) == 'number' { $value: nth($resolution, 1); } @else { $value: nth($resolution, 2); } // Determine min/max/standard @if index($resolution, 'min-resolution') { $feature: 'min-'; } @else if index($resolution, 'max-resolution') { $feature: 'max-'; } $standard: '(#{$feature}resolution: #{$value})'; // If we're not dealing with dppx, @if unit($value) != 'dppx' { $base: 96dpi; @if unit($value) == 'dpcm' { $base: 243.84dpcm; } // Write out feature tests $webkit: ''; $moz: ''; $webkit: '(-webkit-#{$feature}device-pixel-ratio: #{$value / $base})'; $moz: '(#{$feature}-moz-device-pixel-ratio: #{$value / $base})'; // Append to output $output: append($output, $standard, space); $output: append($output, $webkit, space); $output: append($output, $moz, space); } @else { $webkit: ''; $moz: ''; $webkit: '(-webkit-#{$feature}device-pixel-ratio: #{$value / 1dppx})'; $moz: '(#{$feature}-moz-device-pixel-ratio: #{$value / 1dppx})'; $fallback: '(#{$feature}resolution: #{$value / 1dppx * 96dpi})'; // Append to output $output: append($output, $standard, space); $output: append($output, $webkit, space); $output: append($output, $moz, space); $output: append($output, $fallback, space); } } @return $output; } $Memo-Exists: function-exists(memo-get) and function-exists(memo-set); @function breakpoint-build-resolution($query-print, $query-resolution, $empty-media, $first) { $leader: ''; // If we're forcing @if not ($empty-media) or not ($first) { $leader: 'and '; } @if breakpoint-get('transform resolutions') and $query-resolution { $resolutions: breakpoint-make-resolutions($query-resolution); $length: length($resolutions); $query-holder: ''; @for $i from 1 through $length { $query: '#{$query-print} #{$leader}#{nth($resolutions, $i)}'; @if $i == 1 { $query-holder: $query; } @else { $query-holder: '#{$query-holder}, #{$query}'; } } @return $query-holder; } @else { // Return with attached resolution @return $query-print; } } ////////////////////////////// // Breakpoint Function ////////////////////////////// @function breakpoint($query, $contexts...) { $run: true; $return: (); // Grab the Memo Output if Memoization can be a thing @if $Memo-Exists { $return: memo-get(breakpoint, breakpoint $query $contexts); @if $return != null { $run: false; } } @if not $Memo-Exists or $run { // Internal Variables $query-string: ''; $query-fallback: false; $return: (); // Reserve Global Private Breakpoint Context $holder-context: $private-breakpoint-context-holder; $holder-query-count: $private-breakpoint-query-count; // Reset Global Private Breakpoint Context $private-breakpoint-context-holder: () !global; $private-breakpoint-query-count: 0 !global; // Test to see if it's a comma-separated list $or-list: if(list-separator($query) == 'comma', true, false); @if ($or-list == false and breakpoint-get('legacy syntax') == false) { $query-string: breakpoint-parse($query); } @else { $length: length($query); $last: nth($query, $length); $query-fallback: breakpoint-no-query($last); @if ($query-fallback != false) { $length: $length - 1; } @if (breakpoint-get('legacy syntax') == true) { $mq: (); @for $i from 1 through $length { $mq: append($mq, nth($query, $i), comma); } $query-string: breakpoint-parse($mq); } @else { $query-string: ''; @for $i from 1 through $length { $query-string: $query-string + if($i == 1, '', ', ') + breakpoint-parse(nth($query, $i)); } } } $return: ('query': $query-string, 'fallback': $query-fallback, 'context holder': $private-breakpoint-context-holder, 'query count': $private-breakpoint-query-count ); @if length($contexts) > 0 and nth($contexts, 1) != false { @if $query-fallback != false { $context-setter: private-breakpoint-set-context('no-query', $query-fallback); } $context-map: (); @each $context in $contexts { $context-map: map-merge($context-map, ($context: breakpoint-get-context($context))); } $return: map-merge($return, (context: $context-map)); } // Reset Global Private Breakpoint Context $private-breakpoint-context-holder: () !global; $private-breakpoint-query-count: 0 !global; @if $Memo-Exists { $holder: memo-set(breakpoint, breakpoint $query $contexts, $return); } } @return $return; } ////////////////////////////// // General Breakpoint Parser ////////////////////////////// @function breakpoint-parse($query) { // Increase number of 'and' queries $private-breakpoint-query-count: $private-breakpoint-query-count + 1 !global; // Set up Media Type $query-print: ''; $force-all: ((breakpoint-get('force all media type') == true) and (breakpoint-get('default media') == 'all')); $empty-media: true; @if ($force-all == true) or (breakpoint-get('default media') != 'all') { // Force the print of the default media type if (force all is true and default media type is all) or (default media type is not all) $query-print: breakpoint-get('default media'); $empty-media: false; } $query-resolution: false; $query-holder: breakpoint-parse-query($query); // Loop over each parsed out query and write it to $query-print $first: true; @each $feature in $query-holder { $length: length($feature); // Parse a single feature @if ($length == 1) { // Feature is currently a list, grab the actual value $feature: nth($feature, 1); // Media Type must by convention be the first item, so it's safe to flat override $query-print, which right now should only be the default media type @if (breakpoint-is-media($feature)) { @if ($force-all == true) or ($feature != 'all') { // Force the print of the default media type if (force all is true and default media type is all) or (default media type is not all) $query-print: $feature; $empty-media: false; // Set Context $context-setter: private-breakpoint-set-context(media, $query-print); } } @else { $parsed: breakpoint-parse-single($feature, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; } } // Parse a double feature @else if ($length == 2) { @if (breakpoint-is-resolution($feature) != false) { $query-resolution: $feature; } @else { $parsed: null; // If it's a string/number pair, // we check to see if one is a single-string value, // then we parse it as a normal double $alpha: nth($feature, 1); $beta: nth($feature, 2); @if breakpoint-single-string($alpha) or breakpoint-single-string($beta) { $parsed: breakpoint-parse-single($alpha, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; $parsed: breakpoint-parse-single($beta, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; } @else { $parsed: breakpoint-parse-double($feature, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; } } } // Parse a triple feature @else if ($length == 3) { $parsed: breakpoint-parse-triple($feature, $empty-media, $first); $query-print: '#{$query-print} #{$parsed}'; $first: false; } } @if ($query-resolution != false) { $query-print: breakpoint-build-resolution($query-print, $query-resolution, $empty-media, $first); } // Loop through each feature that's been detected so far and append 'false' to the the value list to increment their counters @each $f, $v in $private-breakpoint-context-holder { $v-holder: $v; $length: length($v-holder); @if length($v-holder) < $private-breakpoint-query-count { @for $i from $length to $private-breakpoint-query-count { @if $f == 'media' { $v-holder: append($v-holder, breakpoint-get('default media')); } @else { $v-holder: append($v-holder, false); } } } $private-breakpoint-context-holder: map-merge($private-breakpoint-context-holder, ($f: $v-holder)) !global; } @return $query-print; } ////////////////////////////// // No Query ////////////////////////////// @function breakpoint-no-query($query) { @if type-of($query) == 'list' { $keyword: nth($query, 1); @if type-of($keyword) == 'string' and ($keyword == 'no-query' or $keyword == 'no query' or $keyword == 'fallback') { @return nth($query, 2); } @else { @return false; } } @else { @return false; } } ////////////////////////////// // Respond to ////////////////////////////// //////////////////////// // Default the Breakpoints variable //////////////////////// $breakpoints: () !default; $BREAKPOINTS: () !default; //////////////////////// // Respond-to API Mixin //////////////////////// @mixin respond-to($context, $no-query: false) { @if length($breakpoints) > 0 and length($BREAKPOINTS) == 0 { @warn "In order to avoid variable namespace collisions, we have updated the way to add breakpoints for respond-to. Please change all instances of `$breakpoints: add-breakpoint()` to `@include add-breakpoint()`. The `add-breakpoint()` function will be deprecated in a future release."; $BREAKPOINTS: $breakpoints !global; $breakpoints: () !global; } @if type-of($BREAKPOINTS) != 'map' { // Just in case someone writes gibberish to the $breakpoints variable. @warn "Your breakpoints aren't a map! See https://github.com/snugug/respond-to#api if you'd like a reminder on how to use Respond-to"; @content; } @else if map-has-key($BREAKPOINTS, $context) { @include breakpoint(map-get($BREAKPOINTS, $context), $no-query) { @content; } } @else if not map-has-key($BREAKPOINTS, $context) { @warn "`#{$context}` isn't a defined breakpoint! Please add it using `$breakpoints: add-breakpoint(`#{$context}`, $value);`"; @content; } @else { @warn "You haven't created any breakpoints yet! Make some already! See https://github.com/snugug/respond-to#api if you'd like a reminder on how to use Respond-to"; @content; } } ////////////////////////////// // Add Breakpoint to Breakpoints // TODO: Remove function in next release ////////////////////////////// @function add-breakpoint($name, $bkpt, $overwrite: false) { $output: ($name: $bkpt); @if length($breakpoints) == 0 { @return $output; } @else { @if map-has-key($breakpoints, $name) and $overwrite != true { @warn "You already have a breakpoint named `#{$name}`, please choose another breakpoint name, or pass in `$overwrite: true` to overwrite the previous breakpoint."; @return $breakpoints; } @else if not map-has-key($breakpoints, $name) or $overwrite == true { @return map-merge($breakpoints, $output); } } } @mixin add-breakpoint($name, $bkpt, $overwrite: false) { $output: ($name: $bkpt); @if length($BREAKPOINTS) == 0 { $BREAKPOINTS: $output !global; } @else { @if map-has-key($BREAKPOINTS, $name) and $overwrite != true { @warn "You already have a breakpoint named `#{$name}`, please choose another breakpoint name, or pass in `$overwrite: true` to overwrite the previous breakpoint."; $BREAKPOINTS: $BREAKPOINTS !global; } @else if not map-has-key($BREAKPOINTS, $name) or $overwrite == true { $BREAKPOINTS: map-merge($BREAKPOINTS, $output) !global; } } } ////////////////////////////// // Legact Settings ////////////////////////////// @mixin legacy-settings-warning { $legacyVars: ( 'default-media': 'default media', 'default-feature': 'default feature', 'force-media-all': 'force all media type', 'to-ems': 'to ems', 'resolutions': 'transform resolutions', 'no-queries': 'no queries', 'no-query-fallbacks': 'no query fallbacks', 'base-font-size': 'base font size', 'legacy-syntax': 'legacy syntax' ); @each $legacy, $new in $legacyVars { @if global-variable-exists('breakpoint-' + $legacy) { @warn "In order to avoid variable namspace collisions, we have updated the way to change settings for Breakpoint. Please change all instances of `$breakpoint-#{$legacy}: {{setting}}` to `@include breakpoint-set('#{$new}', {{setting}})`. Variable settings, as well as this warning will be deprecated in a future release." } }; ////////////////////////////// // Hand correct each setting ////////////////////////////// @if global-variable-exists('breakpoint-default-media') and $breakpoint-default-media != breakpoint-get('default media') { @include breakpoint-set('default media', $breakpoint-default-media); } @if global-variable-exists('breakpoint-default-feature') and $breakpoint-default-feature != breakpoint-get('default feature') { @include breakpoint-set('default feature', $breakpoint-default-feature); } @if global-variable-exists('breakpoint-force-media-all') and $breakpoint-force-media-all != breakpoint-get('force all media type') { @include breakpoint-set('force all media type', $breakpoint-force-media-all); } @if global-variable-exists('breakpoint-to-ems') and $breakpoint-to-ems != breakpoint-get('to ems') { @include breakpoint-set('to ems', $breakpoint-to-ems); } @if global-variable-exists('breakpoint-resolutions') and $breakpoint-resolutions != breakpoint-get('transform resolutions') { @include breakpoint-set('transform resolutions', $breakpoint-resolutions); } @if global-variable-exists('breakpoint-no-queries') and $breakpoint-no-queries != breakpoint-get('no queries') { @include breakpoint-set('no queries', $breakpoint-no-queries); } @if global-variable-exists('breakpoint-no-query-fallbacks') and $breakpoint-no-query-fallbacks != breakpoint-get('no query fallbacks') { @include breakpoint-set('no query fallbacks', $breakpoint-no-query-fallbacks); } @if global-variable-exists('breakpoint-base-font-size') and $breakpoint-base-font-size != breakpoint-get('base font size') { @include breakpoint-set('base font size', $breakpoint-base-font-size); } @if global-variable-exists('breakpoint-legacy-syntax') and $breakpoint-legacy-syntax != breakpoint-get('legacy syntax') { @include breakpoint-set('legacy syntax', $breakpoint-legacy-syntax); } } ////////////////////////////// // Breakpoint Mixin ////////////////////////////// @mixin breakpoint($query, $no-query: false) { @include legacy-settings-warning; // Reset contexts @include private-breakpoint-reset-contexts(); $breakpoint: breakpoint($query, false); $query-string: map-get($breakpoint, 'query'); $query-fallback: map-get($breakpoint, 'fallback'); $private-breakpoint-context-holder: map-get($breakpoint, 'context holder') !global; $private-breakpoint-query-count: map-get($breakpoint, 'query count') !global; // Allow for an as-needed override or usage of no query fallback. @if $no-query != false { $query-fallback: $no-query; } @if $query-fallback != false { $context-setter: private-breakpoint-set-context('no-query', $query-fallback); } // Print Out Query String @if not breakpoint-get('no queries') { @media #{$query-string} { @content; } } @if breakpoint-get('no query fallbacks') != false or breakpoint-get('no queries') == true { $type: type-of(breakpoint-get('no query fallbacks')); $print: false; @if ($type == 'bool') { $print: true; } @else if ($type == 'string') { @if $query-fallback == breakpoint-get('no query fallbacks') { $print: true; } } @else if ($type == 'list') { @each $wrapper in breakpoint-get('no query fallbacks') { @if $query-fallback == $wrapper { $print: true; } } } // Write Fallback @if ($query-fallback != false) and ($print == true) { $type-fallback: type-of($query-fallback); @if ($type-fallback != 'bool') { #{$query-fallback} & { @content; } } @else { @content; } } } @include private-breakpoint-reset-contexts(); } @mixin mq($query, $no-query: false) { @include breakpoint($query, $no-query) { @content; } } // My Breakpoint Variables for this demo $breakpoint-to-ems: true; // min-width is default when only a number is declared $small: 480px; // if two numbers are listed, then it assumes the first number is min-width and second is max-width $medium: 600px 900px; $large: 901px; // if one value is a string, assume a feature/value pair // $xsmall: max-width 480px; // string tests together within parentheses, assume each item is a feature value pair $tall-height: (min-height 1000px) (orientation portrait); // Include styles .foo { background: #00C176; content: 'No Media Queries'; /* @include breakpoint($xsmall) { background: #A0B046; content: 'Basic Media Query - xSmall'; }*/ @include breakpoint($small) { background: #49007E; content: 'Basic Media Query - Small'; } @include breakpoint($medium) { background: #FF005B; content: 'Basic Media Query - Medium'; } @include breakpoint($large) { background: #FF7D10; content: 'Basic Media Query - Large'; } } $custom-pair: (height 100px 500px); $pair-portrait: screen 321px 768px, handheld (orientation portrait); .baz { background: #9A8194; content: 'No Media Queries'; @include breakpoint($custom-pair) { background: #398A87; content: 'Custom Pair Media Query - Targeting Height'; } @include breakpoint($pair-portrait) { content: 'Screen media type between 300px and 500px OR Handheld media type in Portrait'; } } .foo:before { content: 'No Media Query'; /* @include breakpoint($xsmall) { content: 'Basic Media Query - xSmall'; }*/ @include breakpoint($small) { content: 'Basic Media Query - Small'; } @include breakpoint($medium) { content: 'Basic Media Query - Medium'; } @include breakpoint($large) { content: 'Basic Media Query - Large'; } } .baz:before { content: 'No Media Query'; @include breakpoint($custom-pair) { content: 'Custom Pair Media Query - Targeting Height'; } @include breakpoint($pair-portrait) { content: 'Screen media type between 300px and 500px OR Handheld media type in Portrait'; } } $basic: screen 800px 1200px, min-height 300px, orientation landscape; .bar { background: #4E395D; content: 'No Media Queries'; @include breakpoint($basic) { content: 'min-height:' breakpoint-get-context('min-height'); content: 'orientation:' breakpoint-get-context('orientation'); content: 'max-width: ' breakpoint-get-context('max-width'); } } .bar:before { content: 'No Media Query'; @include breakpoint($basic) { content: "I am basic. Check the compiled CSS for context."; } } /* Non-layout Styles */ .baz:before, .foo:before, .bar:before { color: #fff; display: block; font-size: 2rem; padding: 1em 0; text-align: center; width: 100%; } @import url(http://fonts.googleapis.com/css?family=Josefin+Sans:100,400,700); // Base text styles to be used for elements in this pen %type-base { color: #fff; font-family: 'Josefin Sans', sans-serif; font-weight: 100; } $color-coral: #F45D4C; $color-green: #A1DBB2; $color-yellow: #FACA66; body { @extend %type-base; background: #2d2d2d; margin: 0 auto; text-align: center; } h1 { font-size: 3.6rem; font-weight: 700; margin: 2rem auto .5rem; } h2 { color: lighten($color-coral, 15%); font-size: 1.6rem; font-weight: 100; margin: 0 auto 1.5rem; }