CSS min(), max() and clamp() Functions

Intro

I've seen a lot of chatter lately about how some new CSS functions - min(), max() and clamp() are actually well supported. Even Safari supports clamp() as of 13.1.

Intended audience

This post assumes that you're an advanced and experienced writer of CSS.

Wait, CSS Functions?

A CSS function is a value that we can pass in as part of a rule that actually performs some logic. We've had one function for a while now - calc().

 /* whatever 100% is minus 32 pixels */
  width: calc(100% - 32px);

We just have three more functions that we can use.

min()

min() is pretty straightforward - you pass it a list of comma separated values, and the smallest option is used.

/* will be 100px or 10vw wide, whichever is smaller */
  width: min(100px, 10vw);

The order of the values doesn't matter:

/* does the same thing */
  width: min(10vw, 100px);

You can even have more than two if that helps:

/* will be 100px, 10vw or 50% wide, */
/* whichever is smallest */
  width: min(10vw, 100px, 50%);

Technically you can have only one value for min() and max() but ... that would be rather silly, wouldn't it?

Use cases for min()

Rather unintuitively, the thing that min() is really good at is creating a maximum value for something.

/* will use a relative font size of 10vw, up to 5rem */
  font-size: min(10vw, 5rem);
/* the third column will be 10vw wide up to 200px
  this is an alternative to minmax(),
  which is grid-specific */
  grid-template-columns: 1fr 1fr min(10vw, 200px);
/* the image will be responsive
  and take up it's container width, up to 400px */
  img {
    width: min(100%, 400px);
  }
/* will create relative padding using vh and vw units,
  but cap it at 20px */
  padding: min(5vh, 20px) min(5vw, 20px);

The above example builds on ideas I started with here.

max()

max() works just like min() but it will choose the largest value in the list provided.

/* will be 100px or 10vw wide, whichever is larger */
  width: max(100px, 10vw);

As with min(), you can one or more values, and the order doesn't matter

/* will be 100px, 10vw or 50% wide, whichever is largest */
  width: max(10vw, 100px, 50%);

Use cases for max()

As the inverse of min() - the use case for max() is to establish a minimum value that a thing can be. I tend to write my CSS mobile first, that is, smallest use case first and then work my way up. Consequently, I don't think I'll be reaching for max() that often, if I'm honest.

/* will use a relative font size of 10vw,
  but at least 5rem */
  font-size: max(10vw, 5rem);
/* the third column will be at least 200px wide,
 but 10vw above when that is larger
 this is an alternative to minmax(),
 which is grid-specific */
  grid-template-columns: 1fr 1fr max(10vw, 200px);
/* the image will be a minumum of 200px wide,
  but 100% wide beyond that */
  img {
    width: max(100%, 200px);
  }

clamp()

clamp() is reallllly interesting, and I think will be what CSS authors really should reach for in a lot of responsive implementations.

While it's a related idea to min() and max() it is different in specific ways:

Those 3 parameters are

  1. The minimum
  2. The target value (ideally a relative unit)
  3. The maximum

You use it like:

/* will be 10vw wide, with a minimum of 100px
  and a maximum of 200px */
  width: clamp(100px, 10vw, 200px);

If you want to think of it another way, as noted by MDN, it evaluates like this (using the previous example):

 /* don't actually do this */
 width: max(100px, min(10vw, 200px));

Use cases for clamp()

clamp() makes a lot of intrinsic web design ideas possible - that is, implementations that are responsive but not needing media queries.

/* will be 10vw, with a minimum of 2rem
  and a maximum of 5rem
  to me, this is the responsive typography dream */
  font-size: clamp(2rem, 10vw, 5rem);
/* the image will be responsive and
  take up it's container width,
  with a minimum of 200px and a maximum of 800px */
  img {
    width: clamp(200px, 100%, 800px);
  }
/* will create relative padding using vh and vw units,
  with minimums of 8px and maximums of 20px */
  padding: clamp(8px, 5vh, 20px) clamp(8px, 5vw, 20px);

clamp() and grid

From my experimentation, clamp() is not a valid value for use in CSS Grid. So, this is not a thing:

/* not a thing. don't do this. */
  grid-template-columns: 1fr 1fr clamp(100px, 10vw, 200px);

A note on using Sass / SCSS

Sass had min() and max() functions way before they were implemented in CSS. In order to not break existing Sass code, it works like this - if you pass in a Sass feature (like a variable), it will use the Sass function

  width: min($variable1, $variable2); // will use Sass's min()

If you are using Dart Sass, and if the function uses straight values, it will use CSS's function

  width: min(100px, 10vw); // works as before in Dart Sass

However, if you're using LibSass or Ruby Sass, it will always use the Sass min or max functions, and consequently you may see this error:

Internal Error: Incompatible units: 'px' and 'vw'.

In order to use it with with those versions of Sass, you need to use the following syntax:

  width: unquote('min(100vw, 100px)');

or, with variables:

  width: unquote('min(#{$variable1}, #{$variable2})');

Conclusion

I hope this post gives you an idea of how min(), max() and clamp() work, and more importantly, gives you some ideas of how you might use them.