{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreierrjgyxmml73d73pozjccbg3iiqniywxdworrzub5bh5wollapdi",
"uri": "at://did:plc:vrrdgcidwpvn4omvn7uuufoo/app.bsky.feed.post/3l7nwkdtf6p2p"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreihqh53ww57dkdp6h6luskpfc2gmokmrfl6ezwydrseux2htzqpczy"
},
"mimeType": "image/png",
"size": 31140
},
"description": "A CSS reset I've been using for new projects.",
"path": "/words/my-modern-css-reset/",
"publishedAt": "2024-10-29T00:00:00Z",
"site": "at://did:plc:vrrdgcidwpvn4omvn7uuufoo/site.standard.publication/3mmyfl3pxzi2a",
"tags": [
"css"
],
"textContent": "How many of us start every web project by copy-and-pasting Eric Meyer's famous CSS reset?\n\nI did that for a long time without even really reading it.\nI knew that it smoothed over some of the inconsistencies between various browsers, and that was enough for me.\n\nThen, a few years ago, I read a blog post by Josh W Comeau called My Custom CSS Reset.\nI realized that there's no deep magic; everything a reset does is just normal CSS that you can read and understand.\n\nMy CSS reset is loosely based on Josh's, but it takes a slightly more opinionated stance and applies some light default styling that I end up adding to almost every project anyway.\nCSS has also rapidly improved over the past few years, and I've tried to take advantage of that by including a few modern features like cascade layers, logical properties, nicer text wrapping and nesting.\n\nI suppose it kind of blurs the line between \"CSS reset\" and \"classless CSS framework\".\nMy goal isn't really to adhere to a strict definition of either one; I've just found this set of styles to be a good starting point for most websites I build.\n\nIf you haven't read Josh's post, go do that now.\nHe explains his reset in detail, with a bunch of great interactive examples.\nI'm going to talk mostly about the points at which my reset differs from his.\n\nHere it is:\n\nThe Reset\n\nFirst, everything is in a cascade layer called reset:\n\nThis sets the precedence of the reset.\nBriefly: normal styles (i.e. not !important) outside of layers have precedence over normal styles in layers.\nThe order of precedence for layers is determined by the order in which they're declared, with later layers overriding earlier ones.\nGenerally, resets are placed first in a stylesheet, which means that any other styles will be able to easily override these.\n\nNote that the layer can also be declared at import time rather than as a block:\n\nNext, removing the margins and padding:\n\nJosh only removes the margins; I remove the padding as well.\nThere aren't many elements that I use without overriding the built-in padding — and as we'll see later, I end up adding it back in some cases.\n\nNext, media elements:\n\nLike Josh, I set them to display: block to avoid that weird extra vertical space.\n\nInstead of max-width, though, I use max-inline-size: a logical property which controls layout based on the direction of the text.\nIt sets the maximum size along the inline dimension.\nFor horizontal languages like English, that's width, meaning it functions exactly the same as max-width — but for vertical writing modes (such as in some Asian languages) it instead functions as max-height.\n\nNext, form controls:\n\nThis is another tweak to Josh's styles.\nWhile font: inherit makes these elements inherit the font-family, font-size, etc, from their parent, it doesn't touch the color (which defaults to black) or the letter or word spacing.\nSetting letter-spacing and word-spacing to inherit makes them inherit the corresponding properties from their parent, while setting color to currentColor makes them also take on their parent's text color.\n\nOne notable place where Josh's reset diverges from Eric Meyer's is in resetting list styles:\n\nI find that I remove the list styles more often than not, so it's included in the reset.\nAgain, we'll later see the list styles reapplied in some cases.\n\nThe Framework\n\nHere's where this reset crosses over into \"classless CSS framework\".\nI'm going to start adding back styles to the page, using CSS nesting to wrap everything in this selector:\n\nAll following selectors are nested inside this block, which selects every element without a class.\nThe idea is that if I add a class to an element, it's probably because I want to customize that element specifically, rather than using the base styles.\nThe :not([class]) selector lets me add that base set of styles to elements I often use without classes (such as <p> or <li>) without forcing myself to \"zero out\" those styles if those same elements make sense semantically in a different context.\n\nFirst up, the headings:\n\nThe & sigil combines each nested selector with its ancestors.\nThis is equivalent to selecting :not([class]):where(h1, h2 /* ... */) (and so on) — essentially, any heading without a classname., .\n\nHere are the properties, one by one:\n\nmargin-block: 0.75em is another logical property.\nIt sets the margins along the block dimension, which for horizontal languages means top and bottom.\nIt's defined in em, so it scales based on whatever font size the element ends up using.\n\nmargin-trim: block removes the block dimension margins of elements that touch the edges of their container.\nIt's a cleaner alternative to zeroing out the top and bottom margins of the first and last children.\n\nline-height: 1.25 sets the leading a little tighter than the rest of the text.\n\ntext-wrap: balance is a new value for the text-wrap property that tries to balance the number of characters on each line.\n\nletter-spacing: -0.05ch makes the tracking slightly tighter. It's defined in ch, which scales based on the width of the glyph \"0\" in the element's font family and size.\n\nNext, paragraphs and lists:\n\nSimilar to headings, I set the margin along the block dimension in ems to bring back some vertical spacing proportional to the font size.\nSince most of these elements will be adjacent to others of the same type, 1em might seem like a lot — but margin collapse will prevent the margins from combining.\n\nNext, I bring back the list styles I reset earlier:\n\nLet's tackle <ol> and <ul> first:\n\npadding-inline-start: 1.5em adds padding at the beginning of the inline dimension, which for left-to-right langauges means left. This indents each list item.\n\nlist-style: revert adds back the default list marker.\n\nFinally, for <li> I add back some margin along the block axis for vertical rhythm.\n\nThat's it!\nAs with Josh's reset (and Eric's before his), feel free to use or modify this for your own projects; consider it public domain.\nIf there's anything you think should be added, removed or changed, or any tips I've missed or new features that might improve this, I'd love to hear about it.\n\nChangelog\n\nOctober 2024: Immediately after publishing, Dan Burzo replied to me with his own CSS reset.\nI noticed that he added letter-spacing: inherit to his form elements, to which Dan credited an article by Adrian Roselli.\nBased on that article, I added both letter-spacing: inherit and word-spacing: inherit.\n\nOctober 2024: Based on Mayank's CSS reset, I replaced max-width on media elements with max-inline-size.\n\nJanuary 2026: A few big changes:\n\nGrouped multiple selectors with :where rather than just listing them out (mostly because it keeps CSS formatters like Prettier from placing them each on their own line).\n\nAdded interpolate-size: allow-keywords to :root to allow any element on the page to animate to intrinsic sizing keywords.\n\nAdded margin-trim: block to a few elements.",
"title": "My Modern CSS Reset"
}