CSS Comparison Functions clamp(), max() and min()
Tags: css, webdev
Published: 2020-05-19 12:34:08

We use relative length units to build responsive/fluid layouts. Besides being flexible, elements whose size depends on the size of another element or the viewport, also have a bad habit of sometimes **growing or shrinking more than we would like them to**. For example, if we define the font size with <code>vw</code> unit alone, text can easily become illegible if viewport size gets too small. 

Breaking a bad habit is tough - and in this case it may require some serious thinking and calculations. We usually solve these problems with media queries or different <code>calc()</code> techniques to achieve more fluid effect. It's especially true when it comes to the elements that don't have <code>width</code> property (and consequently <code>max-width</code> and <code>min-width</code>), like the above-mentioned font size. 

Comparison functions can help us build responsive designs with less time and fewer lines of code. Functions <code>clamp()</code>, <code>min()</code> and <code>max()</code> (specified in [CSS Values and Units Module Level 4] (https://drafts.csswg.org/css-values-4/#comp-func)) set upper and/or lower value limits, compute and compare values of the arguments passed to the function, and apply the calculated value to the property. 

<code>clamp()</code>, <code>min()</code> and <code>max()</code> can take values or math expressions as arguments (or basically anything that resolves to a value). They can be used, let me quote [MDN] (https://developer.mozilla.org/en-US/docs/Web/CSS/clamp) here: anywhere a <code>&lt;length></code>, <code>&lt;frequency></code>, <code>&lt;angle></code>, <code>&lt;time></code>,<code>&lt;percentage></code>, <code>&lt;number></code>, or <code>&lt;integer></code> is allowed. That’s a lot of possible use cases to consider, and in this post I explored the most obvious ones.

#clamp()

Function <code>clamp()</code> takes three parameters: a minimum value, a central, preferred value, and a maximum value. The resolved value will always remain between the minimum and maximum.

<code>clamp()</code> calculates property value based on the central value. **If the calculated value falls between the minimum and maximum, the central value will be applied to the element. If the calculated value falls below minimum or exceeds maximum, minimum or maximum will be applied respectively**. There is no need for <code>calc()</code> function when passing math expressions in the comparison function. 

The syntax is simple and logical: 

```css
/* css */
.element {
width: clamp(100px, 50vw, 600px); 
/* width: clamp(min, preferred, max); */
}
```
Depending on the viewport size, the upper CSS ruleset will apply the following widths to the element: 

| Viewport      | Applied width clamp()|
| -----------   | ----------- |
| 200px - 1200px| 50vw        |
| < 200px       | 100px       |
| > 1200px      | 600px       |


Try it for yourself in the <code>clamp()</code> [demo](https://codepen.io/Ekaterina_Vu/pen/QWjxJvm) below: 
{% codepen https://codepen.io/Ekaterina_Vu/pen/QWjxJvm %} 

Check another [demo](https://codepen.io/Ekaterina_Vu/pen/PoPBwwR) to see how both the paragraph text and the heading are being smoothly resized between the value limits. No jumps as with media queries. The ratio between the font size of the headline and body text grows as the viewport gets bigger but nothing will ever get too big or too small. 

{% codepen https://codepen.io/Ekaterina_Vu/pen/PoPBwwR %}

This is a simple example and is far from perfect - vertical rhythm, modular scale, line length, and bazillion other typography related things - it all could be implemented better. But if I ever decide to improve it, I will probably use comparison functions for much of the above.

#max() and min()

**Function <code>max()</code> calculates and applies the largest value from the provided range of values. Likewise, function <code>min()</code> calculates and applies the smallest value from the range.** They can take one or more parameters.

Check the Codepen [demo](https://codepen.io/Ekaterina_Vu/pen/jObKRRP) below to see both functions in action: 

{% codepen https://codepen.io/Ekaterina_Vu/pen/jObKRRP %}

Yes, both <code>min()</code> and <code>max()</code> can be replaced with <code>max-width</code> or <code>min-width</code> if the element has width property and only two parameters are passed into the function. It sounds a bit counterintuitive, but <code>max()</code> actually sets the lower size limit and <code>min()</code> the upper size limit.
```css
/* css */

/* min() */
.element {
width: min(50vw, 500px);
}
/* gives the same result as: */
.element {
width: 50vw;
max-width: 500px;
}
/* max() */
.element {
width: max(50vw, 500px);
}
/* gives the same result as: */
.element {
width: 50vw;
min-width: 500px;
}
```
The upper CSS code applies following width values to the element, depending on the viewport size:

| Viewport      | Applied width max()|Applied width min()|
| -----------   | ----------------- |------------------|
| > 1000px      | 50vw              | 500px            | 
| < 1000px      | 500px             | 50vw             |
   

**You can pass multiple parameters into both <code>max()</code> and <code>min()</code>**: 
```css
/* css */
h1 {
 font-size: min(3rem, 3em, 4vw);/* the smallest value will be applied */
}
```
<code>max()</code> and <code>min()</code> with multiple parameters are potentially capable of doing some serious responsive stuff with a single line of code. However, I find them a bit incomprehensive - it's hard to set the right arguments and it's even harder to check which value gets applied 🤯. Maybe there are some best practices I'm not aware of. 

In the following [demo](https://codepen.io/Ekaterina_Vu/pen/qBOJLaW) the rectangle changes its width and color as the width property takes three different values: 
{% codepen https://codepen.io/Ekaterina_Vu/pen/qBOJLaW %}

**Comparison functions can be nested within other comparison functions**. For example, function <code>clamp()</code> can be alternatively written as <code>max(minimum, min(preferred, maximum))</code>.

#Conclusion

Comparison functions are new to me and I still haven't find time to fully explore them. They have only recently entered some major browsers but already have [decent](https://caniuse.com/#feat=css-math-functions) browser support. 

I can imagine comparison functions being used in web typography. It's not like it will absolve us from using media queries or <code>calc()</code>, but in many cases they can make our job a lot easier.

Potential use cases of comparison functions probably stretch far beyond responsive width and font-size. I was thinking about how to use them with colors (still thinking 🥴). Maybe you have some interesting ideas? Share your thoughts in comments.