CSS: Unavoidable Bad Parts

48 points by LesleyLai


LesleyLai

Nitpicking: the definition of "responsive design" is to "make web pages render well on a variety of devices and window or screen sizes from minimum to maximum display size to ensure usability and satisfaction." Media/container queries are just one tool for implementing that, and responsive design is more of a mindset than "use media query for everything". So maybe the "bad" is just "overuse media queries/break points when you can implement responsive design without it."

chrismorgan

Bad: Browser defaults

There’s some misleading stuff in this section. Reset and normalisation stylesheets are very different in purpose and behaviour, doing three different things, and it conflates them.

Resets are very little to do with browsers differing from one another: they’re more about elements differing from one another. They give you a tabula rasa, where ol no longer has padding-inline-start, where button no longer has any appearance; and let you craft your styles from scratch rather than from user agent stylesheet.

Normalisations instead try to work with the user agent stylesheet. They’re generally made up of two parts: normalising differences between browsers, and changing some styles to things they considered more sensible (which I suppose could be considered a form of normalisation—between expectations and reality).

But the fact is there aren’t many things left where browsers have meaningfully different defaults. General web content authors can probably completely ignore it, which is great! Chromium has the wrong table border-color (WebKit fixed theirs 1½ years ago)… there are various differences in margins/padding/sizing on some form elements (which I think people are too eager to vitiate)… anything involving appearance is deliberately about potential variations between browsers… and I think WebKit may still not have got its act together around styling <summary> by ::marker. Honestly, that’s about it, though if you want a full two years of perfection you’ll need a couple more.


Bad: box-sizing

From my collection of dozens of sets of very rough notes that I might turn into proper posts some day, “Against box-sizing: border-box” (which is pretty high on the priority list to publish):

A contrarian view against the popular practice of *, *::before, *::after { box-sizing: border-box } or :root { box-sizing: border-box } *, :before, :after { box-sizing: inherit } or similar.

border-box is about layout, content-box about content. You should aim to design things around content, not layout: leave layout to the parent.

border-box is incompatible with ratios: you need content-box there.

border-box is only actually useful for things like making body fill the viewport.

Perhaps the biggest remaining case for border-box is width: 100% when you have padding; width: stretch should help there. (2025-10-20: Chromium family only, but -moz-available and -webkit-fill-available fill the remaining major browsers.)

See also what I wrote in https://news.ycombinator.com/item?id=29357636.

This thing is listed in https://wiki.csswg.org/ideas/mistakes: I disagree that it was a mistake.

Note also what’s said later about responsive design; HTML’s “inherent responsiveness” is akin to content-box rather than border-box. Think about it.


Doubleplusungood: font-size

I dislike his take on font-size-adjust: it replaces one ubiquitous, well-understood and fairly-consistently-handleable problem with a less-well-traversed problem which will yield results slightly less bad for some people but slightly worse for others. The underlying problem is fundamentally unsolvable; and, being minor, I think it’s best to leave things at the defaults. When you use font-size-adjust, you’re making unsound and unwarranted assumptions about aspect ratios and other metrics of the user’s fonts.

This is my present opinion, but I plan to investigate it exhaustively at some point, maybe still this year. I don’t rule out changing my opinion, but I’m not optimistic about it, particularly because it messes with using ems as “px, but scalable” so that e.g. 0.25rem no longer means “probably 4px but if the browser em isn’t 16px it will be proportional to that” but rather “now even the font family gets in on the act and it could easily be 3.4567px or 4.5678px even on an otherwise ‘normal’ configuration”.


Bad: line-height

set in the same font

This is… hmm. I’d say “mostly false”, but more generally “it’s complicated”. It’s actually just about the font-sizes involved, but switching languages or using font-family: monospace can change the font-size unexpectedly. (Most notably, font-family: monospace without an absolute font-size will probably shrink the font-size by 18.75%.) Well, vertical-align too, particularly if you have inline blocks, and <sup> and <sub> become fun, and font metrics can get involved there, so… maybe I’ll drop the “mostly false” and just stick with “it’s complicated”. But the wording “set in the same font” is not strictly correct.


Chaotic Good: margin collapsing

Oh, it’s a lot worse than described. Julia Evans’ owl selector assumes only a single level of meaningful nesting, which just isn’t real. aside, ol, div, plenty more where it doesn’t cut it. Margin collapse is actually pretty pragmatic in general. But also part of flow layout. Honestly it makes for a fairly compelling case against using flex or grid for general content. Compelling reasons for those layouts definitely exist, but having to mess around with gap or margins all over the place tends to be a bit fragile, and gets old quickly.

A useful thing people may not know of: display: flow-root lets you contain children’s margins, preventing them from collapsing with the parent’s margins. Historically this involved one of a few dodgy hacks.


Bad: responsive design

Like a sibling commenter, I don’t agree with this overarching framing; but the concept it describes is sound. People use media queries for a lot of stuff that doesn’t need it, and it’s good to work with the browser rather than fight against it. There’s still a place for breakpoints, but if it’s possible to express the layout variations in terms of the content, that’s almost always preferable.

One adjacent trick I’ve made a lot of use of in the past few years is clamped linear interpolation using viewport units. Using my own syntax (disappointingly incompatible with @function; the at will need to become ,), and then showing an expansion:

margin-inline: --vw-lerp(1rem at 20rem, 2.5rem at 60rem);
margin-inline: clamp(1rem,1rem + ((2.5 - 1)/(60 - 20)*(100vw - 20rem)),2.5rem);

Last year I finally implemented this as a LightningCSS visitor; I’ve found it very nice.

“The value should be 1rem when the viewport is 20rem wide (typically 320px) or less; then interpolate linearly up to 2.5rem by a viewport width of 60rem (typically 960px) and stop there.”

Feels very nice. No harsh breakpoints, just smooth interpolation, and user-font-size-aware at that.