The most confusing thing about min(), max(), and clamp() is not how they work. Each one is simple. The confusing part is the naming: you use max() to enforce a minimum and min() to enforce a maximum. I wrote min() when I meant a floor at least twice before the penny dropped, so this is the article I would have handed my past self.
The three mental models
Forget the function names for a moment and think about intent:
min(a, b): "Be this, but no larger than that." A ceiling. It returns the smallest of its arguments, so the result can never exceed the smallest one.max(a, b): "Be this, but no smaller than that." A floor. It returns the largest of its arguments, so the result can never drop below the largest one.clamp(min, preferred, max): "Stay between these bounds." A corridor. The browser computes the preferred value and pins it into the [MIN, MAX] range.
That is the whole game. Every use case below is one of these three shapes.
When min() is the right call
Reach for min() when something should be fluid but must never exceed a cap. The classic is the fluid container:
This says: be 70rem wide, unless the screen is too narrow, in which case shrink to 100% minus 3rem of gutter. One declaration replaces width: 100%; max-width: 70rem; padding-inline: 1.5rem; and it behaves identically. Other natural fits: padding: min(5vw, 3rem) for spacing that grows with the viewport but stops at a sane size, and image widths like width: min(100%, 600px).
If you only need a ceiling, min() reads better than a clamp() with a fake floor. Honesty in the declaration counts.
When max() is the right call
Reach for max() when something must never fall below a floor but can grow freely. The cleanest example is touch targets:
Never smaller than 44px (the accessibility minimum), but allowed to grow on large screens. Another: width: max(250px, 20%) for a sidebar that takes a fifth of the layout yet never collapses below 250px on narrow screens. If you only need a floor, max() is the honest expression of that intent.
When clamp() earns its place
Reach for clamp() when both bounds matter and there is a fluid ideal in between. Fluid type is the poster child:
Never smaller than 1.25rem, never larger than 2rem, gliding smoothly in between. clamp() also carries fluid spacing well: padding-block: clamp(2rem, 5vw, 6rem) grows section padding with the viewport, pinned at both ends. And one worth knowing: clamp(MIN, PREFERRED, MAX) is exactly equivalent to max(MIN, min(PREFERRED, MAX)), so you can think of clamp() as the nested shorthand when you need both bounds in one readable expression.
The trap to avoid: a clamp() whose preferred value can never reach one of its bounds. If the vw slope is too shallow, your "maximum" is decorative and the value never gets there on any real screen. Sanity-check at 320px and at 1440px, the way we did in the min/preferred/max explainer.
The naming trap, stated plainly
The CSS spec itself flags this as a known confusion point: because min() returns the smallest value, it is the function you use to impose a maximum on something (like max-width does), and max() is the function you use to impose a minimum. You will reach for the opposite one the first few times. Everyone does.
My rule of thumb when I am unsure: describe the intent in words first. "No larger than 600px" is a ceiling, so min(). "No smaller than 44px" is a floor, so max(). "Between 20px and 32px, fluid in the middle" is a corridor, so clamp(). Words first, function second.
My take
Of the three, min() is the one I underused for the longest time, and it is the one that deletes the most code. Any time you see width: 100% paired with a max-width, or padding paired with a media query that caps it, try a min() first. The clamp() gets the glory in fluid-type articles, but min() is doing the quiet work in most mature stylesheets I admire.
Frequently asked questions
Is clamp() just min() and max() combined?
Functionally, yes. clamp(MIN, PREFERRED, MAX) is exactly equivalent to max(MIN, min(PREFERRED, MAX)). clamp() exists so that corridor stays readable in one expression instead of nested function calls.
When should I use min() instead of clamp()?
When you only need one bound. If the requirement is "fluid, but never wider than 600px," min(100%, 600px) says that directly. A clamp() with an arbitrary floor would be dishonest about the intent.
Do I need calc() inside min(), max(), or clamp()?
No. The math functions accept expressions directly, so min(5vw + 5px, 50px) works without wrapping anything in calc(). You can still use calc() inside them when it helps readability.
What is the browser support for these functions?
All three shipped in every modern browser in 2020 (Chrome 79, Firefox 75, Safari 13.1), alongside each other. If clamp() is safe for your audience, min() and max() are too.