Skip to content

Containers

Layout containers center content and constrain its width. Included in @grundtone/design-tokens CSS — see Installation for setup. Examples below have a Code / Preview tab.

How it works

Every container shares the same base: width: 100%, centered with margin-inline: auto, and fluid gutters that scale smoothly with the viewport. Unlike Bootstrap's fixed-pixel padding, Grundtone uses clamp() for gutters that adapt from 16px on mobile to 32px on desktop — no breakpoint jumps.

All containers are also container query contexts (container-type: inline-size), so cq-sm:, cq-md:, cq-lg: utilities work on children without needing an extra class.


Basic container

The .container class steps up max-width at each breakpoint. The max-width is computed automatically: breakpoint - gutter * 2, giving breathing room from the viewport edge.

.container — centered, fluid gutters, max-width steps up at each breakpoint
BreakpointViewportmax-width (approx)
< sm< 640px100%
sm640px~608px
md768px~704px
lg1024px~960px
xl1280px~1216px
2xl1536px~1472px

Note: Max-widths are approximate because the gutter scales fluidly via clamp(1rem, 4vw, 2rem). At wider viewports the gutter reaches its 2rem cap, making the math: breakpoint - 4rem.


Fluid container

Always 100% width. Same fluid gutters and centering, but no max-width cap:

.container-fluid — always 100% width, no max-width cap

Responsive containers

.container-{bp} is 100% until the named breakpoint, then it steps up from there. Use these when you want full-width on smaller screens but constrained on larger ones.

.container-lg — fluid until 1024px, then constrained

Available: .container-sm, .container-md, .container-lg, .container-xl, .container-2xl.


Content-width containers

Fixed max-width containers for specific content patterns. All sizes shown side by side:

.container-tight (640px)
.container-narrow (768px)
.container-prose (65ch)
.container (responsive)
.container-wide (1400px)

Narrow and tight

For focused reading and forms:

.container-narrow — max 768px
.container-tight — max 640px

Wide

For dashboards and data-heavy layouts:

.container-wide — max 1400px

Prose container

.container-prose constrains width to 65ch — the typographic standard for optimal line length. Since ch is relative to the font, the width adapts automatically to any typeface:

The .container-prose class constrains content to 65ch — the typographic standard for optimal line length. This keeps paragraphs comfortable to read regardless of viewport width. No fixed pixel value; it adapts to the font.


CSS custom properties

Every container is driven by two CSS custom properties that you can override at any level:

PropertyDefaultDescription
--container-max100% (or computed)The max-width constraint
--container-gutterclamp(1rem, 4vw, 2rem)Inline padding (gutters)

Override max-width

Set --container-max inline to make any container a specific width:

--container-max: 480px (runtime override)

Override gutters

Set --container-gutter to control the internal padding:

--container-gutter: 3rem (large gutters)

This composability means you rarely need custom CSS. Just override the variable on the element.


Breakout

.breakout lets a child element break out of its container to span the full viewport width. Useful for hero images, full-width banners, or edge-to-edge sections inside a narrow container:

Normal content inside .container

.breakout — full viewport width, breaks out of container

Back to normal container width

html
<div class="container">
  <p>Normal content, constrained by the container.</p>

  <div class="breakout">Full viewport width — breaks out of the container.</div>

  <p>Back to container width.</p>
</div>

Note: .breakout uses width: 100vw which includes the scrollbar width on some browsers. Add overflow-x: hidden on <html> or <body> if you see a horizontal scrollbar.


Container queries

Every layout container automatically sets container-type: inline-size, making it a container query context. Children can use cq- prefixed utility classes that respond to the container's width instead of the viewport.

This is the key difference from viewport breakpoints (sm:, md:): a sidebar card at 300px should show single-column layout even on a 1440px screen. Viewport classes can't do that — container queries can.

CQ vs viewport

Same markup, same cq-md:grid-cols-2 class — the narrow container stays single-column while the wide one switches to two columns:

Narrow container (280px)

A
B

Wide container (remaining space)

A
B

CQ breakpoints

PrefixMin-widthPixels
cq-sm:24rem384px
cq-md:32rem512px
cq-lg:48rem768px
cq-xl:64rem1024px
cq-2xl:80rem1280px

Grid columns

