site: layout width tiers + masonry glide — column changes animate instead of snapping
Named width tiers (mobile/narrow/regular/wide) with body max-width easing between them; grid pages opt in via BaseLayout `wide`. Masonry is now absolute-positioned with FLIP glides on column-count changes: targets are computed from the *final* container width (reading --max, which flips instantly while max-width tweens), mid-glide column changes retarget instead of being dropped, and container height eases so content below rides along. Claude-Session: https://claude.ai/code/session_01ADR9r5rw5NuvvnCxfYbMuc
This commit is contained in:
@@ -20,6 +20,8 @@ interface Props {
|
||||
modifiedTime?: Date;
|
||||
articleTags?: string[];
|
||||
jsonLd?: Record<string, unknown> | Record<string, unknown>[];
|
||||
/** Opt into the wider content tier on roomy viewports (grid/listing pages). */
|
||||
wide?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
@@ -38,6 +40,7 @@ const {
|
||||
modifiedTime,
|
||||
articleTags,
|
||||
jsonLd,
|
||||
wide,
|
||||
} = Astro.props;
|
||||
const siteName = 'Unique';
|
||||
const SITE_FOUNDED = new Date(2026, 4, 3);
|
||||
@@ -77,7 +80,7 @@ const year = new Date().getFullYear();
|
||||
/>
|
||||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js" data-cf-beacon='{"token": "fc978456945c49ae90a0b7e0b891ffd2"}'></script>
|
||||
</head>
|
||||
<body>
|
||||
<body class:list={[{ wide }]}>
|
||||
<header class="masthead">
|
||||
<div class="masthead-row">
|
||||
<div class="masthead-stats">
|
||||
@@ -158,8 +161,32 @@ const year = new Date().getFullYear();
|
||||
--muted: #6b6b6b;
|
||||
--accent: #b34700;
|
||||
--rule: #e0dbd2;
|
||||
/* Content column width. Reading pages keep this tight ("narrow") for a
|
||||
comfortable line length; grid/listing pages opt into wider tiers via
|
||||
<body class="wide"> (BaseLayout `wide` prop). See the tier table below. */
|
||||
--max: 42rem;
|
||||
}
|
||||
/* ── Layout width tiers ────────────────────────────────────────────────
|
||||
Named steps, shared with the masonry column logic (Masonry.astro).
|
||||
Element rem = 18px (html font-size), so --max in rem renders ×18;
|
||||
media-query breakpoints use the browser default (1rem = 16px).
|
||||
|
||||
tier viewport (mq) chrome (--max) grid card
|
||||
mobile ≤ 880px 42rem / fluid 1–2 cols fluid
|
||||
narrow 880–1104px 42rem (756px) 3 cols contained 225px
|
||||
regular 1104–1376px 55.5rem (999px) 4 cols contained 225px (= narrow)
|
||||
wide ≥ 1376px 55.5rem (999px) fluid, full-bleed ~288px (≈ old 3-col)
|
||||
|
||||
• Chrome (masthead, hero, footer) is capped at the regular 55.5rem in
|
||||
BOTH regular and wide — it never moves between them. Only the card grid
|
||||
breaks out to full width in wide (the full-bleed rule is in Masonry.astro).
|
||||
• regular = 4·225 + 3·gap(18) + 2·pad(22.5) = 999px, so its 4 columns
|
||||
match narrow's 225px card exactly.
|
||||
• wide engages ~10% past a 4-col grid of 288px cards
|
||||
(4·288 + 3·18 + 2·22.5 = 1251px → ×1.10 ≈ 1376px = 86rem), then fills
|
||||
the full browser width with as many ~288px cards as fit.
|
||||
Reading pages omit `wide`, so they stay at narrow (42rem) at every size. */
|
||||
@media (min-width: 69rem) { body.wide { --max: 55.5rem; } } /* regular + wide chrome */
|
||||
* { box-sizing: border-box; }
|
||||
html, body {
|
||||
margin: 0;
|
||||
@@ -171,10 +198,19 @@ const year = new Date().getFullYear();
|
||||
line-height: 1.55;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
/* Clip at the viewport (not body — the wide grid breaks out past body) so a
|
||||
card mid-glide from a wider layout never flashes a horizontal scrollbar. */
|
||||
html { overflow-x: clip; }
|
||||
body {
|
||||
max-width: var(--max);
|
||||
margin: 0 auto;
|
||||
padding: 1.5rem 1.25rem 2rem;
|
||||
/* Glide between width tiers instead of snapping — the hero and contained
|
||||
cards ride inside body, so they gently resize along with the column. */
|
||||
transition: max-width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
body { transition: none; }
|
||||
}
|
||||
a { color: var(--accent); text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
|
||||
Reference in New Issue
Block a user