FullStack Course LogoFullStack Course
Module: CSS
CSS·024·10 MIN READ

024: Sizing, Units, Constraints, and Overflow

TOPICS COVERED: Sizing, Units, Constraints, and Overflow

Learning outcomes

By the end of this lesson, you can choose between absolute, font-relative, viewport, and percentage lengths. You can express a preferred size with useful limits instead of locking a component to a rigid dimension, build fluid media, explain intrinsic sizing, and diagnose the source of overflow. You will also be able to check that content survives zoom and narrow widths.

Prerequisites and retrieval

Start with yesterday's border-box setup. Before moving on, calculate a card's occupied inline size from its content, padding, border, and margin, and recall why a fixed height around text is risky. Today we will make that card fluid without reaching for Flexbox, Grid, or media queries.

Terminology

  • Absolute length: A unit with a fixed physical-ish definition, such as px (a CSS reference pixel). — Source: MDN: Values and units
  • Relative length: A unit whose value depends on another measure: %, em, rem, ch, or vw. — Source: MDN: Values and units
  • Intrinsic size: A size determined by the element's own content, such as min-content or max-content. — Source: CSS Sizing 3: Intrinsic sizes
  • Extrinsic size: A size imposed by outside constraints rather than determined by content. — Source: CSS Sizing Level 3
  • Min/max constraint: A lower or upper bound that clamps a computed size. — Source: CSS Sizing Level 3
  • Overflow: Content that extends beyond its box's bounds, with its behavior controlled by overflow properties. — Source: MDN: Overflowing content
  • Replaced element: An element whose content is supplied by an external object, such as an img or video. — Source: MDN: Sizing items in CSS
  • Containing block: The rectangle against which an element's offsets and percentage sizes resolve. — Source: MDN: Layout and the containing block
  • Width (width): "The width property specifies the width of the content area (or border area under border-box)." — Source: MDN: width
  • Fluid value (clamp()): "clamp(MIN, VAL, MAX) clamps a value between an upper and lower bound." — Source: CSS Values and Units Level 4: clamp()
  • Viewport unit (vw/dvh): "1vw = 1% of viewport width; dvh = dynamic viewport height." — Source: MDN: CSS values and units — Viewport units

Mental model: available space negotiating with content

Responsive sizing is a negotiation. Available space, the content's minimum needs, its preferred size, and explicit constraints all participate in the result. width: 40rem demands one size. max-inline-size: 40rem; inline-size: 100% describes a relationship instead: fill the available inline space, but never grow beyond 40rem. That second relationship usually survives changing content and viewport sizes better.

Think of units in terms of what they should depend on:

  • rem: typography, spacing, and target dimensions tied to the user's font settings.
  • em: local sizing tied to a component's text.
  • %: relative to a containing block for many size properties.
  • ch: a readable text measure.
  • px: thin borders and exact small details; it remains a CSS reference unit.
  • viewport units: useful when a design genuinely relates to viewport dimensions, but a poor default for forcing text containers to viewport heights.

Use min-*, a preferred size, and max-* as guardrails. In most content components, the content should determine the block height.

Beginner example: fluid portfolio shell and media

css
html { box-sizing: border-box; }
*, *::before, *::after { box-sizing: inherit; }

