Incomplete List of Mistakes in the Design of CSS
wiki.csswg.org
wiki.csswg.org
Two decades ago I was overjoyed to discover that Scheme was finally going to have a useful application beyond illustrating SICP and writing koans to amuse myself, because DSSSL was on the cusp of evolving into the last document styling language anyone would ever need.
Unfortunately following an incident with a broken Lisp machine, a liquid lunch, and an unlicensed particle accelerator, I became trapped in a parallel universe where the HTML ERB anointed CSS by mistake during a drunken night out in Oslo.
The primordial concept of CSS (best revealed by H.W.Lie's thesis IMO[1]) was to create a rich and versatile and (crucially) non-Turing-complete set of structural selectors in lieu of DSSSL's recursive expressions, and to allow styles to overlay one another (the "cascade"); two design choices that only by the application of gallons of irony can explain why most web pages are composed of a bunch of nested DIV elements with hashed IDs and overloaded semantic class attributes, and everyone compiles their assets into a static file.
Drunken or not, I can't also really fathom the primordial mindset of looking at HTML (eg. SGML's already heavy attribute and element syntax infrastructure), then come up with a completely redundant syntax out of nowhere for holding the exact same thing that went into attributes yet with weaker type checks.
The result is the write-only mess that is CSS today, unusable without CSS debuggers, inaccessible to most devs and traditional graphic designers let alone laymen, yet always insufficient for innovators, seemingly perpetuated only by folks who mistake their huge effort into learning CSS with its merit (aka Stockholm syndrome).
I dunno, much as I dislike CSS and its lack of useful modularity, it's never something I'd describe as "write-only" or "unusable". The selector syntax is fairly nice and concise and the cascade of properties works as one would expect (most of the time). I doubt CSS would benefit from throwing some SGML at it, because CSS is fundamentally just a list of selector-property pairs and not a mixed-content document.
The real problem with CSS is two-fold: first, the users of CSS have turned the class= attribute of HTML into an awful ad-hoc inline styling language (with the requisite awful and nightmarish stylesheets). And second, there is a huge amount of legacy cruft because it took 20 years of evolution for us to finally figure out a sane document layout model.
The non-Turing-completeness of CSS has a very very useful attribute: given a parsed stylesheet (a styling tree where selectors are nodes and properties are leaves) it is possible to annotate an HTML document with the correct style properties in a single forward pass without backtracking! That's because everything in CSS is done strictly in accordance with document order. It's not possible for an element to change the styling applied to any elements that precede it in the document.
https://www.mulberrytech.com/dsssl/dsssldoc/cookbook/cookboo...
It, uh... does not make me pine for lost opportunities of DSSSL.
By the same token, if we go searching for code in a 20-years-dead language and make wisecracks comparing some random sample, to something that's had many years of development since; irrespective of whether it is representative (and it isn't, particularly), this still doesn't say much about what might've been. As a more equal basis of comparison, I remember working with the CSS and HTML of twenty years ago, and this was invariably excruciating. The CSS we work with today is the result of two decades of polishing, and it's still mediocre, inconsistently implemented, and still riddled with issues and oh-for-heavens-sake-why-can't-it-just-do-X moments.
Back to the point, however; the canonical DSSSL application was DocBook, and we can still visit the much more lovely DSSSL source at its resting place in https://github.com/docbook/dsssl.
And I haven't been thinking this for 20 years or something set in my ways, I was previously only vaguely aware of this "controversy". In fact, while you suggest the unfamiliarity or dislike of Lisp syntax is behind opposition, I think it's probably the reverse, most of the people (especially in 2020) pining over DSSSL are specifically those in love with Lisp who were hoping it would make it an again mainstream technology -- I'm going to reverse it and say your advocacy is less about the idea of using a full programming language for HTML styling and more about just liking Lisp and wanting an application for it.
But also, sure, syntax matters for technology accessibility. It is arguably inappropriate to require someone to "learn Lisp" in order to style HTML.
(I did learn and enjoy Scheme in undergrad CS curriculum long ago, I admittedly haven't used it since).
And yet, here I am in 2021 writing an execjs wrapper to compile Tailwind via Sprockets because of how much I've come to loathe Webpack.
> more about just liking Lisp and wanting an application for it
Well, yes, or rather more specifically Scheme, and I do believe that was my opening confession in the top level comment.
> It is arguably inappropriate to require someone to "learn Lisp" in order to style HTML
And it never should've been so, and it didn't need to be so with DSSSL either, because how much further might we have come in twenty years with an underlying language that wasn't basically hobbled out of the gate? Yet styling HTML with raw CSS is still programming, requiring knowledge of tree structures, a vast and ever-growing array of selectors and pseudo-classes and properties, recursion, priority ordering, an expression syntax not a million miles from S-expressions, the HTML DOM, four or five different box & layout models, and typography, not to mention all the browser quirks; oh, and - in practice, let's face it - Javascript; and yet 2 out of 3 major browsers still can't consistently size & center a top-level absolute block element, !important is the standard voodoo prayer for many, and fixing misbehaving CSS is basically debugging but in a language that lacks almost any first-class construct that might help.
So after all this further reflection, and notwithstanding that I've built up tons of valuable-in-practice crystallized experience in bending CSS to my will, I'm even more irked about the way things turned out.
It's entirely appropriate to require people to learn something new, like a Lisp-based template language instead of HTML, if you're paying them to do a job.
Requiring people to learn stuff for a job is one way that shit languages proliferate; why deny that advantage to others?
However it fails to do so. The list is mostly subjective preferences, and as such is far too long, leaving the actual universally-accepted gotchas to get completely lost among the rest.
Even some of the points that most would agree on are still such minor gripes as to be almost irrelevant, so listing them just detracts from the significance of some of the very large actual mistakes in CSS.
Here's a few choice subjective examples:
> Table layout should be sane.
This is not a helpful bullet point without expanding further.
> The 4-value shorthands like margin should go counter-clockwise (so that the inline-start value is before the block-start value).
This would make sense for an implementer and make resulting CSS more terse for common use cases but it would be less intuitive for people newly learning CSS.
> z-index should be called z-order or depth and should Just Work on all elements (like it does on flex items).
This would have caused a lot of arms race z-indices, particularly in sites loading widgets generated by third party scripts. It would make z-index less confusing but without scoped CSS this change could get quite problematic.
> The top and bottom margins of a single box should never have been allowed to collapse together automatically as this is the root of all margin-collapsing evil.
I 100% agree but I acknowledge that many don't, so I don't think this belongs here. This is basically like the tabs and spaces debate.
> descendant combinator should have been » and indirect sibling combinator should have been ++, so there's some logical relationships among the selectors' ascii art
wat
> :empty should have been :void, and :empty should select items that contain only white space FIXED in the spec, waiting for implementations to check for Web-compat…
This is BAD. Whitespace isn't empty (nor does it display as such, it collapses to one space, not zero), so that change is incredibly unintuitive. :empty should stay as currently, :blank might fit the new use case.
The whole idea of allowing :empty to match elements containing only whitespace is fraught. Whitespace could be collapsed completely, to one space, or not at all, depending on both the surrounding markup and the values of such properties as display and white-space. If you decided the concept was worthwhile supporting, then :blank would be a decent name. But changing :empty to accept whitespace, well, that’d be a far worse design mistake.
> wat
Skipping the combined character mistake, it means it should have been: > for direct descendant, >> for indirect descendants (instead of just a space), + for direct siblings, ++ for indirect siblings (instead of ~).
> Selectors have terrible future-proofing. We should have split on top-level commas, and only ignored unknown/invalid segments, not the entire thing.
That forces you to duplicate declarations for backward-compatibility. For example, you can't combine those two selectors:
/* works */
:user-invalid {}
:-moz-ui-invalid {}
/* breaks */
:user-invalid, :-moz-ui-invalid {}
Somewhat related to the link: https://github.com/jensimmons/cssremedy tries to "fix" some of those issues.My biggest gripe with the design of CSS is the lack of rules nesting. Having to repeat a selector slug to make a rule for children of something I've already defined gets very verbose.
I also find the whole situation with animations nigh inscrutable, but that could be my lack of experience with them. All I know is that it's nearly impossible to guess at the right values for animation rules, even with intellisense hints.
Can you give an example of repeating the selector slug to make a rule for children?
foo bar {
...styles
}
foo bar baz {
...more styles
}
foo bar baz > bim {
...even more
}
foo bar baz > bim:not(bop) {
...stuff
}
instead of a more SCSS like syntax: foo bar {
...styles
& baz {
...more styles
& > bim {
...even more
&:not(bop)
...stuff
}
}
}
}
SCSS seems like it gets out of control after a while though without rigor from the developers. The last app I worked on had a half-assed SCSS approach that started off with a decent base, and then got tacked onto with a ton of ad-hoc styles that weren't nested where they "belonged." Inconsistent usage of paddings/margins everywhere. It was a mess.At some level, this is unavoidable and just something to get used to. But those longer selectors can be mitigated somewhat with a sane CSS methodology. One of the benefits of CSS is that there are 100 different ways to achieve the same result—and I personally wouldn't trade that for a more opinionated CSS spec.
I don't disagree that there wouldn't be a consensus now, but that's only because the border-box convention has completely taken over.
https://www.tutorialrepublic.com/css-tutorial/css-visibility...
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}"collapse" works kind of like display: none, but ... not in all contexts.
Brevity, explicitness, obviousness, conciseness, and symmetry all contribute to the simplicity and order of a language, which minimizes the learning curve and maximizes ease of utility.
If that were the goal, there are tons of things that could and would have been done differently.
Most lists such as that of the OP and most criticism of CSS I find to be about users from a user standpoint criticising something about CSS that is either obfuscating or obstructive to their experience and productivity.
Trying to be everything to everybody has made CSS an inconsistent bloated buggy mess. If we had the above, we could have domain-specific layout engines that trim features and behaviors not needed by the domain, and reduce the problems of client/browser differences since the real work is done on the server. I'm not saying do away with existing browsers, just allow off-client layout engines when desired.
* (Yes, CSS does have a rough notion of absolute coordinates, but it's too screwed up to be practical. If it worked right, we wouldn't need the PDF standard.)
I disagree. We are inherently used to 2D coordinate systems being X, then Y.
I would instead have made the directional properties go “left, top, right, bottom” instead.
If you came from print publishing, and assume that the browser handles the gutter spacing with defaults then it might even be argued that the right margin should come next!
It's just something you have to learn, none of the options seem more logical to me.
Note I first wrote HTML using pico on a Sun workstation in ~1995; developing with the developments in web development probably causes one to develop strangely. Or, in other words, it's hard to take a fresh view when you've had to deal with IE5.
I agree that I'm more familiar with left being first but then should it be LRTB or LTRB. LRTB is common to say. But many APIs take x,y first which would arguably be LT.
Basically I think you could justify almost any order
• left, right, up, down
• North, South, East, West
• clockwise from the top
• anticlockwise from positive x
• +X, +Y, -X, -Y
The list goes on. Consistency is the most important thing.
I once wasted a whole afternoon looking for a bug until I realized that atan2 takes y first, then x.
I'd rather see something like named parameters, e.g.:
margin: top(1rem) left(2rem) right(2rem) bottom(1rem);
margin: vertical(1rem) horizontal(2rem);
margin: all(1rem);
Or some such – I dunno I'm no language designer.1. It breaks CSS box model that postulates that "width" defines element width. With flexbox that is not so as width can be overridden by flexbox in non-trivial manner.
2. flexibility shall be defined by flex/fraction units like in Grid module. So we may have:
width: 10fr;
margin-left: 2fr;
border-spacing: 1fr;
3. CSS and HTML shall have unified flex units. Flexibility in HTML uses ** units like <frameset rows="200,1*,200">
<frameset rows="200,2*,1*">
<td width="2*">
and so CSS might use that as width: 10*;
margin-left: 2*;
4. Flexibility as an entity shall be expressed uniformly among different CSS modules. Instead of bunch of separate flex-** properties and separate FR units it should be just flex units width:2*; and flex functions if that is needed.-----------------------
"box-sizing" shall have also padding-box value.
When defined padding shall go into scrollable content : https://terrainformatica.com/2019/10/17/css-overflow-padding...
In general box-sizing is broken (or under specified) in regard of paddings of the element.
-----------------------
"outline" shortcut property shall include outline-offset value too.
-----------------------
"visibility" shall have "none" value.
visibility:none;
shall be treated as display:none and display shall not have none value. So for hiding/showing a table for example we can use .some {
visibility:none;
visibility:visible;
}
But not .some {
display:none;
display:block;
}
which is obviously wrong.In short: visibility and display model shall be orthogonal.
-----------------------
Syntax:
Modules shall use functional notation rather introducing bunch of conflicting prefixed properties, so use this
display: grid(
column: 2 / 4,
row: 1 / 3
);
instead of grid-column: 2 / 4;
grid-row: 1 / 3;
Different modules in future may also want to have
grid-columns, etc.------------------------
// - line ending comments please
But one thing I’m disappointed isn’t on the list is a syntax sanity and unification proposal. CSS is a DSL so it gets some flexibility here, but there are far too many syntax variations for the same basic language primitives.
- Either all functions should require arguments separated by commas, or treat all commas between arguments as whitespace (helllloooo lisp)
- More to the point, a slash as an argument separator is bonkers. The rgb/hsl syntax breaks my brain every time I see them with an alpha value.
- Every shorthand should have a longhand equivalent (they’re finally fixing transform, but this is another syntax disaster).
- Lists should have delimiters at all. Or they should be an explicit function.
- Keywords should have some kind of sigil. The current state is untenable, as the keyword space is enormous and ever growing, making invalid bare strings (often used for browser compat) dangerously likely to become valid on unmaintained sites. The “don’t break the web” counter-instinct makes introducing new features almost guarantee more syntax fracturing.
- Either media queries should have been a part of selectors, or nesting should have been made available across the board (though I’ve seen rumors that this is being considered).
- Existing properties should get new values rather than introducing an ever growing, increasingly confusing, set of similar properties that do slightly different things in ways that are so inscrutable that even MDN can’t explain them in plain language.
- Feature forking should have its own syntax (eg or/cond type functions), not implemented as multiple definitions of the same property.
Partly syntax, partly behavior:
- Every pseudoclass should have a -within suffix equivalent, not just focus.
- Equal-specificity rules should be considered more specific by the order they apply to elements (ie the order classes are applied in markup), not the order they’re defined in the stylesheet. Atomic CSS is brilliant, but a minefield to generate programmatically (with any library in the space left to write tomes on ordering caveats), because the specificity spec is just plain wrong.
- Functions should be composable. And I’m thinking specifically about color manipulation here, so while I’m on the topic, HSLuv or some other perceptual color space should be supported.
- Styles in general should be composable in stylesheets. This can be as simple as a native extends keyword modeled on SASS, or as a function.
The new properties for individual transforms (translate, rotate, scale) are new, supplementing the transform property and not supplanting it. See https://drafts.csswg.org/css-transforms-2/#individual-transf... and https://drafts.csswg.org/css-transforms-2/#ctm for details.
SCSS (or SASS, more generally) does benefit some methodologies more than others though; I've never found much use for it while using Tachyons or Tailwind, for example.
A better title would be "some random person's opinion about what should be changed in the CSS spec".
In fact point out any mistake to me ever made and I'll just tell you that it's just your opinion and I have a different one.
I'll take it a step further and say that people can hold opinions but those opinions can be categorically wrong or right.
So this article is about one persons subjective opinion, but all his subjective opinions are definitively right and anyone who shares opposing opinions is wrong.
Just want to caveat this post with the fact that I'm just sharing my subjective opinion on this issue, you can agree or disagree.
But if you disagree with me then you are categorically mistaken, but again it's just my opinion you have the freedom to form your own opinion.
Maybe it's pointless to call something an objective opinion because literally that's what everything is. The man calls aspects of css a design mistake, you disagree, prove to me why he's wrong
Also you suggest that there’s no such thing as a design mistake, yet that opinions can be categorically wrong or right. These seem to me to be mutually incompatible. At the very least, the first part necessarily restricts the type of opinions that can be categorically wrong, so that the designer of something can’t correctly declare something a mistake.
One popular list of design mistakes in a language is https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/. Many of them can be quibbled over, but many of them are unequivocally at the very least suboptimal, where the behaviour that was complained of was quite indefensible—and commonly has been fixed since, because in many cases it was considered a bug. (And so you see how the line between a design mistake and a bug can be fairly arbitrary.)
Another example I’d use of an unequivocally bad design is MySQL’s Unicode charsets: that you had utf8, then utf8mb3 and finally utf8mb4. utf8 and utf8mb3 were both stupidly broken from the very start, utterly unfit for purpose. They should probably never have been invented, but at the very least they should have been named differently—tens or hundreds of thousands have learned the hard way that “utf8” is dangerously broken, and that “utf8mb4” is what they need.
In all seriousness my post is lampooning the absurdity of calling something an objective opinion because anything can be classified as such and I'm subtly hinting at the fact that it's pointless and we should have the capability to label certain things as wrong or right rather then call it just a collection of opinions. I think you're mistaken here, we are actually in agreement.
All of Css is a design mistake and guess what? I'm not saying that's my opinion, that's fact.