Controlling the size of elements precisely — while keeping layouts flexible and responsive — is one of the most practical skills in CSS. The width and height properties are only the start; min-width, max-width, min-height, and modern functions like min(), max(), and fit-content give you fine-grained control over how elements resize across screen sizes. In this lesson you will master all sizing properties and build a robust container pattern used on real production sites.
Sizing Properties
| Property | Description | Common Value |
|---|---|---|
width |
Sets the width (content area in content-box; full box in border-box) | 300px, 50%, 100% |
height |
Sets the height — avoid on text containers; let content define height | 200px, 100vh |
min-width |
Element never shrinks below this value | 200px, 0 (flex item fix) |
max-width |
Element never grows beyond this value — essential for readability | 1200px, 65ch |
min-height |
Element grows with content but never below this | 100vh for full-page sections |
max-height |
Caps height — combine with overflow: auto for scrollable areas | 400px |
Intrinsic Sizing Keywords
| Keyword | Behaviour | Use Case |
|---|---|---|
fit-content |
Shrinks to content width but never exceeds parent | Buttons that don’t stretch full width |
min-content |
Shrinks to the smallest possible width (longest word) | Table columns, auto-sizing labels |
max-content |
Grows to fit all content on one line — ignores container | Measuring natural element width |
Modern Sizing Functions
| Function | Returns | Example |
|---|---|---|
min(a, b) |
The smaller of two values | width: min(100%, 600px) |
max(a, b) |
The larger of two values | width: max(300px, 50%) |
clamp(min, val, max) |
val clamped between min and max | width: clamp(200px, 50%, 800px) |
height on elements that contain text. Fixed heights clip content when the user zooms in, increases font size, or views the page at a different screen size. Use min-height instead — the element grows with content but never shrinks below the minimum.width: min(90%, 1200px); margin-inline: auto;. It is fluid below 1200px (90% of viewport), capped at 1200px on large screens, and always centered — all without a single media query.width: 100% means 100% of the containing block’s content area. If the parent has padding and you set box-sizing: content-box, a child with width: 100% can still overflow. Always use the border-box reset to avoid this.Basic Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS Sizing</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; padding: 32px; background: #f8fafc; margin: 0; }
/* The standard responsive container pattern */
.container {
width: min(90%, 1100px);
margin-inline: auto;
}
/* Fixed width — never changes */
.fixed { width: 240px; background: #fee2e2; padding: 12px 16px; border-radius: 8px; margin-bottom: 12px; }
/* Fluid width — fills parent */
.fluid { width: 100%; background: #d1fae5; padding: 12px 16px; border-radius: 8px; margin-bottom: 12px; }
/* Constrained: fluid up to a max */
.constrained {
max-width: 480px;
background: #ede9fe;
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 12px;
}
/* Readable text — max 65ch */
.readable {
max-width: 65ch;
background: #fef9c3;
padding: 16px 20px;
border-radius: 8px;
line-height: 1.7;
margin-bottom: 12px;
}
/* min-height — grows with content, never collapses */
.min-h {
min-height: 100px;
background: #e0f2fe;
padding: 16px;
border-radius: 8px;
margin-bottom: 12px;
}
/* Scrollable max-height box */
.scroll-box {
max-height: 120px;
overflow-y: auto;
background: #f1f5f9;
border: 1px solid #e2e8f0;
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 12px;
line-height: 1.6;
font-size: 0.875rem;
}
/* fit-content button — width matches its text */
.btn-fit {
display: block;
width: fit-content;
padding: 10px 20px;
background: #4f46e5;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
}
</style>
</head>
<body>
<div class="container">
<div class="fixed">width: 240px (fixed)</div>
<div class="fluid">width: 100% (fills container)</div>
<div class="constrained">max-width: 480px (fluid up to 480px)</div>
<div class="readable">max-width: 65ch — ideal reading line length. This text demonstrates how the character unit creates a comfortable measure that adapts to the current font size automatically.</div>
<div class="min-h">min-height: 100px — grows with content, never below 100px</div>
<div class="scroll-box">
max-height: 120px with overflow-y: auto.
Line 1. Line 2. Line 3. Line 4. Line 5. Line 6.
Line 7. Line 8. Line 9. Line 10. Line 11. Line 12.
Scroll to see more content inside this fixed-height box.
</div>
<button class="btn-fit">fit-content button</button>
</div>
</body>
</html>
How It Works
Step 1 — min() Picks the Smaller Value
width: min(90%, 1100px) evaluates both values and applies the smaller one. On a 800px viewport: 90% = 720px, which is less than 1100px, so width = 720px. On a 1400px viewport: 90% = 1260px, which exceeds 1100px, so width = 1100px. This single declaration replaces width: 90%; max-width: 1100px;.
Step 2 — max-width Prevents Unreadably Long Lines
max-width: 65ch constrains the container to 65 “zero” characters wide in the current font. As the user increases their font size, this limit scales proportionally — always maintaining the ideal reading measure regardless of font size.
Step 3 — min-height Prevents Collapse Without Fixing Height
min-height: 100px ensures the element is at least 100px tall even when empty. As content is added, the element grows beyond 100px naturally. A fixed height: 100px would clip content; min-height grows to accommodate it.
Step 4 — max-height with overflow Creates Scrollable Areas
max-height: 120px; overflow-y: auto caps the visible height at 120px and adds a vertical scrollbar only when content exceeds that limit. This is the pattern for chat boxes, log viewers, and expandable content areas.
Step 5 — fit-content Sizes to Content
width: fit-content on a block-level button makes it shrink to the width of its text content, while still respecting padding. The button does not stretch to fill the parent — it behaves like an inline element’s width while remaining block-level for flow purposes.
Real-World Example: Responsive Page Layout System
/* layout-system.css */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
/* ── Container variants ── */
.container { width: min(90%, 1200px); margin-inline: auto; padding-inline: 16px; }
.container-sm { width: min(90%, 720px); margin-inline: auto; padding-inline: 16px; }
.container-md { width: min(90%, 960px); margin-inline: auto; padding-inline: 16px; }
.container-lg { width: min(95%, 1440px); margin-inline: auto; padding-inline: 24px; }
/* ── Full-page hero section ── */
.hero {
min-height: 100vh; /* at least full screen; grows with content */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 80px 24px;
background: linear-gradient(135deg, #1e293b, #312e81);
color: white;
}
.hero h1 {
font-size: clamp(2rem, 5vw, 4rem);
max-width: 20ch; /* prevent super-wide headings */
margin: 0 auto 24px;
line-height: 1.1;
}
.hero p {
font-size: clamp(1rem, 2vw, 1.25rem);
max-width: 55ch;
margin: 0 auto 32px;
opacity: 0.85;
line-height: 1.7;
}
/* ── Scrollable sidebar panel ── */
.sidebar-panel {
width: 280px;
height: 100vh;
max-height: 100vh;
overflow-y: auto;
background: #f8fafc;
border-right: 1px solid #e2e8f0;
padding: 24px 0;
flex-shrink: 0;
}
/* ── Constrained article ── */
.article-body {
max-width: 72ch;
margin-inline: auto;
font-size: 1.05rem;
line-height: 1.8;
padding: 48px 24px;
}
/* ── Responsive image ── */
img {
max-width: 100%; /* never overflow container */
height: auto; /* preserve aspect ratio */
display: block;
}
Common Mistakes
Mistake 1 — Fixed height on text containers
❌ Wrong — content overflows or gets clipped when text wraps:
.card { height: 200px; overflow: hidden; }
/* When user zooms or font increases, text clips */
✅ Correct — use min-height and let content define the height:
.card { min-height: 200px; } /* grows beyond 200px if content requires */
Mistake 2 — width: 100% causing overflow with padding
❌ Wrong — without border-box, child can overflow parent:
/* No box-sizing reset */
.parent { padding: 20px; }
.child { width: 100%; padding: 16px; }
/* Child = 100% + 32px padding = overflows parent */
✅ Correct — the global border-box reset prevents this:
*, *::before, *::after { box-sizing: border-box; }
.parent { padding: 20px; }
.child { width: 100%; padding: 16px; } /* stays within parent */
Mistake 3 — Using max-width without centering
❌ Wrong — constrained to max-width but stuck to the left edge:
.container { max-width: 1200px; }
/* Content is left-aligned — no centering */
✅ Correct — always pair max-width with margin-inline: auto:
.container { max-width: 1200px; margin-inline: auto; }
Quick Reference
| Property / Function | Use | Example |
|---|---|---|
width |
Set element width | width: 300px / 100% |
max-width |
Cap maximum width | max-width: 65ch |
min-width |
Prevent shrinking below | min-width: 0 (flex fix) |
min-height |
Grow with content; never below | min-height: 100vh |
max-height |
Cap height; use with overflow | max-height: 400px; overflow: auto |
min(a, b) |
Fluid up to a cap | width: min(90%, 1200px) |
fit-content |
Size to content, respect parent | width: fit-content |