body {
  margin: 0;
  color: rgb(30 41 59);
  background: rgb(248 250 252);
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

.site-shell {
  inline-size: 100%;
  max-inline-size: 70rem;
  margin-inline: auto;
  padding-inline: 1rem;
}

.prose {
  max-inline-size: 65ch;
}

img,
svg,
video {
  display: block;
  max-inline-size: 100%;
  block-size: auto;
}

.project-card {
  inline-size: 100%;
  max-inline-size: 36rem;
  min-block-size: 12rem;
  padding: 1rem;
  border: 1px solid rgb(203 213 225);
  background: white;
}
html
<div class="site-shell">
  <main>
    <section class="prose">
      <h1>Selected work</h1>
      <p>Projects built with semantic HTML and resilient CSS.</p>
    </section>
    <article class="project-card">
      <img src="images/library.jpg" width="960" height="540" alt="Library finder search results">
      <h2>Library finder</h2>
      <p>A long description may wrap to several lines without being clipped.</p>
    </article>
  </main>
</div>

The shell occupies the available width until it reaches 70rem; after that, the auto margins divide the remaining space. Its inline padding keeps content away from the viewport edges. The media can shrink to fit the container while retaining its aspect ratio. The HTML width and height attributes let the browser reserve the correct proportional space before the image downloads, which reduces layout shift. min-block-size gives the card a floor without preventing longer content from making it taller. Replacing it with block-size: 12rem would risk clipping that content.

Resize the browser continuously rather than checking only a few breakpoint presets. This behavior needs no breakpoint.

Intermediate example: intentional overflow

Overflow is evidence about a sizing decision, not automatically a defect. For example, long unbreakable data can exceed a card:

html
<article class="project-card">
  <h2>API explorer</h2>
  <p class="resource-url">https://example.com/a-very-long-unbroken-resource-identifier-that-continues</p>
  <pre><code>const result = await fetch("/projects?sort=recent");</code></pre>
</article>
css
.resource-url {
  overflow-wrap: anywhere;
}

pre {
  max-inline-size: 100%;
  overflow-x: auto;
  padding: 1rem;
  background: rgb(15 23 42);
  color: rgb(226 232 240);
}

Prose URLs can safely break at any point. Code is different: whitespace can carry meaning, so a local horizontal scrollbar is preferable to wrapping the code or making the whole page wider. Avoid putting overflow-x: hidden on body just to hide the symptom. It can leave off-screen content unreachable.

For a thumbnail that should crop to a fixed proportion:

css
.project-thumbnail {
  inline-size: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 0.5rem;
}

The aspect ratio reserves proportional geometry, while object-fit: cover crops the replaced image so it fills that geometry. Check that the crop does not remove meaningful information. If the complete screenshot matters, use an ordinary fluid image instead.

Optional advanced example: bounded fluid values

clamp(minimum, preferred, maximum) is broadly supported:

css
.hero {
  padding-block: clamp(2rem, 8vw, 6rem);
}

.hero h1 {
  font-size: clamp(2rem, 1.5rem + 3vw, 4.5rem);
}

The preferred term grows with viewport width but cannot move below the minimum or above the maximum. For fluid text, keep a rem contribution in the preferred expression so zoom and user font settings still influence the result. clamp() expresses a constraint compactly; it does not remove the need to test real content.

Viewport heights deserve extra care on mobile because browser controls can appear and disappear. When a genuinely full-height panel is required, modern dynamic viewport units such as dvh follow those visible viewport changes more closely. For most content pages, min-block-size or natural content height is safer than forcing the content to fit one screen.

Mistakes, debugging, and DevTools

  • Fixed width wider than the viewport: replace it with a fluid preferred size plus max-inline-size.
  • width: 100vw on page content: viewport width can include scrollbar space and cause horizontal overflow; 100% usually fits the containing block.
  • Fixed card height: text clips or overlaps under zoom. Prefer min-block-size or no block size.
  • Unconstrained images: intrinsic pixel width can exceed the container.
  • Global overflow: hidden: hides evidence, clips focus, and can make content inaccessible.
  • Percentage height with no definite containing-block height: it may resolve unexpectedly.
  • Using viewport-only font size: text can become too small or ignore zoom expectations.

In DevTools, enable responsive/device mode and drag the width continuously instead of testing only presets. Inspect the computed used width, maximum width, and box sizing. Find the element that extends past the viewport; during debugging, you can temporarily apply * { outline: 1px solid red; } and then remove it. The Layout or Rendering tools may reveal which element owns scrollable overflow. Test long words, 200% and 400% zoom, larger default fonts, and translated text. These cases expose constraints that ordinary sample copy often hides.

Accessibility and performance

WCAG Reflow expects content to work without two-dimensional scrolling at 320 CSS pixels wide, or at 256 CSS pixels high for vertical writing, except where the content inherently requires a two-dimensional layout. A code sample may have a local scrollbar; the article as a whole should not.

Never clip essential text. Keep focus indicators visible near constrained edges, and let controls and labels wrap. rem dimensions generally adapt better to text preferences, but relative units alone do not guarantee reflow.

Give images width and height attributes so the browser can reserve space and reduce cumulative layout shift, then constrain them with CSS. Serve appropriately sized, compressed images rather than downloading a massive file and shrinking it visually. CSS sizing changes the display dimensions; it does not reduce the number of file bytes transferred.

Deep dive: choose units by what the value should depend on

Choose a unit by identifying its dependency:

  • px: a device-independent CSS pixel; useful for thin borders and exact small details.
  • rem: the root font size; useful for consistent type and spacing scales.
  • em: the current element's font size; useful when a component should scale with its own text.
  • %: relative to a property-specific reference, often a containing block.
  • vw / vh: viewport width or height.
  • svh / lvh / dvh: small, large, and dynamic viewport-height variants that account for mobile browser UI behavior.
  • ch: an approximate width of the 0 glyph; useful for text measure.
  • fr: a Grid-only share of leftover track space.
  • cqw / cqh: container query units once a query container exists.

Do not choose units because they are fashionable. Ask what should happen when the user changes text size, the container gets narrower, or browser chrome changes.

Deep dive: intrinsic sizing keywords

CSS can derive a size from content:

css
.badge {
  inline-size: max-content;
}

.search {
  inline-size: min(100%, 32rem);
}

.panel {
  inline-size: fit-content(40rem);
}

Grid and Flexbox also use intrinsic concepts such as min-content and max-content when they determine minimums and track sizes.

A well-known Grid overflow fix is:

css
.layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 18rem;
}

