Responsive layout
Page Sections distinguishes viewport width from content-container width. A narrow article in a wide window should still use a narrow content grid. Dimensions are CSS pixels; physical screen size and device pixel ratio do not select a breakpoint.
Viewport classification and page width
| Width | resolveViewportLayout | Default ordinary content width |
|---|---|---|
| <600 | xs | Available width |
| 600–839 | s | Available width |
| 840–1199 | m | Available width |
| 1200–1599 | l | Available width, capped at 1536px |
| 1600–1808 | xl | Parent available width minus 272px, capped at 1536px |
| 1809–2299 | 2xl | Available width, capped at 1536px |
| >=2300 | 3xl | Same ordinary content cap |
The 1536px cap is canonical. resolvePageLayout(ResponsiveLayoutInput) resolves content/menu
positions, including optional scrollbar and safe-area reservations. The native navigation uses
the available containing-block width; mount it at the viewport level.
Navigation shows its item disclosure below 1200px and satellites at 1600px. ContentPage uses its sidebar from 1200px. Image/video pairs split at a 600px container; artwork heroes at 840px.
Content grids
| Unpadded container width | Grid | Columns | Gutter/gap | Heading size / line | Body size / line | Heading gap |
|---|---|---|---|---|---|---|
| <600 | xs | 4 | 12px | 18 / 28px | 14 / 20px | 8px |
| 600–839 | s | 6 | 16px | 18 / 28px | 14 / 20px | 8px |
| 840–1199 | m | 8 | 16px | 20 / 32px | 14 / 20px | 12px |
| >=1200 | l | 12 | 24px | 24 / 40px | 16 / 24px | 16px |
Section creates a named ps-content container, and its inner wrapper supplies one
outer gutter on each side. ContentGrid adds only gaps between columns. A container exactly 840px
wide selects m before its 32px total horizontal padding is subtracted.
For container width c, column count n and gap g, column width is max(0, (c - (n + 1) * g) / n). A span of s columns occupies s * columnWidth + (s - 1) * g, capped by
container width. Numeric core resolution caps c at 1536px and normalizes negative/nonfinite
input to zero. The section content wrapper also caps at 1536px; full layout can extend its
outer surface.
Explicit responsive blocks
<script>
import { Section, ContentGrid, ContentBlock } from '@page-sections/svelte';
</script>
<Section
section={{
id: 'layout',
title: 'Layout',
headline: 'Main story and related notes',
style: { width: '1100px' }
}}
>
<ContentGrid>
<ContentBlock span={{ xs: 4, s: 3, m: 5, l: 8 }}><p>Main story</p></ContentBlock>
<ContentBlock span={{ xs: 4, s: 3, m: 3, l: 4 }}><p>Related notes</p></ContentBlock>
</ContentGrid>
</Section> Below 600px the blocks stack as full rows. On s they split evenly; on m and l the first is wider. Omitted spans fill a row; responsive values inherit mobile-first. Oversized values clamp; nonpositive, noninteger and nonfinite values fill a row. ContentBlock also emits client warnings for invalid/clamped values. Visual order follows source order; no dense placement is applied.
Catalog and editorial cards
Catalog cards use the same media-plus-text layout in CardGridSection and CarouselSection: S/M span 2 columns, L spans 4 (3 on the S grid). Media ratios are 3/2 (default), 4/3 or 1/1; titles have two lines in S/M and three in L, with an additional collection-wide eyebrow line for M/L when used. Text has 12px padding; contained media has an 8px inset. S titles are 12px. The complete card is not constrained to a square. Geometry follows layoutTokens.cards and resolveCardLayout.
Editorial cards use cardVariant="editorial", responsive itemSpan and natural text height and equal grid rows. They support descriptions, footers and independent action links.
Nested text and panels omit redundant outer gutters. A nested grid or catalog establishes a
new grid and owns one gutter pair; nested declarative grids should use <Section inset>. Breakpoint selection always uses that section container before padding.
See Core API and CSS Variables and Layout Tokens.