The Coyier CSS Starter ![rw-book-cover](https://api.urlbox.io/v1/ln9ptArKXobLRpDQ/52506fa66318ab48987b7462dc2a9a9fbc7334a30f2f67ab534d42daa0c38a77/png?url=https://piccalil.li/og/the-coyier-css-starter/&width=1024&height=526&retina=true) ## Metadata - Author: [[Chris Coyier]] - Full Title: The Coyier CSS Starter - Category: #articles - Document Note: ```markdown --- tags: [CSS, Frontend, Best-Practices] author: [Chris Coyier] source: [Piccalilli] reference: [https://piccalil.li/links/the-coyier-css-starter/] date created: 2025-10-01 00:00 --- # 🏷️ Title: The Coyier CSS starter ## 🧭 Table of Contents - [📝 Summary](#-summary) - [📖 Main Content](#-main-content) - [🗒️ Notes](#️-notes) - [📚 References](#-references) - [🗣️ Paraphrase](#️-paraphrase) - [📰 Newsletter](#-newsletter) - [✅ Action Items](#-action-items) - [🧪 Hypotheses](#-hypotheses) - [📊 Methodology](#-methodology) - [❓ Questions](#-questions) - [🔮 Future Research](#-future-research) - [💡 Implications](#-implications) - [🧠 Learning Styles Assessment](#-learning-styles-assessment) - [📊 Accessibility Assessment](#-accessibility-assessment) - [🌍 DEIB Assessment](#-deib-assessment) - [✅ Logical Validity](#-logical-validity) - [🛡️ DARVO Analysis](#-darvo-analysis) - [🎯 Conclusion](#-conclusion) ### 🔗 References - Include links cited in or relevant to the article. ## 📝 Summary - The piece evaluates a CSS “starter,” not a reset. - It supports global styles first, with careful specificity. - Stakeholders include frontend engineers, designers, and educators. - Risks include global styles interfering with component needs. - Bottom line: adopt, adapt, and align with team context. ## 📖 Main Content - The author favors sensible global CSS and selective adoption. - They caution on using @layer without team-wide understanding. - They endorse clamped root font sizes and fluid typography. - They dislike global body padding for production risk. - They praise balanced headings and list styling with ch units. - They flag font-dependent letter-spacing and font-weight risks. - Form defaults should fill inline space; layout handles splits. - Textarea min height could be more generous; test in context. - Tables get sensible defaults; prefer em/rem over percentages. - They reject default view transitions but like smooth scrolling. ### 🗒️ Notes - “Starter, not reset” aligns with global-styles-first teaching. - Use @layer cautiously; it changes cascade and specificity. - Prefer separate font properties over font shorthand for clarity. - Avoid global body padding in production; harms full-bleed layouts. - Headings: tight line-height, zero top margin, text-wrap: balance. - Beware global letter-spacing/weight; font-family matters. - Lists: inside markers; nested indent via ch; check dl semantics. - Forms: font: inherit; inputs 100% inline-size except buttons. - Buttons invert Canvas/CanvasText for system color compatibility. - Textarea: field-sizing: content; set reasonable min-block-size. - Tables: caption bottom; collapsed borders; consistent unit system. - Motion: avoid default view transitions; smooth scroll is fine. - Guidance: pick parts, build team-fit starter, iterate over time. ## 📚 References - The Coyier CSS Starter commentary (https://piccalil.li/links/the-coyier-css-starter/) - CSS Cascade Layers (@layer) overview (https://developer.mozilla.org/en-US/docs/Web/CSS/@layer) - text-wrap: balance proposal and support (https://developer.mozilla.org/en-US/docs/Web/CSS/text-wrap) - CSS logical properties (https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties) - prefers-reduced-motion media feature (https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion) - View Transitions API (https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API) ## 🗣️ Paraphrase - The starter promotes robust defaults while avoiding heavy resets. - Teams should adopt only what fits their workflows and typography. ## 📰 Newsletter - This week: a practical take on a CSS starter, not a reset. - Highlights: cautious @layer use, fluid type, and safer forms. - WordPress themers: avoid global body padding to protect full-bleed. - Prefer em/rem in tables for contextual sizing. - Try text-wrap: balance for headings in block themes. - Read the analysis and compare with your theme.json settings. ## ✅ Action Items - DevRel - Publish a “Starter vs Reset” explainer with demos. - Host office hours on cascade layers and theme.json interplay. - Developer advocacy: plans, talks, demos, and measurable outcomes. - Demo clamped root font size and fluid type in WP themes. - Measure CLS/legibility impact across default themes. - Education: workshops, curricula, office hours, mentorship programs. - Create labs on @layer scopes and specificity budgeting. - Developer experience: docs, SDKs, examples, templates, quickstarts. - Provide WP block theme starter with optional CSS modules. - Developer marketing: campaigns, content, funnels, and attribution. - Run a campaign on global styles pitfalls and fixes. - Community management: moderation, code of conduct ops, surveys. - Survey themers about default global styles pain points. - Internal/external/cross-project: align goals, SLAs, and feedback loops. - Align CSS starter guidance across design systems and WP docs. - OSPO - Policy & Governance: contribution policies, decision rights, charters. - Define guidelines for adopting CSS APIs in shared starters. - License Compliance: policies, scanning, review, and training cadence. - Ensure starters include license headers and third-party notices. - Security Management: vuln intake, embargo policy, signing, attestations. - Version and sign distributed starter packages. - Software Inventory: SBOM strategy, ownership, freshness SLOs. - Track CSS starter dependencies and browser-API assumptions. - Developer Support: training, tooling, legal guardrails, consultation hours. - Offer consultations on cascade layers in product code. - Community Engagement: upstream funding, MoUs, operator agreements. - Fund docs for View Transitions and motion-reduction patterns. - Strategic Alignment: KPIs, OKRs, executive reporting, initiative roadmaps. - KPI: adoption rate of accessible default patterns. - Community - Maintainers: roadmap clinics, governance templates, release hygiene. - Establish versioned starter CSS with change logs. - Contributors: onboarding paths, “first issue” rotations, pairing sessions. - Tag issues: unit consistency, typography, motion preferences. - Sponsors: transparent budgets, milestones, deliverables, impact reports. - Sponsor tests for accessibility defaults in starters. - Ecosystem: cross-project incident drills and coordinated disclosures. - Drill for breaking changes in cascade or unit systems. - WordPress - Core: priorities, issue triage, performance budgets, release criteria. - Evaluate text-wrap: balance defaults in block editor. - Core Performance: profiling plans, metrics dashboards, perf bounties. - Benchmark fluid type impact on layout stability. - Core AI: responsible AI guardrails, evaluation sets, pilot projects. - Generate starter diffs with AI but gate with lint rules. - Core Program: coordination rituals, cross-team dependencies, retrospectives. - Sync design tools with theme.json and CSS starter updates. - Mobile: app backlog, telemetry review, offline UX improvements. - Respect prefers-reduced-motion in mobile webviews. - Playground: browser labs, reproducible bugs, education modules. - Build labs on @layer and logical properties. - Community: meetup kits, WordCamp playbooks, speaker mentorship. - Run “CSS Starters that Don’t Bite” talks. - Training: lesson plans, learning paths, certification pilots. - Add unit-selection modules (em/rem/ch/px). - Marketing: campaigns, narratives, social editorial calendars. - Promote accessible motion defaults as brand value. - Support: response SLAs, knowledge base gaps, escalation paths. - KB: fix global body padding affecting full-bleed blocks. - Design: UX audits, design tokens, research backlogs. - Tokenize typography clamps and spacing scales. - Documentation: DevHub/HelpHub gaps, examples-first patterns, style guide. - Document safe heading defaults and list semantics. - Photos: content drives, moderation guidelines, taxonomy hygiene. - N/A. - TV: submission guides, caption quality, content indexing. - N/A. - Polyglot - Summary: I'm somewhat a fan of resets and sensible global CSS styles, so I thought it would be fun to run through Chris' recent starter and pick out bits I like and don't like. - URL: https://piccalil.li/links/the-coyier-css-starter/ I’m somewhat a fan of resets and sensible global CSS styles, so I thought it would be fun to run through Chris’ recent starter and pick out bits I like and don’t like. One thing to preface here for everyone — and I think this is really important; **everyone** has their own preferences and ways to do stuff that **works for them** and we should celebrate that. Chris’, as he describes himself, is not a reset, but a starter. That aligns quite nicely with the global styles first approach I teach people. Those who’ve taken [Complete CSS](https://piccalil.li/complete-css/?utm_medium=author-promo) will really recognise the value in doing as much up high as possible so already I’m really on board with what Chris is doing here. Something I’m always keen to watch out for, with that in mind, is stuff *getting in the way* of the highly customised styles we apply in our day-to-day work, but on the flip side I’ve been keenly looking for stuff which is set and forget. That’s the most value I personally get from my [“modern reset”](https://piccalil.li/blog/a-more-modern-css-reset/), anyway. Let’s get stuck in. I’ll be honest, I wouldn’t use `@layer` here. I don’t think it’s *wrong*, but it’s more I (and we at the Studio/Piccalilli) haven’t really found a legitimate need for `@layer` in *our* work. As Chris says, this starter isn’t to be used verbatim, but if you’re planning using it like that, make sure [you understand how `@layer` works](https://css-tricks.com/css-cascade-layers/) to avoid future foot-guns. This is the sort of thing I was referring to at the start of this run-through with “stuff getting in the way”. For example, the [“modern reset”](https://piccalil.li/blog/a-more-modern-css-reset/) continues to evolve internally because elements get in the way in various different types of projects for us. We’ve actually opted to use `:where()` in places to knock down some specificity, especially where we’re using attribute selectors in combination with element selectors. But that works for us and `@layer` works for Chris. That’s *fine*. So yeh, use `@layer` with caution *and* knowledge (in the whole team) would be my advice. I’m all in with the clamped root font size. In fact, by setting this and have a global fluid typography system right off the bat. Nice. One thing I don’t like here though is the `font` shorthand setting size, line height and font family. I personally prefer separate CSS properties for this sort of thing, for readability and understandability purposes. ``` body { margin: 0; padding: 2rem; @media (width < 500px) { padding: 1rem; } } ``` I’ll be honest, I’m not feeling this one. I put global padding on the `body` for demos etc. but I don’t think I’d be doing that for production work. There’s just too much risk of again, this stuff *getting in the way*, especially if you have full bleed elements. ``` html { word-break: break-word; } pre { white-space: pre-wrap; } ``` I love, love, *love* these and will be stealing them. ``` h1, h2 { font-weight: 900; letter-spacing: -0.02rem; } h1, h2, h3 { line-height: 1.1; } h1, h2, h3, h4, h5, h6 /* FUTURE :heading */ { text-wrap: balance; margin-block-start: 0; } ``` Be careful setting font weight and letter spacing globally as both will be very font family specific. For example, Inter will be treated very differently to Georgia in those terms. A tighter line height, zeroed top margin and balanced text wrapping are very useful though. Just be careful setting line height too tight if your font has large ascenders and descenders though or you’ll get overlaps and readability problems. ``` ul, ol, dl { margin: 0; padding: 0; list-style: inside; ul, ol, dl { padding-inline-start: 2ch; } } ``` I quite like the use of the `ch` unit here. One thing to watch out for is `ul` and `ol` are not permitted *direct* children for `dl`, but you *might* have them as child elements of a `dd` element, for example. Just know your lists are going to be indented by this style in that scenario. The nesting probably doesn’t surface that for you, when scanning the code. I won’t touch on the nesting in this starter, other than [what I’ve written about before](https://piccalil.li/blog/css-nesting-use-with-caution/). ``` input, select, textarea, button { font: inherit; /* FUTURE: apperance: base; */ } label { display: block; } input:not( :where( [type="submit"], [type="checkbox"], [type="radio"], [type="button"], [type="reset"] ) ) { inline-size: 100%; } button, input:where( [type="submit"], [type="reset"], [type="button"] ) { background: CanvasText; color: Canvas; border: 1px solid transparent; } textarea { field-sizing: content; min-block-size: 5lh; inline-size: 100%; max-inline-size: 100%; } ``` Some very useful styles in here! I agree with Chris on filling the inline space with form fields too. If you want to do a split layout for forms, the parent layout should be doing that work for you, rather than the fields themself. Essentially, [the C in CUBE CSS](https://piccalil.li/blog/cube-css/#composition) applies here. One tweak I’d make though is a more generous min height (`min-block-size`) on the `textarea`. I think `5lh` is a little stingy, but `field-sizing: content` will allow the `textarea` to grow with the input, so maybe not. See how it feels in your context would be my advice. ``` table { caption-side: bottom; border-collapse: collapse; td { font-size: 90%; } td, th { word-break: normal; border: 1px solid gray; padding: 0.5rem; } } [role="region"][aria-labelledby][tabindex] { overflow: auto; } caption { font-size: 90%; } ``` Often forgotten tables get some nice defaults here. I’m not a fan of percentage font sizes though, purely on a consistency basis. The root element (`html`) is nice and clamped so `rem` units would be hella handy here, but I’d probably opt for `em` units to achieve what Chris is gunning for here: relative sizing based on the table’s immediate context to get that nice visual balance. I’m just picking him up on an inconsistency of the application of units here, as he’s using `rem`/`em` everywhere else. Makes sense to do the same for tables as I see it. Yeh I’m boring at parties. ``` @media (prefers-reduced-motion: no-preference) { @view-transition { navigation: auto; } html { interpolate-size: allow-keywords; &:focus-within { scroll-behavior: smooth; } } } ``` View transitions on every page by default? Not for me Chris, sorry. I am a grumpy old man with that sort of thing 😅 I like the smooth scroll behaviour rule though. It pairs well with Chris’ usage of `scroll-margin` in this starter. Chris says this is opinionated and it’s exactly that. There’s a lot to really like about this starter, that’s for sure. Just like with **every** starter and reset: pick what you like and build one that works for you and your team. These things are really handy and if you turn out a lot of different projects. They save a tonne of time in the long term too, so it’s really worth investing the time in making one. You’ll learn a lot about how user agent styles work while you’re at it too. [![Mindful Design. Learn to design for real humans. Save £100 by pre-ordering. Ends September 30.](https://piccalilli.imgix.net/images/ads/md-pre-order-ad-landscape.png?auto=format&q=60&w=1500)[Mindful Design. Learn to design for real humans. Save £100 by pre-ordering. Ends September 30.](https://piccalilli.link/md-pre-order-closer)](https://piccalilli.link/md-pre-order-closer), The Coyier CSS Starter, Chris Coyier, 01k6fsq94xan5a94dbparn80p5.