minmax(0, 1fr) explicitly allows the flexible track to shrink below its content-based automatic minimum. Without that lower bound, a long item can keep the track wider than the space appears to allow.

Deep dive: math functions

calc()

css
.sidebar {
  inline-size: calc(100% - 2rem);
}

calc() is useful when different unit types need to participate in one expression.

min() and max()

css
.shell {
  inline-size: min(100% - 2rem, 72rem);
  margin-inline: auto;
}

Read this as: choose the smaller of “viewport/container minus gutters” and “72rem”.

clamp()

css
.section {
  padding-block: clamp(2rem, 5vw, 6rem);
}

clamp(min, preferred, max) is a concise way to create a bounded fluid value.

Worked example: responsive shell with no media query

css
.shell {
  width: min(100% - 2rem, 75rem);
  margin-inline: auto;
}

.hero {
  padding-block: clamp(3rem, 10vw, 8rem);
}

.hero h1 {
  font-size: clamp(2.25rem, 1.5rem + 4vw, 5rem);
}

The page grows continuously as the available space changes instead of jumping between arbitrary device sizes.

Deep dive: aspect ratio and replaced elements

css
.thumbnail {
  aspect-ratio: 16 / 9;
  width: 100%;
  object-fit: cover;
}

aspect-ratio contributes a preferred width-to-height relationship. object-fit controls how replaced content such as an image or video fits inside its content box.

Use:

css
.avatar {
  inline-size: 4rem;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 50%;
}

This creates a stable square crop without hard-coding both width and height.

Deep dive: overflow is a behavior decision

Common values include:

css
.demo-a { overflow: visible; }
.demo-b { overflow: hidden; }
.demo-c { overflow: clip; }
.demo-d { overflow: auto; }
.demo-e { overflow-x: auto; overflow-y: hidden; }

Use auto when scrolling should appear only when it is needed. hidden clips content and establishes scrolling behavior even though the user cannot directly scroll it in the usual way. clip clips content without creating a scroll container.

