/// poly-fluid-sizing
/// Generate linear interpolated size values through multiple break points
/// @param $property - A string CSS property name
/// @param $map - A Sass map of viewport unit and size value pairs
/// @requires function linear-interpolation
/// @requires function map-sort
/// @example
/// @include poly-fluid-sizing('font-size', (576px: 22px, 768px: 24px, 992px: 34px));
/// @author Jake Wilson <jake.e.wilson@gmail.com>
@mixin poly-fluid-sizing($property, $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-fluid-sizing() $map requires at least values"
}
// Sort the map by viewport width (key)
$map: map-sort($map);
$keys: map-keys($map);
// Minimum size
#{$property}: map-get($map, nth($keys,1));
// Interpolated size through breakpoints
@for $i from 1 through ($length - 1) {
@media (min-width:nth($keys,$i)) {
$value1: map-get($map, nth($keys,$i));
$value2: map-get($map, nth($keys,($i + 1)));
// If values are not equal, perform linear interpolation
@if ($value1 != $value2) {
#{$property}: linear-interpolation((nth($keys,$i): $value1, nth($keys,($i+1)): $value2));
} @else {
#{$property}: $value1;
}
}
}
// Maxmimum size
@media (min-width:nth($keys,$length)) {
#{$property}: map-get($map, nth($keys,$length));
}
}
/// list-sort
/// Sort a SASS list
/// @param $list - A SASS list
/// @returns A sorted SASS list
/// @requires function list-remove
/// @author Jake Wilson <jake.e.wilson@gmail.com>
@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;
}
/// linear-interpolation
/// Calculate the definition of a line between two points
/// @param $map - A SASS map of viewport widths and size value pairs
/// @returns A linear equation as a calc() function
/// @example
/// font-size: linear-interpolation((320px: 18px, 768px: 26px));
/// @author Jake Wilson <jake.e.wilson@gmail.com>
@function linear-interpolation($map) {
$keys: map-keys($map);
@if (length($keys) != 2) {
@error "linear-interpolation() $map must be exactly 2 values";
}
// The slope
$m: (map-get($map, nth($keys, 2)) - map-get($map, nth($keys, 1)))/(nth($keys, 2) - nth($keys,1));
// The y-intercept
$b: map-get($map, nth($keys, 1)) - $m * nth($keys, 1);
// Determine if the sign should be positive or negative
$sign: "+";
@if ($b < 0) {
$sign: "-";
$b: abs($b);
}
@return calc(#{$m*100}vw #{$sign} #{$b});
}
/// list-remove
/// Remove an item from a list
/// @param $list - A SASS list
/// @param $index - The list index to remove
/// @returns A SASS list
/// @author Jake Wilson <jake.e.wilson@gmail.com>
@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;
}
/// map-sort
/// Sort map by keys
/// @param $map - A SASS map
/// @returns A SASS map sorted by keys
/// @requires function list-sort
/// @author Jake Wilson <jake.e.wilson@gmail.com>
@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;
}