Incomplete list of mistakes in the design of CSS
127 comments
·December 11, 2025anonymars
Angostura
> Related: I also love when I can't paste tabular data into Excel/etc. anymore
Except that’s exactly where tables should be used. So if you can’t, someone has really misunderstood CSS.
Use it for tables, not for layout.
wanderingstan
I’ve gotten in several arguments over the years where webdevs insisted on showing tabular data using flexbox or hardcoded div widths or worse. They insisted that html tables were never ever to be used and couldn’t be persuaded.
idbehold
If you try to render tables with millions of cells the browser does a really poor job and the performance is abysmal. The only solution when you need to render that many cells is to virtualize the table and only have the visible cells (plus some buffer) actually in the DOM at a time. That plus weird restrictions browsers put on certain table elements (looking at you thead) that prevent them from being "sticky" headers means that the developer is left with absolutely positioned divs as the only solution. Blame browser vendors for not providing a native way to present tabular data with more than a few hundred thousand rows without causing performance issues.
MrJohz
In fairness, the default `display: table` setup is often a pain to work with, so I can understand why people would opt for flexbox instead. One better option, though, might be to use `table` elements under the hood, styled with `display: grid` (and judicious use of subgrid for the intermediate elements) to get more precise control over the layout, while still using the right semantic elements underneath.
pornel
They are wrong, and didn't get the point of separating semantics and presentation.
Rendello
I agree, but it is funny to me that your Hacker News comment is itself a table. It's in the same vein as "don't freak out, but there's a spooky skeleton inside you!"
xboxnolifes
I think it was advised a bit too early, but ever since flexbox entered the scene, tables for page formatting became irrelevant.
And just in case, nobody ever said tables were dead. Tables were declared bad practice for page formatting, not for tabular data.
cluckindan
Do not use flexbox for page layout. It invites nested flexboxes, which eats your reflow performance.
Use grid instead.
easyThrowaway
Not the first time I hear of this, but I thought it was a blink-specific issue when using severely nested structures (e.g., html pages written using visual editors like Elementor or Webflow)?
throwaway77385
For quite a while, I had to keep using flexbox instead of grids, because grids killed performance, funnily enough. That seems to have been rectified with modern browsers though, funnily enough.
twsted
Useful insight: any sources?
zwnow
Flexbox is great and having nested flexboxes is also great. It makes building responsive pages a bliss. Learn it if you are having trouble with it, it is really not that difficult. Grids are much more error prone and allow for much less flexibility.
rcxdude
Even for layout, CSS took a long time to catch up with tables in some areas. Tables were not designed for layout, but there's a lot of aspects to them which are easier to grasp and work with than trying to get the same effect with early CSS.
KevinMS
They shamed everybody into the torturous use of floats for layout and then eventually, about 15 years later, added layout features back into a layout language.
lucideer
> I will never understand
I think it's fairly easy to understand if you understand what it was a backlash against. Tables today are used sensibly, for the most part, but the pre-CSS world was truly absurd in its table use.
The reaction may well have been over-the-top, but it wasn't disproportionate given the state of table usage at the time.
CSS's initial forays into layout seem bad today because people think of tables in terms of their intended use (not the now long-gone monstrosities the community actually extracted from them), but in comparison to the previous ecosystem, floats were a relative godsend.
wongarsu
Tables as a layout primitive are fine. Lots of modern layout engines are based around vstacks and hstacks, which are just single table rows and columns. Most paper forms use a 2d table layout, and newspapers arrange their articles in a 2d table layout.
There were some reasonable concerns. Using tables for both layout and literal tables removes semantic meaning, nested tables can get complicated to layout, and layout the whole page as a giant table makes it difficult to adapt to screen size. But the first could easily be solved by adding a tag that works exactly like table but is for layout, the other two are about overuse of tables in the absence of viable options. We could have easily kept table layouts for the parts where it makes sense and augmented it with something css-like for the parts where it doesn't.
RaftPeople
> There were some reasonable concerns. Using tables for both layout and literal tables removes semantic meaning
The simple solution:
<table type="layout"> (or "data")
mrdatawolf
Thanks, I was going to say the same thing. The developer cultural context, back then, really matters.
PunchyHamster
This is somehow worse than "never use goto"; because there are plenty of good uses for tables, and CSS was lacking features for forever after the clowns declared "tables bad" and the other clowns followed without thinking
erfgh
The killer argument at the time (and even now most likely) is that screen readers could not distinguish whether the table was used for layout or for data and therefore sight-impaired users would have trouble.
The argument doesn't make sense because it is not too hard for a screenreader to understand whether a table is used for layout and even if it was hard the problem would more easily be solved by just adding an attribute to the table to indicate that it is used for layout.
afavour
Tables aren’t dead, they never were… when displaying tabular data. When it comes to layout I think you might be wearing rose tinted glasses. Remember having to put a 1px image in a table cell to avoid it disappearing? Remember “best viewed at 800x600”? I’m personally not nostalgic for either.
tobr
For what it’s worth, the very page we’re on here still uses tables and spacer gifs, in 2025. (EDIT: I don’t mean to imply that this is good, just an inescapable observation in this context)
Popeyes
Probably why there are endless reworkings of the site.
erfgh
There were better solutions to those problems than the CSS debacle.
eviks
> Remember having to put a 1px image in a table cell to avoid it disappearing
Isn't this a trivial problem to solve that doesn't require introducing any new layout mechanisms?
dahcryn
at least they were specific
Today it's usually implicitly designed for iphone, designed for 1080p, or ipad, and you have to guess, strong correlation with whatever device the designer uses in his personal life.
afavour
...no? Today's sites use responsive design and adapt to pretty much any screen size.
agumonkey
sidenote: as a teen, i would regularly layout posters and presentations in excel.. the page preview dashed-border and the grid stability was such a relief compared to word
6510
On commodore 64 the screen is just a fixed size grid of characters. No one ever had issues making an ui. We pretend but flexible viewport size is not actually possible. If you are making a painting for example the size of the canvas greatly influences what can and can be done.
I made a stunning landscape photo one time that looked great only when displayed at roughly the size of a hand. If made larger undesirable details became visible (littering), when smaller important details were lost (a formation of birds over a fishing vessel).
oneeyedpigeon
> We pretend but flexible viewport size is not actually possible.
Not beyond a point, but it's still very useful to be flexible up to that. For example, I'm very grateful that a web page will reflow text rather than print everything on one line and force horizontal scrolling.
Izkata
> The display property should be called display-type.
More importantly to me, "display" has been overloaded with two meanings: Display of the element this rule applies to/how it interacts with surrounding elements (none, block, inline, inline-block) and display of the contents of this element (flex, grid).
Which is why we now also have inline-flex and inline-grid.
Edit: Apparently we can now arbitrarily combine inline/block and flex/grid as two values to "display", no idea when this happened: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/P...
nfw2
I'd like to propose for the list:
Default heading styles should not have equal top and bottom margin. Headings should be closer to the content they label than to the content they are setting their content apart from.
h1, h2, h3 should not have different styles. it's an anti-pattern that leads to broken accessibility
0xfffafaCrash
moreover h* is just broken whenever dealing with more dynamic content — it simply can’t reasonably be made to work according to accessibility recommendations — and the accessibility guidelines around never skipping a level themselves are ridiculous given the practical reality that dynamic content exists and we have only h1, h2, etc. to work with — the readers and specs are what need to adapt here, not the entire internet
there should really be one header tag and its level should be based on some nesting depth
and don’t get me started on the maintainability mess that is z-index… better we have a system to centrally maintain an ordering list than a distributed one which only works reasonably consistently if you already know everything in the whole system
webstrand
I like how z-index works, currently. And though I agree with the article, it should apply to all elements by default, I'm not sure how you'd do stacking differently in a way that'd work any better than the current situation?
You can't do away with stacking contexts, you need those to isolate content you don't control to prevent it from breaking the stacking order of content you do control.
I completely agree with you about h* tags, though. I wish html5 sectioning hadn't been killed by the browser vendors. As is there's no safe way to put headings inside custom elements. We almost had it, it was specified and everything.
nfw2
The problem with trying determine heading depth automatically is the depth is not something that can be deduced just by the structure. If headings are siblings, for example, the may be on the same level semantically or not.
One way I've dealt with this in react is combine a Heading component with ContentGroup component. Each content group needs exactly one heading, and heading can't exist without it. Content group can contain other content groups. The tag for heading can then be determined by how many content groups are in the tree above it.
This works pretty well ime, but it can be hard to get devs to use (or think about accessibility at all).
wongarsu
That's how html should have been designed from the start. HTML is originally designed as a very flat hierarchy, e.g. h1 p p p h2 p p h2 p p h3 p h2 p just following each other. When really it would make much more sense to have h{p p p h{p p} h{p p h{p}} h{p}}.
wavemode
That's sensible, but I think default styles for specific elements are not part of the CSS standard, and are instead dictated by the user-agent stylesheet of your browser.
quirino
This "headings closer to the content" suggestion is very good.
I came across it when reading Butterick's Practical Typography and it's possibly the lowest effort/clearest improvement guideline in the book.
Now I can't unsee websites that do it wrong.
IshKebab
> h1, h2, h3 should not have different styles. it's an anti-pattern that leads to broken accessibility
How does that hurt accessibility? Are you saying people use h3 in order to get its style even when they didn't mean h3?
I think the opposite could happen too - if they all have the same style then people might just use h1 everywhere which is probably just as bad. People tend not to use elements that have no obvious use, like <output> which apparently has better accessibility but does absolutely nothing else, so nobody bothers. The whole "semantic web" thing failed partly because of this.
nfw2
> Are you saying people use h3 in order to get its style
yes, and that people assume the purpose of having different tags is to control styling
IshKebab
I mean, they aren't wrong. That is part of the purpose. Of course now we try and do it via CSS but it's definitely still fine to use <b> as bold and <i> as italic, even if the semantic pedants will insist that they mean "Bring attention to" and "Idiomatic" (that name's stretched so thin you can see through it!).
savolai
This felt relieving. As in: some part of me had felt stupid for thinking some of this seems really unintuitive when using it in practice. Like z-index stuff, margins, vertical-align, border-radius, ...
Meanwhile, one of the linked pages mentioned bluegriffon, so I got curious if such editors can handle template languages such as django's.
While I don't know that yet (edit:no templates at all, what a shame), I also found this tutorial, and it was inspiring that such a pedagogical approach to online authoring still exists.
https://www.thesitewizard.com/bluegriffon/bluegriffon-2-tuto...
Edit: no seriously, why don't these editors support at least some established template language? I think dreamweaver had a concept of templates, which made using these editors make at least some sense.
Edit: oh wow dreamweaver still exists. Any of you have experience? Still good?
edent
When I occasionally venture I to standards-land, I always ask "what user research have you done on this?"
So many weird design choices in computing are because one person said "this seems right to me" without considering other viewpoints or consulting with the wider community.
Sure, you probably dont want death by committee, but a tiny cabal engaging in groupthink often produces unhelpful results.
pornel
Many of these mistakes weren't even made by any committee, but were stuff shipped in a rush by Netscape or Microsoft to win the browser wars.
There was some (academic) reaserch behind early CSS concept, but the original vision for it didn't pan out ("cascading" was meant to blend style preferences of users, browsers and page authors, but all we got is selector specificity footguns).
Netscape was planning to release their own imperative styling language, and ended up shipping a buggy CSS hackjob instead.
Once IE was dominant, Microsoft didn't think they have to listen to anybody, so for a while W3C was writing CSS specs that nobody implemented. It's hard to do user research when nothing works and 90% of CSS devs' work is fighting browser bugs.
Timwi
This is true, but my feeling is that with CSS, a lot of the weird decisions are for backwards compatibility with way back when HTML was just tag soup and browser implementations were haphazard.
mcphage
This feels like the origin of a lot of these mistakes (and more besides): they weren't based on "what is it that lots of real designers are actually trying to accomplish?". Why did it take so long to get support for pinstriping, when prior to that there were 1001 different ways to try and accomplish it, because so many people wanted it? Why did it take so long to get layout functionality that even just matched the power of what CSS was intending to replace? Or vertical alignment, or drop shadows, etc, etc, etc. I like CSS and the intentions of it, but man, it was designed from a place of having no idea what people wanted to do.
yread
I don't understand the point about comments. Why shouldn't they be allowed? What object model?
>Comments shouldn't have been allowed basically everywhere in CSS (compare to HTML, which basically only allows them where content goes), because it makes them basically unrepresentable in the object model, which in turn makes building editing directly on top of the object model impossible
recursivecaveat
Imagine you have something like `width /comment/: /comment2 /12px /comment3/,`. Now you want to load your css into some kind of structured representation, rearrange it, then spit it back out again with that comment intact. The requirement to represent such comments in your structured format so you can retain them is really obnoxious. In html you can just view comments as another node in a uniform tree.
IshKebab
> In html you can just view comments as another node in a uniform tree.
When you parse an AST with comments (or a CST), they do become "just another node in a uniform tree". Think about it - in HTML you have a tree of nodes but comments can be anywhere, which is exactly as obnoxious to deal with as a CST where comment nodes can be anywhere.
This is a terrible reason to not support comments. If it was really important, then probably you should support comments in only a couple of places, e.g. on attributes or on selectors.
But I don't think it is very important. I can't think of a single tool that loads CSS, rearranges it, and then spits it back out in a form that would benefit from comments.
matt_kantor
> in HTML you have a tree of nodes but comments can be anywhere
Maybe I'm misunderstanding, but no they can't. For example the comment here is not a comment, but part of the URL:
<a href="https://example.com<!-- comment -->">click me</a>
And HTML like this is simply broken: <div<!-- comment -->>content</div>
Maybe you meant "they can be anywhere that a Node can be in the DOM", but I think that's more or less what the CSS "mistake" is suggesting should be true about CSS (just replace "DOM" with "CSSOM").wedg_
I'm guessing they mean that comments shouldn't be allowed everywhere, not that they shouldn't be allowed at all? i.e. CSS lets you put comments in many more places than HTML, in such a way that it's hard to practically impossible to represent in an AST? At least that's how I read it
systoll
The CSS Object Model.
HTML comments are basically just a HTML tag that isn't rendered. Tools that 'compile' the HTML code into a document tree, including browsers, preserve comments as nodes without any extra effort.
CSS comments can go anywhere:
/*wow*/ .selector /*x*/ {animation /*z*/: 2s /*z*/ linear /*z*/ bounce;}
Tools that transform/parse CSS can either:
1. Strip comments before parsing, meaning anything based on the parsed version will lose the comments.
2. Dedicate a disproportionate amount of complexity to retaining the comments, and still not really have a good way to handle them through edits/transformations.yread
But if it's valid CSS it has to be representable in AST/object model? It's a comment, it can't have any child nodes, it doesn't depend on anything - pretty trivial. And if it's in the tree you can transform it with proper tools. If you are transforming CSS you have to write a proper parser and not just a bunch of regexes
EDIT: also why is it useful to have comments in the object model in the first place? To access them from js?
nialse
Round-tripping to CSS and keeping information that may be useful to the user if they would inspect the content I would presume.
A similar issue is CDATA in XML which is not retained when round-tripped. Very annoying, but in line with the spec.
DonHopkins
Same reason why JSON prohibits comments: When you parse it, there is no place to represent the comments in the JavaScript object and array tree, so they must be thrown away, therefore it's impossible to write it out with the same comments in the same places.
Same thing with white space: JSON can not round trip white space or comments the way XML or HTML can, because XML and HTML DOM represents comments and white space explicitly.
Also you can't put comments inside elements like <div <--! comment --> class="foo">. There is no way to represent a comment inside an element in XML or HTML DOM.
But CSS lets you, so you can't round trip comments in CSS.
shiomiru
The greatest mistake IMO is the way float state leaks out of blocks, as this is both extremely unintuitive and undesirable for performance reasons.[1] Floats should've been restricted to inline formatting contexts, with all in-flow blocks behaving as if they had `clear: both' set.
I also don't understand why they never specced the (much simpler) `text-align: -moz-left/-moz-right/-moz-center' which already had precedent in HTML with `<div align=left/right/center>'. It's the saddest part of the "center a div" saga, all the W3C had to do to fix it is to assign a standard keyword to a feature that everybody already implemented, but to this day it still hasn't happened.[2]
[1]: https://pcwalton.github.io/_posts/2014-02-25-revamped-parall...
[2]: After many long decades, they did finally specify block-level `justify-items'. Two problems: a) it's backwards-incompatible with text-align, b) it still doesn't work in Gecko.
3eb7988a1663
Are they taking requests? I know just enough CSS to hang myself, but one thing I can never keep straight in flexbox is "align" vs "justify". Could not have used something like "main-axis" or "cross-axis"? Intentionally had to be somewhat obtuse from how it would be used?
jdthedisciple
Yea align and justify get me everytime.
I like that in Flutter they do exactly as you suggest: they call it mainAxisAlignment and crossAxisAlignment
eviks
> That should be corrected if anyone invents a time machine. :P
Why can't this be dealt with with CSS versioning/features where you can opt into your current-color and a lot of more substantive style behavior while leaving currentColor functional?
Timwi
A lot of the behaviors should just have a toggle to turn them off. For example, there are many situations where margin collapsing is in the way and I keep wondering why there isn't simply a `margin-collapse: none`. It would also be nice to have something like `default-styles: none` that will remove all the default styling for h1/h2/etc. and em/strong/cite/etc. so I don't have to deal with browsers having differing defaults.
shiomiru
> It would also be nice to have something like `default-styles: none` so I don't have to deal with browsers having differing defaults.
This already exists:
*, ::before, ::after { all: unset }groby_b
It is extremely funny to me that the list thinks the mistake about !important was using the exclamation mark sigil, and not the concept of a single priority level.
In the words of one of my CS profs, from a few decades ago: "There are only 3 numbers - zero, one, and infinity. And 'one' is often a mistake"
semolino
This is what Cascade Layers was designed to solve:
https://developer.mozilla.org/en-US/docs/Learn_web_developme...
A lingering bit of weirdness is that all !important declarations, no matter the layer they appear on, are interpreted as being part of their own implicit layer.
dnpls
There is no need for more priority levels, because precedence is already defined by inline > #ID > .class / [attribute=""] / :pseudo-classes / elements / ::pseudo-element / universal selector (*). And the order they're written, if both have the same priority. The !important just exists to override that order.
colechristensen
As opposed to the 15 levels of priority available in Chef.
5 different types (default, force_default, normal, override, force_override)
which can be in 4 different places (attribute, node, environment, role) but not all of the types can be in all of the places
PLUS the "automatic" type, which is from somewhere else entirely
Oh and there's inheritance and merging which does not behave intuitively at all because it's not exactly inheritance.
In other words I have early career trauma from someone's extremely unwise priority implementation and am deeply suspicious of ANY priority override system which isn't just code I've written in a normal programming language.
silverwind
Why not make a opt-in "strict mode" for CSS that fixes all these issues?
reddalo
Because writing such CSS would lead to broken results on most browsers.
kjgkjhfkjf
It would be very interesting to see a post-mortem for each of the design mistakes, with links to the original design discussions and docs, and analysis of how the decision-making process went astray.
I will never understand the bizarre scene of the web's smug collective declaration that tables were dead and not to be used juxtaposed against the years it took to regain the ability to reliably center things. Assuming one agrees that we even did regain it.
Related: I also love when I can't paste tabular data into Excel/etc. anymore
For the record, I don't hate the idea of stylesheets, but...sheesh