Dynamic Sizing with CSS min()

Abstract image used to represent Dynamic Sizing with CSS min()
Image by Shubham Dhage.

Use min() when a value should follow the available space up to a cap. It chooses the smallest supplied value, which is useful for a container that can shrink but shouldn't grow indefinitely. max() provides the opposite bound; clamp() combines a preferred value with both limits.


Understanding min()

In the case of min(), and as you can probably guess from the name, we get a function which allows us to provide a set of different values, and expect that the browser will apply whichever is the smallest amongst them.

Here's a quick example:

.element {
  width: min(100%, 50rem);
}

Here, we're setting the width of an element to be the lesser of either 100% (i.e., the full width of the containing element), or 50rem. So, if the container is narrower than 50rem, then the width of .element will be whatever the container width is (100%). However, if the containing element is wider than 50rem, then the browser will apply the other width value (50rem: smaller than 100%) to .element.

This means that .element will grow fluidly with the width of the container on small screens, and then restrict itself at a maximum of 50rem as the screen (and containing element)'s width increases.


Practical Applications

Responsive Typography

You can use min() to cap a responsive font size, but it won't stop that size becoming too small. The following example demonstrates the cap, rather than a complete typography rule.

Take this snippet, for example:

body {
  font-size: min(4vw, 1.8rem);
}

Here, 4vw grows with the viewport width until it reaches the 1.8rem cap. There is no readable minimum: on a narrow viewport, the result can be too small. If the design needs both bounds, use clamp() with a suitable minimum and consider a preferred value combining rem and viewport units. Then check text resizing and browser zoom rather than assuming the formula makes the text accessible.

Responsive Containers

I already touched upon this at the beginning of this article, but really the area where the use of min() shines is in implementing responsive containers and layouts.

Imagine a card component, which should occupy a portion of the viewport width up until a predefined maximum width to maintain content density and readability. Using min(), it might look something like this:

.card {
  width: min(90vw, 30rem);
}

This ensures that our card occupies 90% of the viewport, and is responsive by not exceeding 30rem in width. What's particularly impressive about this (and I've said the same before about calc()) is that there's no need whatsoever for media queries in layouts like this, making your code simpler, quicker, and easier to understand.


Browser Support and Workarounds

By April 2024, min() was available across current browser engines. Internet Explorer did not support it, so check the browsers your readers need before relying on it for essential layout. For a simple width cap, the older sizing properties give us a straightforward fallback.

A viewport media query can approximate the first example when the containing block tracks the viewport width:

.element {
  width: 100%;
}

@media (min-width: 50rem) {
  .element {
    width: 50rem;
  }
}

That media query measures the viewport, whilst the 100% in min(100%, 50rem) measures the containing block. They aren't generally equivalent: a narrow container can still sit inside a wide viewport. For this example, width: 100% with max-width: 50rem follows the container correctly.

The example above can be achieved just like this too:

.element {
  width: 100%;
  max-width: 50rem;
}

So, in these simpler layoutbased uses, you may not need to use min() (or max()) at all...

Having reread this sometime after it was published, I should also say: min() and max() can both accept any number of different values. I tend to write examples with two simply because it's easier to say, "This value is bigger than that" (or vice versa). You could include any number of different viewport, fixed, fluid, etc values within the function. The browser will simply use whichever is the smallest at that point in time.


Need a senior engineer involved?

I can work directly in the codebase, review the architecture, or support the team through delivery when the work needs more than extra hands.