I keep a card component that ships in two sizes. The large variant bumps the font size to 1.25rem, and for a long time I wrote a second padding rule to match. Then I changed one line and deleted the second rule for good:
The em values resolve against the element's own font size, so the large variant's padding scales up with its type automatically. No second rule, and no drift when someone changes the scale six months from now. Using em in the preferred value ties the fluid expression to the component instead of the page, and that is the whole trick.
What each slot does with em in it
Minimum and maximum in em keep the floor and ceiling proportional to the component. The preferred value is where the interesting part lives: 0.75em + 2vw means the fluid middle grows with the viewport but stays anchored to the component's type size. Double the component's font size and the entire clamp range roughly doubles with it. The viewport part still does its job at every size; the em part just moves the whole range up or down with the component.
The decision rule: em for the box, rem for the type
Here is the rule I use. If the value should track the component's own font size, card padding, button padding, badge border-radius, the gap inside a sized container, put em in the preferred value. If it should track the user's global text setting, body copy, headings, page-level spacing, use rem.
The reason is the accessibility contract. Guidance for fluid type says the preferred value should include a rem component so the fluid part keeps responding when a user raises their browser font size. A preferred value built only from viewport units can freeze the scaling relative to the user's setting. For text itself, keep the shape clamp(1rem, 0.5rem + 2vw, 2rem): rem endpoints, rem anchor in the middle. Use the em pattern for the box around the text, not the text.
Where it breaks
Nesting. A child component with its own em-based clamp inside a parent that scaled its font size multiplies the scaling, because the child's em resolves against the parent's already-scaled size. The padding comes out larger than either declaration suggests. Devtools will not help much here: the computed panel shows a px value that hides the relationship entirely, so you have to read the declared value to see the compounding.
Two fixes. Reset the font size at the component root so the em has a known anchor, or switch the nested component to rem. I do the first for leaf components like buttons and badges, and the second for anything that gets composed inside other components, since I cannot control what font-size context it lands in. Either way, the rule is: one em-anchored component per stacking context of font sizes, not two.
The pattern is one line and it removes a whole class of variant overrides. It belongs on component chrome, not on text sizing, and not inside nested font-size contexts.
Frequently asked questions
Can you use em units inside clamp()?
Yes. All three arguments of clamp() can use em, which resolves against the element's own computed font size. Mixed with viewport units inside calc(), it works in every browser that supports clamp().
Does em in clamp() hurt accessibility?
For text sizing it can, because the fluid part stops tracking the user's root font-size setting. Keep min and max in rem for text and include a rem component in the preferred value. Use em-based clamps for component spacing and chrome instead.
Should the preferred value use em or rem?
Use em when the value should scale with the component's own font size, such as card or button padding. Use rem when it should follow the page's base font size and the user's browser settings, such as body copy and headings.
Why does my nested component's em clamp() look wrong?
em compounds: the child's em resolves against the parent's already-scaled font size, multiplying the effect. Reset font-size at the component root or switch the nested component to rem.
Does clamp() with em work in all browsers?
Yes. em is one of the oldest CSS units and clamp() has shipped in all modern browsers since 2020, so the combination needs no special fallback beyond your normal clamp() fallback.
Generate your own clamp() values
Dial in min and max sizes, preview the fluid scale live, and copy production-ready CSS.
Keep reading
The clamp() Preferred Value Formula, Worked by Hand
The linear-interpolation math behind the middle slot, with three worked examples you can check in devtools.
rem vs px in the clamp() Preferred Value
Why the unit in the middle changes what user zoom does to your fluid type.
Does clamp() With vw Break Browser Zoom?
The accessibility question behind every fluid-type snippet, answered with the rem-component rule.
Fluid Type Scale With CSS clamp(): Building It From a Modular Ratio
Let the ratio pick the sizes and clamp() make them fluid, with real scale output values.