Clamp-based sizing

클램프 레이아웃

clamp(min, preferred, max) grows and shrinks a value smoothly between two bounds, proportional to the viewport — with zero media queries.

Also known as: CSS clamp()Fluid sizing
···
html
<div class="area">
  <div class="viewport" id="viewport">
    <div class="box" id="box"><span id="val">–</span></div>
  </div>
  <div class="code">width: clamp(70px, 55%, 220px)</div>
</div>
css
.area{width:min(94%,480px);display:flex;flex-direction:column;align-items:center;gap:10px}
.viewport{width:26%;min-width:110px;max-width:92%;border:2px dashed var(--muted);border-radius:10px;padding:12px;
  transition:width 3s cubic-bezier(.4,0,.2,1);display:flex;justify-content:center;box-sizing:border-box}
.viewport.wide{width:92%}
.box{width:clamp(70px,55%,220px);flex-shrink:0;height:44px;border-radius:8px;background:var(--accent);display:grid;place-items:center;
  color:#fff;font:800 clamp(10px,2vmin,13px)/1 ui-monospace,monospace;transition:background .3s}
.box.clamped{background:var(--accent-2)}
.code{font:700 clamp(9px,1.6vmin,11px)/1 ui-monospace,monospace;color:var(--muted)}
js
const viewport = document.getElementById('viewport');
const box = document.getElementById('box');
const val = document.getElementById('val');
setInterval(() => viewport.classList.toggle('wide'), 3200);
function tick() {
  const w = box.getBoundingClientRect().width;
  val.textContent = Math.round(w) + 'px';
  box.classList.toggle('clamped', w <= 72 || w >= 218);
  requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

clamp(A, B, C) uses the middle value (B, the "preferred" value) by default, but clips it down to A if it would go smaller, or up to C if it would go bigger. Put a vw unit (proportional to viewport width) in the preferred slot — clamp(70px, 40%, 220px), say — and the value grows along with the screen (or container) until it hits the stated floor or ceiling, then stops there.

Getting the same effect with media queries means defining stepped values at each breakpoint — @media (min-width: …) { font-size: 18px } — and the value jumps abruptly at each one, with nothing happening in between. clamp() mathematically interpolates between the two bounds instead, turning the jump into a ramp — which is exactly why it's called "fluid" typography or layout.

The most common trap is leaving no relative unit in the middle term at all. clamp(16px, 16px, 32px) never moves regardless of viewport, because the preferred value is a fixed 16px — making it actually fluid requires a vw, a %, or a mixed calc() like 1rem + 2vw in that middle slot.

When to use

A reasonable default for most numbers that shouldn't be a single fixed value but also aren't worth defining separately at every breakpoint — heading sizes, card widths, section padding.