{"id":"0m4fdakkcvr3lrt","title":"Mobile-First CSS That Scales Up Without Rewriting","slug":"mobile-first-css-that-scales","summary":"Mobile-first is write small screen rules first, enhance with min-width, not shrink desktop comps in a panic on Friday.","imageUrl":"https://briancrabtree.me/images/journal-mobile-first-css-that-scales.webp","category":"CSS","date":"2026-03-30T18:00:00.000Z","featured":false,"likes":27,"author":"Brian Crabtree","content":"<h2>Min-width mindset</h2>\n\n<p>Base styles target narrow viewports: single column, touch targets 44px, readable type without zoom. @media (min-width: 48rem) adds grid columns and nav density. I avoid max-width hacks that undo desktop rules unless fixing a specific regression.</p>\n\n<p>Designers deliver mobile comps first when they are serious. Engineering mirrors that order in CSS files.</p>\n\n<p>Logical properties margin-inline and padding-block reduce RTL bugs when sites go bilingual. Mobile-first international is cheaper than retrofit. Breakpoint constants in JavaScript duplicated from CSS is a drift hazard. I delete JS width listeners unless a chart truly needs canvas width.</p>\n\n<pre><code>.grid { display: grid; gap: 1rem; grid-template-columns: 1fr; }\n@media (min-width: 768px) {\n  .grid { grid-template-columns: repeat(2, 1fr); }\n}</code></pre>\n\n<h2>Touch and pointer coexist</h2>\n\n<p>hover styles under @media (hover: hover) so tap devices do not get sticky hovers. Focus-visible rings stay for keyboard on all sizes. Click areas span padding, not just text nodes.</p>\n\n<p>pointer: coarse media query can enlarge hit targets on touch laptops that report fine pointer incorrectly sometimes.</p>\n\n<p>Landscape phone with short height needs compact header patterns tested separately from portrait.</p>\n\n<h2>Typography and spacing tokens</h2>\n\n<p>Fluid type with clamp(min, preferred, max) on headings reduces breakpoint count. Spacing scale in custom properties: --space-2 through --space-6. Components consume tokens; breakpoints only change grid template, not every margin.</p>\n\n<p>Viewport meta width=device-width is baseline; interactive-widget=resizes-content helps Android keyboard not obscure inputs.</p>\n\n<p>Foldable devices add aspect-ratio ranges; min-width media may fire on unfolded inner screen while outer is narrow.</p>\n\n<h2>Performance on real phones</h2>\n\n<p>Mobile lab throttling exposes fat selectors and expensive filters. I drop backdrop-filter on low-end when perf budgets fail. Images use responsive srcset, not shrunk desktop assets in CSS background-image.</p>\n\n<p>Sticky headers and position fixed bottom bars reduce visible viewport; account for safe-area-inset on notched devices.</p>\n\n<p>Horizontal scroll on body from 100vw hacks still appears. I use overflow-x clip on root carefully with sticky test. Dark mode images with transparency need separate assets or borders visible on OLED black backgrounds.</p>\n\n<h2>Navigation patterns</h2>\n\n<p>Hamburger versus persistent nav is a product call. Technically I prefer details summary or checkbox hack without JS for simple menus; React nav when state is complex. Either way focus trap and escape close for modals.</p>\n\n<p>Image max-width 100 percent alone does not fix oversized intrinsic dimensions; width height attributes still required.</p>\n\n<p>Tap highlight color on iOS can be toned with -webkit-tap-highlight-color without killing affordance.</p>\n\n<h2>Testing beyond your iPhone</h2>\n\n<p>BrowserStack or physical Android mid-range device. Safari iOS quirks on 100vh and fixed positioning still appear. I test one small Android and one iPhone each release, not thirty emulators.</p>\n\n<p>Performance budget for mobile CSS file size separate from desktop when you split, rare but useful on ad-heavy pages.</p>\n\n<p>Content visibility auto on below-fold sections is an advanced optimization when CLS reserves height first.</p>\n\n<h2>Scale-up without debt</h2>\n\n<p>Desktop adds whitespace, not new components, when mobile-first was honest. If desktop needs a different DOM tree, the mobile base was wrong. Refactor early. I help teams restructure one template rather than patch five breakpoints later.</p>\n\n<p>I prototype mobile nav in HTML/CSS before React state machines to settle interaction cheaply.</p>\n\n<p>Mobile-first does not mean mobile-only QA. Desktop wide screens still need max-width on line length for readability. For a related angle I keep coming back to, see <a href=\"/journal/responsive-tables-without-scroll-hell/\">Responsive Tables Without Horizontal Scroll Hell</a>.</p>","tags":["mobile-first","css","responsive"],"views":94}