Scrollable regions need deliberate accessibility decisions:

css
.table-wrap {
  overflow-x: auto;
}

Keep the content keyboard- and reflow-friendly, and avoid trapping users in nested scroll areas unnecessarily.

Worked example: long content destroys a flex layout

html
<div class="row">
  <div class="content">
    https://example.com/a-very-long-unbroken-identifier-that-cannot-wrap
  </div>
  <button>Copy</button>
</div>
css
.row {
  display: flex;
  gap: 1rem;
}

.content {
  min-inline-size: 0;
  overflow-wrap: anywhere;
}

Flex items have an automatic minimum size that can stop them from shrinking. min-inline-size: 0 often fixes the underlying negotiation problem, while overflow-wrap: anywhere gives the text a legal place to break.

Sizing failure lab

When you investigate an overflow bug, test these hypotheses in order:

  1. A child has an intrinsic minimum larger than the available space.
  2. A width combined with padding or border exceeds the container.
  3. A min-width or fixed width is blocking shrinkage.
  4. A transform visually moves content without changing its layout size.
  5. A long word or URL has no break opportunity.
  6. A positioned child is escaping normal size calculations.
  7. The scroll container is the wrong element.

The objective is to find the box that owns the constraint, not to hide the resulting scrollbar.

Tiered exercises

Checkpoint: identify the overflow owner

Horizontal overflow can originate deep inside a page. Start with the document scrollbar, inspect the widest suspicious descendant, and move inward until you find a box crossing its containing block. Check intrinsic images, long tokens, white-space: nowrap, fixed widths, transforms, and 100vw. Repair the responsible component rather than clipping the document.

Separate acceptable overflow from failure. A code sample with a labeled local horizontal scroll area can preserve formatting. A button label, paragraph, or entire page extending off-screen is normally a failure. Keyboard-scroll the local region and confirm that its focus indicator remains visible; mouse scrolling by itself is not enough evidence.

Test every constraint with content shorter and longer than expected. A max-inline-size protects readable measure on wide screens, but it does not force a narrow box to remain wide. A min-block-size supplies visual presence while still yielding to longer text. Describe those relationships in plain language before choosing values. If the sentence says “always exactly,” reconsider whether real content can satisfy it.

Foundation: Make the portfolio wrapper fill available space, stop at 70rem, and center. Make all content images fluid while preserving their aspect ratio.

Core: Replace fixed project card width and height with fluid constraints. Handle a long URL and a code block without hiding page overflow.

Stretch: Add one bounded fluid heading or section-spacing value with clamp(). Explain its minimum, preferred expression, and maximum, then test at narrow width and 200% zoom.

css
.site-shell {
  inline-size: 100%;
  max-inline-size: 70rem;
  margin-inline: auto;
  padding-inline: 1rem;
}
img, svg, video { display: block; max-inline-size: 100%; block-size: auto; }
.project-card {
  inline-size: 100%;
  max-inline-size: 36rem;
  min-block-size: 12rem;
  padding: 1rem;
}
.resource-url { overflow-wrap: anywhere; }
pre { max-inline-size: 100%; overflow-x: auto; padding: 1rem; }
.hero { padding-block: clamp(2rem, 8vw, 6rem); }
.hero h1 { font-size: clamp(2rem, 1.5rem + 3vw, 4.5rem); }

The card has no fixed block size, so its content can grow. Only the code block scrolls horizontally; the page itself remains within the viewport.

Recap and exit questions

Resilient sizing describes relationships and limits instead of prescribing one rigid dimension. Let content determine block size, constrain inline measure, make media fluid, and fix the source of overflow rather than hiding it.

  1. When is rem preferable to px?
  2. Why can 100vw produce page overflow?
  3. What is the difference between block-size and min-block-size?
  4. Why should code overflow locally while prose URLs wrap?
  5. What does each argument of clamp() do?

Official references

Reader page: /css/lesson/024/sizing-units-constraints-and-overflow