Skip to content

Instantly share code, notes, and snippets.

@romellem
Created October 30, 2020 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romellem/aae9591450524458aea275b7aa705b1c to your computer and use it in GitHub Desktop.
Save romellem/aae9591450524458aea275b7aa705b1c to your computer and use it in GitHub Desktop.
Sass poly sizing mixin / functions
/// 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