DEV Community

ChristianMay21
ChristianMay21

Posted on

Easy CSS Clamp SCSS Mixin

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);
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Using this function, we can rewrite our original CSS snippet:

font-size: clamp-calc(480px, 640px, 12px, 16px);
Enter fullscreen mode Exit fullscreen mode

Which does indeed compile to the same CSS (albeit a bit more verbose):

body {
  font-size: clamp(12px, 0px + 0.025 * 100vw, 16px);
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
kentpilkington profile image
Kent Pilkington

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.