The CSS clamp function is great.
For anyone not familiar with it, it allows you to elegantly set a minimum and maximum size to something, as well as define a function to transition smoothly between them.
Its syntax goes something like this:
font-size: clamp(12px, 2.5vw, 16px);
In a nutshell, this sets the font to be 2.5vw, with a minimum font size of 1 rem and a maximum font size of 2 rem.
So at screen width <= 480 px, the font-size is 12px.
At screen width >= 640 px, the font-size is 16px.
Between 480px and 640 px, it transitions linearly between the two sizes.
Now let's say you wanted to change the threshold for a 12px font from 480px to 400px - it's not very simple, you'd have to do some algebra. Thankfully, Pedro Rodriguez wrote a great post for CSS-Tricks detailing the math involved.
So I took that math and turned it into a SCSS mixin. Here it is:
/*Returns a CSS clamp function which resolves to $size-at-min-width when page width is
below $min-width,
$size-at-max-width when page width is above $max-width,
and linearly scales between the two between $min-width and $max-width*/
@function clamp-calc($min-width, $max-width, $size-at-min-width, $size-at-max-width) {
$slope: ($size-at-max-width - $size-at-min-width) / ($max-width - $min-width);
$y-axis-intersection: -1 * $min-width * $slope + $size-at-min-width;
$return-value: clamp(#{$size-at-min-width}, #{$y-axis-intersection} + #{$slope} * 100vw, #{$size-at-max-width});
@return $return-value;
}
Using this function, we can rewrite our original CSS snippet:
font-size: clamp-calc(480px, 640px, 12px, 16px);
Which does indeed compile to the same CSS (albeit a bit more verbose):
body {
font-size: clamp(12px, 0px + 0.025 * 100vw, 16px);
}
Happy styling! Quick note: the function will work with units other than px, but $min-width
and $max-width
will need to be the same unit, and $size-at-min-width
and $size-at-max-width
will need to be the same unit.
Top comments (1)
Just for the sake of posterity, the "+" on the last line (#{$y-axis-intersection} + #{$slope}) needs to be "#{+}" instead. Otherwise it doesn't get output in the result as a + and the whole thing doesn't produce a result that the browser can understand.