logo

NJP

CSS min() All The Things — Smashing Magazine

Articles on Smashing Magazine — For Web Designers And Developers · Oct 17, 0000 · article

Did you see [this post](https://frontendmasters.com/blog/what-if-you-used-container-units-for-everything/) that Chris Coyier published back in August? He experimented with CSS container query units, going all in and using them for every single numeric value in a demo he put together. And [the result](https://codepen.io/chriscoyier/pen/OJYKLXz) was… not too bad, actually.

See the Pen [Container Units for All Units \[forked\]](https://codepen.io/smashingmag/pen/ExqWXOQ) by [Chris Coyier](https://codepen.io/chriscoyier).

What I found interesting about this is how it demonstrates the complexity of sizing things. We’re constrained to absolute and relative units in CSS, so we’re either stuck at a specific size (e.g., `px`) or computing the size based on sizing declared on another element (e.g., `%`, `em`, `rem`, `vw`, `vh`, and so on). Both come with compromises, so it’s not like there is a “correct” way to go about things — it’s about the element’s context — and leaning heavily in any one direction doesn’t remedy that.

I thought I’d try my own experiment but with the CSS `min()` function instead of container query units. Why? Well, first off, we can supply the function with **any type of length unit we want**, which makes the approach a little more flexible than working with one type of unit. But the real reason I wanted to do this is personal interest more than anything else.

The Demo

I won’t make you wait for the end to see how my `min()` experiment went:

> Taking website responsiveness to a whole new level 🌐 [pic.twitter.com/pKmHl5d0Dy](https://t.co/pKmHl5d0Dy)
>
> — Vayo (@vayospot) [March 1, 2023](https://twitter.com/vayospot/status/1630863145014112257?ref%5Fsrc=twsrc%5Etfw)


We’ll talk about that more after we walk through the details.

A Little About `min()`

The `min()` function takes two values and applies the smallest one, whichever one happens to be in the element’s context. For example, we can say we want an element to be as wide as `50%` of whatever container it is in. And if `50%` is _greater_ than, say `200px`, cap the width there instead.

See the Pen [\[forked\]](https://codepen.io/smashingmag/pen/LYwWLMg) by [Geoff Graham](https://codepen.io/geoffgraham).

So, `min()` is sort of like container query units in the sense that it is aware of how much available space it has in its container. But it’s different in that `min()` isn’t querying its container dimensions to compute the final value. We supply it with two acceptable lengths, and it determines which is best given the context. That makes `min()` (and `max()` for that matter) **a useful tool for responsive layouts that adapt to the viewport’s size**. It uses conditional logic to determine the “best” match, which means it can help adapt layouts without needing to reach for CSS media queries.

```
.element {
width: min(200px, 50%);
}

/* Close to this: */
.element {
width: 200px;

@media (min-width: 600px) {
width: 50%;
}
}

```

The difference between `min()` and `@media` in that example is that we’re telling the browser to set the element’s width to `50%` at a specific _breakpoint_ of `600px`. With `min()`, it switches things up automatically as the amount of available space changes, whatever viewport size that happens to be.

When I use the `min()`, I think of it as having the ability to make smart decisions based on context. We don’t have to do the thinking or calculations to determine which value is used. However, using `min()` coupled with just any CSS unit isn’t enough. For instance, relative units work better for responsiveness than absolute units. You might even think of `min()` as [setting a _maximum_ value](https://css-tricks.com/min-max-and-clamp-are-css-magic/) in that it never goes below the first value but also caps itself at the second value.

I mentioned earlier that we could use any type of unit in `min()`. Let’s take the same approach that Chris did and lean heavily into a type of unit to see how `min()` behaves when it is used exclusively for a responsive layout. Specifically, we’ll use **viewport units** as they are directly relative to the size of the viewport.

Now, there are different flavors of viewport units. We can use the viewport’s width (`vw`) and height (`vh`). We also have the `vmin` and `vmax` units that are slightly more intelligent in that they evaluate an element’s width and height and apply either the smaller (`vmin`) or larger (`vmax`) of the two. So, if we declare `100vmax` on an element, and that element is `500px` wide by `250px` tall, the unit computes to `500px`.

That is how I am approaching this experiment. What happens if we eschew media queries in favor of only using `min()` to establish a responsive layout and lean into viewport units to make it happen? We’ll take it one piece at a time.

Font Sizing

There are various approaches for responsive type. Media queries are quickly becoming the “old school” way of doing it:

```
p { font-size: 1.1rem; }

@media (min-width: 1200px) {
p { font-size: 1.2rem; }
}

@media (max-width: 350px) {
p { font-size: 0.9rem; }
}

```

Sure, this works, but what happens when the user uses a 4K monitor? Or a foldable phone? There are other tried and true approaches; in fact, [clamp() is the prevailing go-to](https://www.smashingmagazine.com/2023/11/addressing-accessibility-concerns-fluid-type/). But we’re leaning all-in on `min()`. As it happens, just one line of code is all we need to wipe out all of those media queries, substantially reducing our code:

```
p { font-size: min(6vmin, calc(1rem + 0.23vmax)); }

```

I’ll walk you through those values…

1. `6vmin` is essentially 6% of the browser’s width or height, whichever is smallest. This allows the font size to shrink as much as needed for smaller contexts.
2. For `calc(1rem + 0.23vmax)`, `1rem` is the base font size, and `0.23vmax` is a tiny fraction of the viewport‘s width or height, whichever happens to be the largest.
3. The `calc()` function adds those two values together. Since `0.23vmax` is evaluated differently depending on which viewport edge is the largest, it’s crucial when it comes to scaling the font size between the two arguments. I’ve tweaked it into something that scales gradually one way or the other rather than blowing things up as the viewport size increases.
4. Finally, the `min()` returns the smallest value suitable for the font size of the current screen size.

And speaking of how flexible the `min()` approach is, it can restrict how far the text grows. For example, we can cap this at a maximum `font-size` equal to `2rem` as a third function parameter:

```
p { font-size: min(6vmin, calc(1rem + 0.23vmax), 2rem); }

```

This isn’t a silver bullet tactic. I’d say it’s probably best used for body text, like paragraphs. We might want to adjust things a smidge for headings, e.g., `

`:

```
h1 { font-size: min(7.5vmin, calc(2rem + 1.2vmax)); }

```

We’ve bumped up the minimum size from `6vmin` to `7.5vmin` so that it stays larger than the body text at any viewport size. Also, in the `calc()`, the base size is now `2rem`, which is smaller than the default UA styles for `

`. We’re using `1.2vmax` as the multiplier this time, meaning it grows more than the body text, which is multiplied by a smaller value, `.023vmax`.

This works for me. You can always tweak these values and see which works best for your use. Whatever the case, the `font-size` for this experiment is completely fluid and completely based on the `min()` function, adhering to my self-imposed constraint.

Margin And Padding

Spacing is a big part of layout, responsive or not. We need `margin` and `padding` to properly situate elements alongside other elements and give them breathing room, both inside and outside their box.

We’re going all-in with `min()` for this, too. We could use absolute units, like pixels, but those aren’t exactly responsive.

`min()` can combine relative and absolute units so they are more effective. Let’s pair `vmin` with `px` this time:

```
div { margin: min(10vmin, 30px); }

```

`10vmin` is likely to be smaller than `30px` when viewed on a small viewport. That’s why I’m allowing the margin to shrink dynamically this time around. As the viewport size increases, whereby `10vmin` exceeds `30px`, `min()` caps the value at `30px`, going no higher than that.

Notice, too, that I didn’t reach for `calc()` this time. Margins don’t really need to grow indefinitely with screen size, as too much spacing between containers or elements generally looks awkward on larger screens. This concept also works extremely well for padding, but we don’t have to go there. Instead, it might be better to stick with a single unit, preferably `em`, since it is relative to the element’s `font-size`. We can essentially “pass” the work that `min()` is doing on the `font-size` to the `margin` and `padding` properties because of that.

```
.card-info {
font-size: min(6vmin, calc(1rem + 0.12vmax));
padding: 1.2em;
}

```

Now, padding scales with the `font-size`, which is powered by `min()`.

Widths

Setting `width` for a responsive design doesn’t have to be complicated, right? We could simply use a single percentage or viewport unit value to specify how much available horizontal space we want to take up, and the element will adjust accordingly. Though, container query units could be a happy path outside of this experiment.

But we’re `min()` all the way!

`min()` comes in handy when setting constraints on how much an element responds to changes. We can set an upper limit of `650px` and, if the computed width tries to go larger, have the element settle at a full width of `100%`:

```
.container { width: min(100%, 650px); }

```

Things get interesting with text width. When the width of a text box is too long, it becomes uncomfortable to read through the texts. There are competing theories about how many characters per line of text is best for an optimal reading experience. For the sake of argument, let’s say that number should be between 50-75 characters. In other words, we ought to pack no more than 75 characters on a line, and we can do that with the `ch` unit, which is based on the `0` character’s size for whatever font is in use.

```
p {
width: min(100%, 75ch);
}

```

This code basically says: _get as wide as needed but never wider than 75 characters._

Sizing Recipes Based On `min()`

Over time, with a lot of tweaking and modifying of values, I have drafted a list of pre-defined values that I find work well for responsively styling different properties:

```
:root {
--font-size-6x: min(7.5vmin, calc(2rem + 1.2vmax));
--font-size-5x: min(6.5vmin, calc(1.1rem + 1.2vmax));
--font-size-4x: min(4vmin, calc(0.8rem + 1.2vmax));
--font-size-3x: min(6vmin, calc(1rem + 0.12vmax));
--font-size-2x: min(4vmin, calc(0.85rem + 0.12vmax));
--font-size-1x: min(2vmin, calc(0.65rem + 0.12vmax));
--width-2x: min(100vw, 1300px);
--width-1x: min(100%, 1200px);
--gap-3x: min(5vmin, 1.5rem);
--gap-2x: min(4.5vmin, 1rem);
--size-10x: min(15vmin, 5.5rem);
--size-9x: min(10vmin, 5rem);
--size-8x: min(10vmin, 4rem);
--size-7x: min(10vmin, 3rem);
--size-6x: min(8.5vmin, 2.5rem);
--size-5x: min(8vmin, 2rem);
--size-4x: min(8vmin, 1.5rem);
--size-3x: min(7vmin, 1rem);
--size-2x: min(5vmin, 1rem);
--size-1x: min(2.5vmin, 0.5rem);
}

```

This is how I approached my experiment because it helps me know what to reach for in a given situation:

```
h1 { font-size: var(--font-size-6x); }

.container {
width: var(--width-2x);
margin: var(--size-2x);
}

.card-grid { gap: var(--gap-3x); }

```

There we go! We have a heading that scales flawlessly, a container that’s responsive and never too wide, and a grid with dynamic spacing — all without a single media query. The `--size-` properties declared in the variable list are the most versatile, as they can be used for properties that require scaling, e.g., margins, paddings, and so on.

The Final Result, Again

I shared a video of the result, but here’s a link to the demo.

See the Pen [min() website \[forked\]](https://codepen.io/smashingmag/pen/wvVdPxL) by [Vayo](https://codepen.io/vayospot).

So, is `min()` the be-all, end-all for responsiveness? Absolutely not. Neither is a diet consisting entirely of container query units. I mean, it’s cool that we can scale an entire webpage like this, but the web is never a one-size-fits-all beanie.

If anything, I think this and what Chris demoed are **warnings against dogmatic approaches to web design** as a whole, not solely unique to responsive design. CSS features, including length units and functions, are tools in a larger virtual toolshed. Rather than getting too cozy with one feature or technique, explore the shed because you might find a better tool for the job.

View original source

https://smashingmagazine.com/2024/10/css-min-all-the-things/