cq-sm:grid-cols-2, cq-lg:grid-cols-4 — same classes as the grid utilities, just container-relative:

Card 1
Card 2
Card 3
Card 4

Flex direction

Stack vertically in narrow containers, go horizontal when there's room:

Card Title

Stacks vertically in narrow container

Card Title

Goes horizontal when container is wide enough

Show/hide elements

cq-md:block with hidden — the label only appears when the container is wide enough:

Narrow

Wide

Available CQ utilities

All CQ utilities mirror their viewport equivalents with a cq-{bp}: prefix:

CategoryClassesBreakpoints
Displayblock, inline-block, inline, flex, inline-flex, grid, inline-grid, hiddensm–xl
Grid columnsgrid-cols-1, grid-cols-2, grid-cols-3, grid-cols-4, grid-cols-6, grid-cols-12sm–lg
Flexboxflex-row, flex-col, flex-wrap, flex-nowrap, justify-start/center/end/between, items-start/center/endsm–lg
Spacingp-0p-12, m-0m-12 (scale varies per breakpoint)sm–lg
Text sizetext-xstext-3xl (scale varies per breakpoint)sm–lg

Named containers

For component-level container queries, use named containers instead of relying on the nearest ancestor:

Named container — padding and font-size adapt to container width
Same classes, narrower container
html
<div class="cq-card">   <!-- container-name: card -->
  <div class="card-compact card-normal card-spacious">
    Content adapts to the card's own width
  </div>
</div>
Classcontainer-name
.cq-cardcard
.cq-sidebarsidebar
.cq-mainmain
.cq-modalmodal

Container type utilities

If you need a CQ context without a layout container, use these:

Classcontainer-type
.cq-containinline-size
.cq-sizesize
.cq-normalnormal (reset)

Browser support

Container queries are supported in all modern browsers. For older browsers, a @supports fallback hides cq-*:hidden elements by default.


Containers + Grid

Containers and grid work together. Put a grid inside a container for a centered, responsive layout:

1
2
3
html
<div class="container">
  <div class="grid grid-cols-3 gap-4">
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </div>
</div>

Logical properties and RTL

All containers use CSS logical properties (padding-inline, margin-inline) instead of physical left/right. This means RTL layouts work automatically — no additional configuration needed.


The make-container mixin

When writing custom SCSS, use the make-container mixin to create your own container variants:

scss
@use '@grundtone/design-tokens/scss/lib' as tokens;

.my-custom-container {
  @include tokens.make-container;
  --container-max: 900px;
}

The mixin applies: fluid gutters, width: 100%, max-width: var(--container-max), margin-inline: auto, and container-type: inline-size.


Class reference

Layout containers

ClassMax-widthDescription
.containerSteps up at each breakpointResponsive centered container
.container-fluid100%Full width, no cap
.container-sm100% until sm, then steps upResponsive from 640px
.container-md100% until md, then steps upResponsive from 768px
.container-lg100% until lg, then steps upResponsive from 1024px
.container-xl100% until xl, then steps upResponsive from 1280px
.container-2xl100% until 2xl, then steps upResponsive from 1536px

Content-width containers

ClassMax-widthUse case
.container-tight640pxForms, dialogs, login
.container-narrow768pxArticles, focused reading
.container-prose65chTypographic optimal line length
.container-wide1400pxDashboards, data tables
.container-ultrawide1600pxFull-featured admin panels

Utilities

ClassDescription
.breakoutFull viewport width, breaks out of container

CSS custom properties

PropertyDefaultDescription
--container-max100% or auto-computedControls max-width
--container-gutterclamp(1rem, 4vw, 2rem)Controls inline padding

Comparison with Bootstrap

FeatureBootstrap 5Grundtone
GuttersFixed 12px / 16pxFluid clamp(1rem, 4vw, 2rem)
Max-widthsSeparate hardcoded mapComputed from breakpoints automatically
CustomizationSCSS variables onlyCSS custom properties (runtime) + SCSS
RTL supportRequires extra configAutomatic via logical properties
Container queriesNot integratedEvery container is a CQ context
Reading-width containerNot available.container-prose (65ch)
Breakout utilityNot available.breakout
Maps to maintain$container-max-widths + $grid-breakpoints$grid-breakpoints only