My Custom CSS Reset
joshwcomeau.com
joshwcomeau.com
A reset.css is supposed to create a common truth across different browsers. However, this doesn't concern so much with different browser default settings but more with developer preference for specific behaviors, like e.g. the boxing model (which is the often being done in a base.css/scss in addition to a reset.css).
That is not bad, just the wrong term being used. That being said, I like those settings :-)
> A pedantic note
> Historically, the main goal of a CSS reset has been to ensure consistency between browsers, and to undo all default styles, creating a blank slate. My CSS reset doesn't really do either of these things.
> These days, browsers don't have massive discrepancies when it comes to layout or spacing. By and large, browsers implement the CSS specification faithfully, and things behave as you'd expect. So it isn't as necessary anymore.
> I also don't believe it's necessary to strip away all of the browser defaults. I probably do want <em> tags to set font-style: italic, for example! I can always make different design decisions in the individual project styles, but I see no point in stripping away common-sense defaults.
> My CSS reset may not fit the classical definition of a “CSS reset”, but I'm taking that creative liberty.
I cannot fathom why the sibling has been killed to death, they are objectively correct.
Here's a great interview with the author on CSS Tricks that explains some of the design choices in depth (this is where I first came across it): https://css-tricks.com/an-interview-with-elad-shechter-on-th...
TL;DR: This rule does most of the heavy lifting and is the most novel aspect of this approach:
/\* Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property */
*:where(:not(iframe, canvas, img, svg, video):not(svg \*)) {
all: unset;
display: revert;
}
It practically wipes out all styling from user agents across the board, so you will never again need to exhaustively override every undesirable user agent style to get an element to look exactly the way you want. The styles you've placed on an element explicitly become (for the most part) the only things that will contribute to its appearance.I've been prototyping with it at https://app.reflame.dev/ and it honestly feels like a breath of fresh air in terms of productivity.
One thing I've learned to watch out for when using it, is that it also happens to wipe out the default focus state styles of interactive elements like button, anchor, etc (the blue outline in Chrome). This is the reset working as intended, but it's also a show-stopping accessibility issue if not properly addressed in userland by adding some form of visual focus indicator back in. I have a feeling we might discover more gotcha's like this as time goes on, but so far this is the only one I've noticed, and as a result I've been very happy with the tradeoff.
Also ‘* > selector’ used to be much slower
-webkit-font-smoothing: antialiased
Looks _horrible_ on non-retina (read: most external) monitors with macOS.
Browsers have sane defaults for every OS! Please retain them rather than making me install TamperMonkey just to read your blog.> Apple disabled subpixel antialiasing across the operating system
Right, so what is he disabling exactly?
> Chrome and Safari still use subpixel antialiasing by default
Wrong. They do not. Zoom in yourself. There are no colored pixels.
That CSS line basically acts as a `font-weight: -=100` across the document. That's all it does, and that does not belong to a CSS reset. You might as well set the rest of the `font` properties and call it a regular stylesheet.
If you’re using one now, yeah it’s probably a good idea to understand what it’s actually doing, rule by rule.
I pointed this out to them all when I first joined, and they said, "But CSS resets are good ideas."
So yes - please take the time to understand what your CSS does, especially when working with tags that format text, as it can have subtle (and not so subtle) impacts on data created in a UI with unwise CSS reset choices.
Certainly there used to be a couple of major exceptions to my feeling that content-box is a better way of thinking, but this is the main one. Now I can only think of one significant exception: that `html, body { height: 100% }` needs border-box on body if you introduce padding or don’t zero margin, and that if you have an element inside the body that constrains the whole page’s width with max-width and also has margin or padding, same situation.
—⁂—
> The WCAG criteria states that line-height should be at least 1.5.
This is being completely misread. The criterion says that no loss of content or functionality must occur if the user overrides line-height and sets it to at least 1.5. It doesn’t say you should be setting it to at least 1.5—or else it would also say you should be setting letter-spacing to at least 0.12em, which would be awful.
—⁂—
On `-webkit-font-smoothing: antialiased`:
Neither screenshot exhibits subpixel antialiasing. I’m guessing (as a non-user of macOS) based on the appearance that `-webkit-font-smoothing: antialiased` might actually be disabling that thing that macOS misnames “font smoothing” which is actually glyph dilation (about which I have written here on HN before). If it’s doing that, then hey, that could actually be useful for adjusting font grades.
> MacOS is the only operating system to use subpixel-antialiasing, and so this rule has no effect on Windows, Linux, or mobile devices.
This is not true: on Windows, ClearType (enabled by default, I think? but certainly not always) does subpixel antialiasing, and you can definitely choose to go with subpixel antialiasing under Linux. It’s just that those platforms don’t provide a CSS knob to twiddle, perhaps because they saw how much it was abused on macOS.
—⁂—
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
Why apply it to paragraphs and headings alone? Would it not be better to just apply it to the root element? Let it cascade, it’s an inherited property. That way also you don’t get anomalous behaviour when you write lists without wrapping each item’s contents in <p>.I think it's absurd that I can set a div to a specific width (100px, 200px, whatever) and the padding or border will make the div larger than that width.
It makes it so hard to think about designing a page when you have to continuously add together padding, margin, and border with the width to get the actual width.
You're right about flexbox and grid solving most of these issues -- and responsive design has pretty much done away with using exact pixel widths for anything, but I still run into some cases (especially around creating grid layouts that automatically reflow) where CSS columns and floats are the best approach (not often, but it still happens...) and then you need to rely on the width being the actual width, you know?
It’s about the difference between layout and content concerns.
Margin and padding should generally be layout concerns.
Explicitly-set width and height should generally be content concerns. This means it should exclude margin and padding, so content-box is the most appropriate model.
Before flexbox came along, it was necessary to use width and height for layout concerns quite extensively, which is why people started recommending border-box. But now, the root elements are pretty much the only places that may (or should) use width and height for layout concerns. So I say specify border-box for them if you need, but leave it at content-box everywhere else.
Just like gap (flex/grid/column) isn’t part of width or height—it’s a layout rather than content concern.
I’m saying that you’re thinking the wrong way: don’t try to squeeze your content into the layout, but define your content first of all and let the layout exist around it.
That’s not what’s happening.
Imagine you have a physical box. The contents are 10cm wide. There is padding of 2cm on each side. And the space around the box is 3cm. How wide is the box? It’s not 10cm; it’s 14cm.
When you say:
> I can set a div to a specific width
…you aren’t setting the width of the div, you are setting the width of its contents. That’s why the property value is box-sizing: content-box – because you are setting the width of the content.
If you’re setting the width of the content when you mean to set the width of the box, then no wonder it’s not doing what you want.
How big is the box? I think most would measure from border to border. I think it’s easier to think of CSS in that way.
Again, you’re not understanding what’s happening here. You’re right – the measurement of the box is from border to border. That’s completely correct! But the width you are setting is the width of the content, not the width of the box. Pointing at the width of the box and saying that it’s not the width you set is looking at it completely wrong. You didn’t set the width of the box. You set the width of the content.
Take bicycle tyres. The most popular naming scheme in Australia approximates the external diameter in inches, which is objectively problematic. The technically vastly superior naming scheme endorsed by ISO measures the rim diameter, which is the far more important measurement for determining compatibility, in millimetres. As it stands, each inch measurement corresponds to at least two incompatible sizes, depending on the tyre’s width: for example, 16″ tyres are normally 305mm (e.g. 16×2¼″), but there’s also the rarer 349mm (e.g. 16×1⅜″) commonly used in recumbents.
The relevant section from Every Layout is a great explainer: https://every-layout.dev/rudiments/boxes/
I prefer: https://necolas.github.io/normalize.css/
To me, having reset styles feels like using unwanted globals in a programming language. Styles on html and body are ok though, as there's only 1 of them on a page.
> This doesn't work because in Flow layout... the width of an element is calculated based on its parent, but the height of an element is calculated based on its children.
Well, more specifically, `height: 100%` isn't expanding as it's already the maximum height of its parent, right? All he's done is increase the parent height.