Created
October 30, 2020 19:14
-
-
Save romellem/aae9591450524458aea275b7aa705b1c to your computer and use it in GitHub Desktop.
Sass poly sizing mixin / functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Poly-sizing mixin | |
/// | |
/// @see https://www.smashingmagazine.com/2017/05/fluid-responsive-typography-css-poly-fluid-sizing/ | |
/// | |
/// @param {String|List} $properties - Can be a single CSS property (e.g. `"font-size"`) or a list of properties (e.g `("margin-right", "margin-left")`). | |
/// @param {Map<(List<Length>|Length)>} $map - Can be a map of single values, or a map of lists of values. | |
/// @example @include poly("font-size", (375px: 15px, 767px: 30px)); | |
/// @example @include poly("padding", (375px: (0 10px), 767px: (0 20px))); | |
/// @example @include poly(("margin-top", "margin-bottom"), (375px: 10px, 767px: 20px)); | |
@mixin poly($properties, $map) { | |
// Get the number of provided breakpoints | |
$length: length(map-keys($map)); | |
// Error if the number of breakpoints is < 2 | |
@if ($length < 2) { | |
@error "poly() $map requires at least 2 keys"; | |
} | |
// Sort the map by viewport width (key) | |
$map: map-sort($map); | |
$keys: map-keys($map); | |
$values: map-values($map); | |
// Verify that all values are the same length | |
$values-length: length(nth($values, 1)); | |
@for $v from 2 through $length { | |
$temp-value-length: length(nth($values, $v)); | |
@if ($temp-value-length != $values-length) { | |
@error "poly() values must all be same length"; | |
} | |
} | |
// Coerce `$properties` to a list | |
@if (type-of($properties) != 'list') { | |
// Make a list of 1 | |
$properties: ($properties); | |
} | |
// Base sizing | |
@each $property in $properties { | |
#{$property}: map-get($map, nth($keys, 1)); | |
} | |
@for $i from 1 through ($length - 1) { | |
$x1: nth($keys, $i); | |
$y1: map-get($map, $x1); | |
$x2: nth($keys, ($i + 1)); | |
$y2: map-get($map, $x2); | |
// To support passing in a list for our values, | |
// we loop over the values and map it to its `linear-interpolation` | |
// Then, we store that value this list below, separated by spaces. | |
$value-list-interpolated: (); | |
@for $j from 1 through $values-length { | |
$y1-jth: nth($y1, $j); | |
$y2-jth: nth($y2, $j); | |
$interpolation: linear-interpolation( | |
( | |
$x1: $y1-jth, | |
$x2: $y2-jth, | |
) | |
); | |
$value-list-interpolated: append($value-list-interpolated, $interpolation, space); | |
} | |
@media (min-width: nth($keys,$i)) { | |
@each $property in $properties { | |
#{$property}: $value-list-interpolated; | |
} | |
} | |
} | |
// Max sizing | |
@media (min-width: nth($keys,$length)) { | |
@each $property in $properties { | |
#{$property}: map-get($map, nth($keys, $length)); | |
} | |
} | |
} | |
@function linear-interpolation($map) { | |
$keys: map-keys($map); | |
@if (length($keys) != 2) { | |
@error "linear-interpolation() $map must be exactly 2 values"; | |
} | |
// $map: (x1: y1, x2: y2) | |
$x1: nth($keys, 1); | |
$y1: map-get($map, $x1); | |
$x2: nth($keys, 2); | |
$y2: map-get($map, $x2); | |
// If we are interpolating from two identical values, just return that value. No `calc` needed | |
@if ($y1 == $y2) { | |
@return $y1; | |
} | |
// The slope | |
$m: ($y2 - $y1) / ($x2 - $x1); | |
// The y-intercept | |
$b: $y1 - $m * $x1; | |
// Determine if the sign should be positive or negative | |
$sign: '+'; | |
@if ($b < 0) { | |
$sign: '-'; | |
$b: abs($b); | |
} | |
@return calc(#{$m * 100}vw #{$sign} #{$b}); | |
} | |
@function list-sort($list) { | |
$sortedlist: (); | |
@while length($list) > 0 { | |
$value: nth($list, 1); | |
@each $item in $list { | |
@if $item < $value { | |
$value: $item; | |
} | |
} | |
$sortedlist: append($sortedlist, $value, 'space'); | |
$list: list-remove($list, index($list, $value)); | |
} | |
@return $sortedlist; | |
} | |
@function map-sort($map) { | |
$keys: list-sort(map-keys($map)); | |
$sortedMap: (); | |
@each $key in $keys { | |
$sortedMap: map-merge( | |
$sortedMap, | |
( | |
$key: map-get($map, $key), | |
) | |
); | |
} | |
@return $sortedMap; | |
} | |
@function list-remove($list, $index) { | |
$newList: (); | |
@for $i from 1 through length($list) { | |
@if $i != $index { | |
$newList: append($newList, nth($list, $i), 'space'); | |
} | |
} | |
@return $newList; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment