
CSS 2 Column Layout Flexbox
Published
16 hand-coded CSS two-column layout templates — flexbox 68/32 content+sidebar, CSS Grid responsive stack, fixed 240px sidebar SaaS dashboard, 50/50 marketing hero, two-column form pairs, sticky-sidebar docs, split-screen, equal-height cards, magazine article, side-by-side pricing, product cards, auto-width minmax, and legacy float + inline-block. Every demo name is the exact-match Google search query — the URL slug is the SEO win. Scoped under .tcl-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Related30 CSS Grid Layouts15 CSS Flexbox Layouts22 CSS Split Screen Layouts

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published
grid-template-columns expresses intent directly and gives you subgrid, minmax(), and named lines for free. Flexbox is the correct default when the two columns are a horizontal band that should wrap at narrow widths (marketing hero + image, zig-zag section, header brand + nav). Both approaches are 2015+ Baseline — every browser your tier-1 traffic uses supports them. Float-based layouts and the inline-block pattern are legacy — the collection ships them (Demo 11 float, Demo 16 no-flexbox-no-grid) purely as reference implementations for developers maintaining older codebases (WordPress themes pre-2018, email templates, print stylesheets). The one situation flexbox still wins outright is when you don't know the column count in advance — a chip row or logo wall — because flex-wrap handles overflow gracefully where grid-auto-flow needs an explicit column count. For a definitive answer: reach for grid-template-columns: 1fr 300px (or 2fr 1fr) 90% of the time; reach for display: flex; flex: 1 1 320px when you're building a horizontal band that must wrap; never reach for float or inline-block on new work unless the codebase is legacy.grid-template-columns: 1fr — one column, everything stacks. Then a single breakpoint at 768px (the standard tablet-portrait threshold every design system from Stripe to Vercel converges on) upgrades to two columns: @media (min-width: 768px) { grid-template-columns: 2fr 1fr }. That's it — no JavaScript, no viewport listeners, no library. Choose the breakpoint based on where your content becomes uncomfortable at 100% width: for a text article + sidebar, 768px works; for a form with First/Last name pairs, 640px is often enough; for a dashboard with 8 modules, wait until 1024px so the modules don't crush. The mobile stack order is DOM order by default — put the content BEFORE the sidebar in the HTML so mobile readers see the primary content first, then use CSS Grid grid-template-areas (or order) to swap them on desktop without changing the DOM. WCAG 2.4.3 (Focus Order) requires the visual order match the tab order on desktop, so this DOM-first approach is the a11y-correct default. Adds zero JavaScript weight, zero CLS, and passes Google's is-mobile-friendly test without any extra configuration.display: grid; grid-template-columns: 1fr 1fr; gap: 16px. Each label element occupies one grid cell — pairs like First Name / Last Name naturally sit side-by-side. Full-width fields (email, address line 1, textarea, submit button) use grid-column: 1 / -1 to span both columns in one line — no wrapper div, no colspan hack. The mobile collapse to one column is a single media query at 640px: @media (max-width: 640px) { grid-template-columns: 1fr } — every field stacks, the grid-column: 1 / -1 rules become no-ops because there's only one column. Modern CSS features layered on top: :user-invalid gives you a real-time invalid state that ONLY triggers after the user has blurred a field (unlike :invalid, which fires immediately and reads as hostile); :focus-visible gives the focused input a 3-color ring meeting WCAG 2.4.13 focus-appearance without a fixed-thickness fight; accent-color themes native checkboxes and radios to your brand hue without JavaScript. On tier-1 SaaS checkout and signup traffic (Stripe, Shopify, Vercel, Notion, Linear all use this exact pattern), CPMs run 8-25 USD; on fintech KYC + healthcare patient-intake variants, 25-50 USD.position: sticky — three lines of CSS. First, set up the two-column grid: grid-template-columns: 1fr 260px; align-items: start. The align-items: start is critical — without it, sticky doesn't work because Grid stretches children to the row height by default, and position: sticky needs the element to be shorter than its scroll container. Second, on the sidebar: position: sticky; top: 20px. The 20px is the offset from the viewport top when the sidebar pins. Third, verify the parent doesn't have overflow: hidden anywhere in the ancestor chain — that silently kills position: sticky and is the #1 debug question on Stack Overflow for this pattern. On mobile, the sidebar collapses to a full-width row above the content via the standard @media (max-width: 768px) { grid-template-columns: 1fr; .sidebar { position: static } }. Every docs site in the tier-1 dev tools cluster (Stripe Docs, Vercel Docs, Cloudflare Docs, MDN, VS Code Docs) ships this exact CSS — CPMs on dev-tools content run 8-15 USD, and the sticky sidebar is one of the two most-copied patterns from this collection (after flexbox 68/32).grid-template-columns: 240px 1fr. That's it — the left column stays exactly 240px wide (or whatever pixel value matches your sidebar navigation depth), the right column fluidly fills the remaining viewport. The reverse (fluid-left + fixed-right) is the identical pattern with the values swapped: grid-template-columns: 1fr 300px — this is the docs/blog/marketing site pattern where content is primary and the sidebar carries table-of-contents / newsletter signup / ad slots. For a truly rebrandable sidebar width, use a CSS custom property: --rail: 240px; grid-template-columns: var(--rail) 1fr — then override --rail at breakpoints (--rail: 64px collapses to icon-only, --rail: 0 hides it entirely) without touching the grid rule. Zero JavaScript, zero layout shift, works in every browser your tier-1 traffic uses. On SaaS admin dashboard content, CPMs run 8-25 USD; on fintech dashboard variants (Coinbase Pro, Robinhood, Wealthfront, Bloomberg-style trading), 15-45 USD.float: left + width: 50% + a clearfix pseudo-element on the parent. The full recipe: parent gets .wrapper::after { content: ''; display: table; clear: both } (the clearfix hack that survives 15 years of copy-paste), both columns get float: left; width: 50%; box-sizing: border-box; padding: 0 12px. That's it — the layout works in IE8+, in Outlook 2007's email renderer (which is Microsoft Word, not a browser), and in any WordPress theme built before the Gutenberg editor landed in 2018. The gotchas: equal-height columns require either display: table-cell on children + display: table on parent (Demo 09's pattern), or absolute positioning + padding-bottom faux-columns (the 2010-era CSS-Tricks trick), because floats don't stretch vertically. Column gap is achieved via padding on each column, not gap (which is grid/flex only). On mobile, floats don't auto-stack — you need an explicit @media (max-width: 640px) { .col { float: none; width: 100% } }. Ship this pattern ONLY when the constraint is genuine: an email newsletter, a WordPress classic theme, a print stylesheet, or a codebase that must support IE11 (a shrinking list — mostly Japanese enterprise banking and some US government portals). For everything else, Demo 01 (flexbox) or Demo 02 (grid) is the correct answer.grid-template-columns: 1fr 1fr; gap: 24px; align-items: stretch on the parent so both cards claim equal height regardless of feature-list length. The Pro card gets --elevated treatment — a subtle scale(1.03), an accent-color border (--brand), a box-shadow: 0 20px 40px -20px var(--brand)/0.35, and a small "Most popular" ribbon in the top-right corner via position: absolute; top: -12px; right: 24px. Baymard Institute's 2024 pricing-page study across 200+ SaaS sites found the elevated-Pro-card pattern outperforms flat 50/50 by 18% conversion on average, because the visual asymmetry primes the eye to compare the Pro card AGAINST the Basic card (making the Pro price feel earned rather than default). For three-tier pricing (Free / Pro / Enterprise), the middle-highlighted pattern is standard — but the two-tier side-by-side is what Stripe Billing, Vercel Pro, Linear Business, Notion Plus, Superhuman, Framer, Cursor Pro, Raycast Pro and every other tier-1 SaaS ships. Also: CSS subgrid (Baseline 2024) makes the feature-list rows in both cards align to the same baseline — see the subgrid demo in this pattern for the details. On SaaS pricing content, CPMs in tier-1 markets run 15-45 USD driven by direct competitors bidding on brand-comparison queries.:focus-visible outline at 2px minimum with 3:1 contrast per WCAG 2.4.13 focus-appearance (the new SC that landed October 2023); prefers-reduced-motion: reduce is honored on every transition (form ring, sidebar hover, pricing card lift); the mobile breakpoint at 768px keeps text at a comfortable reading measure (66-75 characters per line, the Bringhurst standard). Zero JavaScript in any of the 16 demos — CLS is provably zero, LCP is bound only by the browser's rendering pipeline (typically 12-40ms on a mid-tier Android), INP is 0 since there's no JS bundle at all. Framework portability: drop the HTML straight into React (rename class to className and for to htmlFor), Vue (SFC accepts as-is), Svelte or SvelteKit (accepts class and for natively), Astro (as an .astro component with the CSS in a scoped style block), Next.js App Router (as a client or server component — no use client needed for these zero-JS layouts), Remix (any route module), or Solid.js. MIT licensed. Compared to premium alternatives: Tailwind's arbitrary-value grid classes (grid-cols-[1fr_300px]) express the same rules with more bracket noise; shadcn's ResizablePanel primitive is $0 but adds ~8KB for drag-to-resize behavior these demos don't need; Framer Motion's layout-shift primitives are 60KB+ for a use case pure CSS handles.15 hand-coded CSS aspect-ratio demos for video embeds, product galleries, IAB ad slots, native dialogs, and CLS-safe placeholders: 16:9 iframe YouTube embed with click-to-load facade + up-next rail, 21:9 full-screen hero video with min-height/max-height:100svh guardrails + Ken Burns drift, 1:1 Instagram-style square grid with 2×2 feature tile, 4:3 magazine card image cover, 9:16 vertical stories rail (TikTok/Reels/Shorts pattern) with scroll-snap + segment bars, 4:5 apparel product image gallery with radio-driven state + 1:1 thumbnails, 1:1 zoom thumbnail carousel with pointer-tracked --zx/--zy magnifier, prevent-layout-shift placeholder with live PerformanceObserver CLS meter (before/after side-by-side lab), dynamic content fallback with three policies (bend/strict/auto) via :has() toggle, IAB ad banner slots (728×90 leaderboard, 300×250 medium rectangle, 300×600 half-page, 320×50 mobile) with skeletons + container-query mobile swap, responsive modal dialog sized min(92vw, 88svh×16/9, 1080px) with @starting-style animation, responsive OpenStreetMap iframe wrapper with 16:9 → 1:1 container-query narrow swap, media query orientation live HUD + resize:both container-ratio playground, object-fit logo cloud with contain/cover/fill switcher via :has(), and side-by-side padding-top hack (height:0 + padding-top:56.25%) → modern aspect-ratio migration comparison with live ratio picker. 11 truly Pure CSS + 4 with a tiny optional vanilla JS snippet (facade swap, pointer magnifier, CLS meter, native dialog). Every demo is scoped under a unique .car-NN prefix so it drops into any project without CSS collisions, ships prefers-reduced-motion guards, and is framework-agnostic (works as-is in React, Vue, Svelte, Astro, Next.js, Remix, or plain HTML).
6 production CSS bento grid layouts with 12 hand-coded designs — Apple-style product showcase, SaaS feature value-prop matrix, analytics dashboard overview, creative portfolio, e-commerce category hub, and link-in-bio social hub. Each topic ships 2 sub-variants side-by-side so visitors see both a keynote aesthetic and a paper-doc variant at once. Container queries, CSS Grid, zero dependencies, copy-paste ready.
20 hand-coded CSS blog and editorial layouts for magazine homepages, news sites, personal archives, newsletter back-issues, recipe and podcast blogs, developer tutorials, and long-form journalism. Covers a magazine homepage with hero plus editor-picks rail, a news homepage with breaking-news ticker, blog archives with sticky year separators, Substack-style issue-numbered archives, recipe card grids with prep-time badges, podcast episode lists with waveforms, long-form articles with scroll-driven reading progress, drop caps and floated pull quotes via first-letter, Medium-style 65ch centred reader layouts, dev tutorials with a sticky code panel beside prose, interview transcripts with alternating speakers, case-study pages with stat counters, video blogs with an episode rail, full-bleed photo essays, news articles with sticky related-stories sidebars, documentation pages with prev/next chapter nav, a standalone blog post card, a scroll-snap category filter bar, an inline newsletter callout that breaks out of the prose column, and a horizontal featured-post rail. 12 are pure CSS with zero JavaScript. Every layout is scoped under a .bl-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.