min-content, max-content, and fit-content() Explained
CSS sizing keywords like min-content, max-content, and fit-content() describe a box's width in terms of what it contains rather than a fixed length or a percentage of its parent. They are the vocabulary of intrinsic sizing, and knowing exactly what each one computes turns a category of fiddly layout problems — auto-width buttons, shrink-to-fit sidebars, label columns that never wrap awkwardly — into one-line declarations. This guide explains what each keyword evaluates to and where it is the right tool. It is part of Intrinsic Sizing Techniques within Mastering Container Queries & Responsive Layouts.
Why intrinsic keywords instead of fixed widths or percentages
The common alternatives each have a failure mode. A fixed width ignores the content and either clips it or leaves dead space. A percentage width tracks the parent but is blind to what is inside the box, so a tiny label and a paragraph get the same width. The intrinsic keywords flip the relationship: they ask the content how much room it needs and size the box from the answer, which is precisely what you want for elements whose size should follow their text.
There is no JavaScript measurement involved, which matters for both performance and correctness. A common pattern people reach for is reading scrollWidth in script to size an element to its content; that forces a synchronous layout and runs after paint, so it can flash. The intrinsic keywords are resolved by the engine during layout itself, so the box is correct on first paint with no measurement pass and no flash. Accessibility benefits too: because the box sizes to real content, text reflows naturally under zoom instead of being trapped at a scripted pixel width that ignores the larger glyphs.
The cost is that these keywords can produce surprising widths if you do not know their definitions — a min-content box can collapse to one long word, and a max-content box can blow past its parent. The fix is understanding, not avoidance.
What each keyword computes
The three keywords answer three different questions about the same content:
min-contentis the smallest width the box can take without its content overflowing. Practically, it is the width of the widest unbreakable unit — the longest word, the longest URL, the widest replaced element. Text wraps at every opportunity.max-contentis the box's preferred width: how wide it would be if nothing ever wrapped, as on an infinitely wide canvas. For a paragraph that is the full text on one line.fit-content(limit)is a hybrid: it behaves likemax-contentuntil the content would exceedlimit, then it caps atlimitand lets the content wrap. The barefit-contentkeyword is equivalent tofit-content(stretch), clamping the preferred size to the available space. Formally it ismin(max-content, max(min-content, available-or-limit)).
The implementation below renders the same paragraph in four boxes so you can see the differences directly.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; max-width: 40rem; }
.box {
border: 2px solid #7aa2ff;
padding: 0.5rem;
margin-bottom: 1.5rem;
background: #7aa2ff14;
}
.label { font: 600 0.75rem ui-monospace, monospace; color: #555; margin: 0 0 0.25rem; }
.box p { margin: 0; line-height: 1.4; }
/* Collapses to the widest single word; everything else wraps */
.min { width: min-content; }
/* Preferred width: the whole sentence on one line, even past the parent */
.max { width: max-content; }
/* max-content until it would exceed 18rem, then caps and wraps */
.fit { width: fit-content(18rem); }
/* Bare keyword: shrink-wrap, but never exceed the available space */
.fitbare { width: fit-content; }
</style>
</head>
<body>
<div class="box min">
<p class="label">width: min-content</p>
<p>Intrinsic sizing keywords describe width by content.</p>
</div>
<div class="box max">
<p class="label">width: max-content</p>
<p>Intrinsic sizing keywords describe width by content.</p>
</div>
<div class="box fit">
<p class="label">width: fit-content(18rem)</p>
<p>Intrinsic sizing keywords describe width by content.</p>
</div>
<div class="box fitbare">
<p class="label">width: fit-content</p>
<p>Intrinsic sizing keywords describe width by content.</p>
</div>
</body>
</html>
The min-content box narrows until its tallest, thinnest column of wrapped text fits the longest word; max-content stretches the sentence onto one line and can overflow the page; fit-content(18rem) shrink-wraps but stops at 18rem; bare fit-content shrink-wraps but never exceeds the body width.
Key technique: fit-content() as a grid track
The single most valuable place these keywords appear is grid track sizing, where fit-content() solves the classic label-column problem. A track defined as fit-content(12rem) sizes itself to its widest cell content but refuses to exceed 12rem, so a sidebar of labels is as wide as the longest label needs and no wider, yet a freakishly long label wraps instead of pushing the main column off-screen.
.layout {
display: grid;
/* label column shrink-wraps up to 12rem; content takes the rest */
grid-template-columns: fit-content(12rem) 1fr;
gap: 1rem;
}
This is impossible to express cleanly with fixed or percentage widths, because the correct width depends on the content.
Variation: RTL and a max-content button row
max-content shines for a row of buttons that must each hug their label, never stretch, and stay correct in right-to-left layouts. Setting each control to width: max-content makes it exactly as wide as its text plus padding, and because it is content-driven it mirrors correctly under direction: rtl with no extra rules.
.toolbar {
display: flex;
gap: 0.5rem;
}
.toolbar button {
width: max-content; /* hugs its own label, never stretches */
padding-inline: 1rem; /* logical padding flips automatically for RTL */
}
.toolbar[dir="rtl"] {
/* no width changes needed; max-content + logical padding handle it */
flex-direction: row-reverse;
}
Using padding-inline rather than padding-left/padding-right keeps the hugging behavior symmetric in both writing directions.
Browser support note
min-content and max-content are supported as width and height values in Chrome 46+, Edge 79+, Safari 11+, and Firefox 66+, so they are safe everywhere today. fit-content() as a track and box sizing function is supported in Chrome 57+, Edge 79+, Safari 11+, and Firefox 91+. No fallback is needed for current engines; if you target very old browsers, a fixed max-width is the closest graceful degradation.
FAQ
What is the difference between min-content and max-content?min-content is the smallest a box can be without overflowing its content, roughly the width of its longest unbreakable word. max-content is the box's preferred width with no wrapping at all, the width it would take on an infinitely wide canvas.
When should I use fit-content() instead of max-content?
Use fit-content() when you want a box to shrink-wrap its content but never exceed a cap. It behaves like max-content until the content reaches the limit you pass, then it stops growing and wraps, which max-content never does.
Does fit-content() work as a grid track size?
Yes. fit-content(limit) is a valid grid track sizing function: the track sizes to its content up to the limit, then caps. It is one of the most useful sidebar and label-column track definitions.
Why does my width: min-content element look too narrow?
Because min-content collapses to the longest unbreakable run of content. Long words, URLs, or non-breaking phrases set the floor; if there are none, the box can become as narrow as a single character.
Related
- Intrinsic Sizing Techniques — the parent guide for content-driven sizing.
- aspect-ratio for Responsive Media — reserving box dimensions before media loads.
- Building a Fluid Spacing Scale — pairing intrinsic widths with fluid padding tokens.
- Container vs Media Queries Comparison — sizing components by their own context.
- Smooth Hover Effects Without JavaScript — cross-area: content-sized controls that animate on hover.
Related articles
More pages in the same section.