When laying out a page, we often run into particular situations: an element that has to be wider than its parent but with a relative value, or fluid type that lives between a range of values and depends on the screen width. To match in code the result presented by the UX/UI team, we have to invent systems that let us create these styles. That is where the CSS function calc() not only shines but is essential, because it allows mathematical calculations using different units. Today we are going to look at other functions also collected in the working draft CSS Values and Units Module Level 4 that already have broad support: min(), max() and clamp().

Min()

min() is a CSS function that can be applied to any property that supports one of the types <length>, <frequency>, <angle>, <time>, <percentage>, <number> or <integer>. Given a series of comma-separated values (parameters), it picks the smallest among them and applies it as the property value.

.element {
  width: min(500px, 70%);
}

The way to read the example above would be: “Right now, which is the smallest value? 500px, or 70% of the parent container’s width?”

If the parent container were 1000px, we would be looking for the smallest value between 500px and 700px, so the width would be 500px.

We emphasise “Right now” because the interesting part is that if the screen size or the zoom changes, the parent container’s width changes, and therefore so does the result of that 70%. If the container were now 500px, 70% would be 350px, so the value to apply would be 350px, not 500px as before.

In practice, with this formula we are guaranteeing a maximum value that cannot be exceeded. If we use it for a <width>, we could read it as the equivalent of <width> and <max-width> together, because we have a <width> (70%) and a <max-width> (500px).

Ideally the values passed to the function are of different units or relative, because if they were of the same unit and absolute, such as “500px, 550px”, the property would lose its point

Max()

max() is another CSS function that can be applied to any property that supports one of the types <length>, <frequency>, <angle>, <time>, <percentage>, <number> or <integer>. From the comma-separated parameters it receives, it picks the largest, which will be applied as the property value.

.element {
  width: max(40em, 98%);
}

In this case we would read the example as: “Right now, which of the two values is larger? 40em, or 98% of the parent container’s width?”

Because the conditions in which the content is being rendered can change, the beauty and power of the function lie in its re-evaluation, so it can pick the value that fits best in each situation.

Here we are guaranteeing a minimum value for that property. If we use it for a <width>, we could read it as the equivalent of <width> and <min-width> together, because we have a <width> (98%) and a <min-width> (40em).

For both min() and max(), the order of the parameters does not matter, because sometimes the first parameter will be the largest/smallest and sometimes it will be the second

Clamp()

We can think of clamp() as the function that groups the previous two. It must receive 3 parameters, in a specific order: MIN_VALUE, IDEAL_VALUE and MAX_VALUE.

The function is resolved with the formula: max(MIN_VALUE, min(IDEAL_VALUE, MAX_VALUE)). In words: “Pick the larger value between the minimum (which works as a lower bound) and the maximum that resulted from resolving min() between the ideal value and the maximum (which works as an upper bound)”.

.element {
  font-size: clamp(14px, 3em, 4rem);

  /*
    Assuming that 1em = 10px, 3em = 10px * 3 = 30px
    and that 1rem = 16px, 4rem = 16px * 4 = 64px
    We would transform it into
  */
  font-size: clamp(14px, 30px, 64px);

  /*
    Applying the formula we would transform it again into
  */
  font-size: max(14px, min(30px, 64px));
  font-size: max(14px, 30px);
  font-size: 30px;
}

We would be talking about a property similar to the flex shorthand, but in practice it would be like applying (if we were setting a width) <min-width>, <max-width> and <width>.

clamp(MIN, VAL, MAX) is resolved as max(MIN, min(VAL, MAX))

Common properties and uses

  • min(), max() and clamp() can be used together with calc(), and they can also be nested, that is, combined: calc(min()), max(calc()), calc(max(min())), and so on.

  • They allow simple math such as addition, subtraction, multiplication and division, and because they are math functions it is not necessary to nest calc() inside them: parentheses are enough.

.element-a {
  font-size: max(min(10%, ((1.25vw + 10px) * 0.5), 5vw), 1rem);
}

.element-b {
  font-size: max(min(10%, calc((1.25vw + 10px) * 0.5), 5vw), 1rem);
}
  • They are very useful for fluid typography and for improving the accessibility of a project, because with max() and clamp() we can set a minimum font size for our text that always keeps it readable.
.text {
  /* Guarantee that a text value can never be smaller than 18px */
  font-size: clamp(18px, (1rem + 1vw) * 1.25, 3rem);
}

Using them in Sass

When using min() and max() in Sass (SCSS), the compiler (LibSass or Ruby Sass) throws an error for incompatible units. As the official documentation explains, this is because they interpret min() and max() as Sass’s own functions, not as the CSS functions (which arrived much later). That is why, to use these implementations, they recommend treating them as a string:

.element-c {
	width: unquote("min(500px, 98%)");
}

.element-d {
	font-size: unquote("max(min(10%, ((1.25vw + 10px) * 0.5), 5vw), 1rem)");
}

Another solution, very smart in its simplicity, comes from Ana Tudor in a CSS-Tricks article titled “When Sass and new CSS features conflict”, which I reached through CodePen’s reply when I asked the question on Twitter. The article goes deep into computation with unrelated values, special cases and native CSS variables, but the solution is a language basic: Sass is case-sensitive but CSS is not, so the Sass compiler would not understand Min() as its internal function and the error would not happen. The resulting CSS, which does not make that distinction, interprets MIN(), Min() and min() the same way, so we could use these functions without problems.

Conclusion

It is worth noting that although clamp() is the most complex of the three, it is also the most complete, and in practice, after a little use, you will realise it is the one you will use the most — if not the only one.

These 3 functions let us add a bit more logic, flexibility and control to our stylesheets, which helps us build more powerful applications and enrich them to meet increasingly demanding results. Understanding how min(), max() and clamp() work will give us new tools to face a layout with more resources and, potentially, to be more creative. Demo

Resources