Things the CSS spec folks got right
blog.jim-nielsen.com
blog.jim-nielsen.com
I see CSS as a massive toolbox full of awesome tools, some old, some new, some I use all the time, others I barely know they exist, but it's nice they are there when I need them.
It also has improved significantly over the years, it's quite remarkable; transforms, transitions, flex, grid, media queries, I could go on, we even have CSS vars!
I've written/styled UI in quite a few ways, and I still much prefer CSS. I even use it for design, I often find it quicker to write a few lines of css than doing things in graphics software.
> This is all a way of extending a big “thank you” to the CSS spec authors
Seconded! I am very grateful for CSS and everyone who contributed to it.
Nowadays most of the web-design-y things I do have more CSS than HTML in them, my element trees are shallow and my stylesheets long.
For this reason I tend to prefer CSS frameworks that give me CSS classes to use in my HTML, as ugly as it might be. I just never found a good abstraction/philosophy to keep my CSS organized. Or to centralize things like margin/padding so that I'm not creating ad-hoc margins/paddings as I need them on every component.
Basically you have to tame the cascading aspects of css and use them with moderation.
If you use Typescript you should also check out plugins that will generate type definitions for your CSS, makes it much easier to refactor and remove stuff.
As to margins/paddings, basically consistency, you need a way to define and manage your "design tokens" as they are known these days. That can be with SCSS, custom util classes, and/or CSS vars, or indeed util CSS frameworks. You could also use something like https://stitches.dev/.
I am personally not a huge fan of css frameworks as I have not had the best experience maintaining components with long strings of heavily abbreviated classnames everywhere, but I do see why people might like them, they can be very powerful.
But I used to use a poor man's BEM, because my team didn't like the aesthetics of the whole double-underscore thing:
Every component (usually tied to a $WhicheverFramework counterpart, matching case and all) has a class for it, elements that are part of that component get a class like $Component-$part, and states ("modifiers" in BEM) do not need a prefix.
That, and striving to keep the tree small, moving decorations to pseudo-elements when possible, and using CSS grid instead of element-based ones like Bootstrap, means you might get some long CSS rule lists, but the actual amount of selectors is pretty manageable.
Even with Flexbox it's taken a number of years using CSS regularly to get to a point where I've now previously encountered most things I need to do which aren't straightforward derivations from the basic rules of behavior (e.g. even something simple like getting absolute positioning relative to immediate parent to work, or how to make arbitrary elements scrollable/non, or how to auto-truncate text with an ellipsis).
But at this point, it feels awesomely powerful. I've been awed in recent history at how rapidly I can create even novel/complex UI's; the experience is partly of hitting green lights over and over, improbably (which says something about the less fun stages I had to go through prior). But it's not just that; coming from working with desktop and mobile finite widget set GUI toolkits, the expressiveness via CSS is extensive by comparison (and, separately, the one-way-dataflow/functional-reactive style of development common in modern web dev feels excellent for connecting components to backing models).
It's also just quite a bit of fun. Combine the wide-ranging expressiveness with rapid-feedback workflows like editing from browser dev tools (or with HMR and live-updating through webpack)—writing CSS and watching sleek, novel UIs come together can be pretty enjoyable these days.
Could a better system be designed so that I wouldn't have had to go through the long journey I did, while still ending with something highly expressive and great for experts to use? I often wonder but haven't been able to think of an alternate design that would be a fundamental improvement.
You describe it very well; that expressiveness is what’s really enjoyable, and pretty much impossible to find elsewhere.
I think it’s maybe just a professional tool, hard to start with but once you get over the initial hurtle it becomes very powerful. In that sense it’s not that different from learning any programming language. It’s a good question if it could be easier, I’ve also done that exercise of “how else” I think the problem might be the complexity and messiness of ui and layout, it’s not css, it’s the layout. I think it could and will be easier though, not as something totally different, but simply improving what’s there; basically continuing the path it’s already been on for the past decades. I’m truly enjoying it today and excited for what’s to come!
I've often thought it's because CSS is lower-level, more like a tool for creating UI libraries (similar to writing e.g. OpenGL directly vs a higher-level scene graph lib built on top of it)—but when you want to make something unique, there's really no competition.
> I think it could and will be easier though, not as something totally different, but simply improving what’s there; basically continuing the path it’s already been on for the past decades.
Seems likely to me too.
Agree! I always liked CSS, it got better and better, and the real fun for me started when I found out all the different color names. For one little side project I forced myself to only use color names, it turned out pretty nice.
Furthermore, the CSS spec that the post linked to [3] even mentioned OpenType!:
> If the font family already uses a numerical scale with nine values (like e.g. OpenType does), the font weights should be mapped directly.
[1] https://docs.microsoft.com/en-us/typography/opentype/spec/os...
[2] https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf...
The flow model that gave CSS reputation for being unable to center things vertically was also deliberate to allow rendering in one pass (which was the model of early web browsers before dynamic HTML). It’s notable that the slowest and messiest layout algorithm in CSS is tables, which predates CSS, and CSS tried to resist for a long time.
Parsing model of CSS is pretty nice too. It can be implemented with a simple recursive parser, and the forward-compatible error handling is relatively easy in such parser.
These properties may seem unremarkable, but often it takes just one cool feature to break them and cause complications down the line.
- not supporting tables in CSS1, even though they were the dominant layout mechanism used at the time.
- `box-sizing: content-box` as original sizing model, which nobody has ever needed.
- `::pseudo-elements`, also used to convince people that having to add extra divs or spans to HTML is a horrible mortal sin to be avoided at all costs.
- the cascade / `!important`, causing endless rule precedence wars.
- `ems` as units relative to the parent instead of the root font size
- making flex-box alignment props the most confusing thing ever
- `display: none` to exclude elements, instead of an `exclude` prop, colliding with the display model
- `position: fixed` not making sense
- `text-overflow: ellipsis` not working in most cases where you'd want it to
I could go on for a while.
"It’s easy, in hindsight, to critique things CSS got wrong or should’ve prioritized differently. But I want to take a moment to marvel at the things they got right."
If you are going to bring them up, it would be nice to also provide the modern CSS way of fixing those problems.
One note, there are "rems" which are ems relative to the root. I love ems and use them for almost every component because of the size inheritance actually. rems are used when I need to make sure something is always the same size regardless of the parent, but that doesn't happen often.
Instead that "noneness" shall go to visibility - orthogonal property.
So if you have <tr> (display:table-row) you can switch it on and off by
visibility:none; and visibility:visible;
without touching display model.
Maybe they were obvious, or based on something that came before, but I've just never had any trouble using it.
I have. I'd love to write JavaScript-free webpages that use (FP-pure) deterministic CSS techniques in more cases (like the ":checked-trigger" trick which enable limited interactivity in pages), but which are sometimes absolutely impossible just because sometimes it's impossible to move the hidden trigger input to the right-place to enable the selector to work.
With very limited exceptions[1], CSS selectors are strictly "forward only": a CSS selector could only match elements based on preceding ancestors and siblings in the DOM, but not on any subsequent siblings or ancestor's subsequent siblings.
For example; a selector can match a <p> element that's preceded by an <img> element, or a <ul> element that's a descendant of a <div> element, but you cannot select a <div> element that contains a <ul> descendant, nor an <img> element that's then followed by a <p> element.
I understand the original reason for being strictly forward-only was to prevent progressively-loaded HTML documents being re-styled (quite possibly quite dramatically) as it loaded over everyone's 56K connections at the time. Considering how bad FOUC ("Flash of unstyled content") still is today on poorly architectured websites despite our multi-gigbit home Interet connections I'd say it's a sensible restriction.
-------------------
[1] The exceptions are things like `:focus-within` and `:last-child/-of-type/-nth-last` - but also `:has()`...
...but the problem is that the `:has()` selector-function is so expensive to evaluate it can only be used inside JS's `querySelector()`, `querySelectorAll()`, `matches()`, and `closest()` functions: i.e. it cannot be used in selectors inside stylesheets (both <style> and .css files). Since 2021 there is work being done to allow `:has()` in in stylesheets for limited patterns that aren't as expensive as allowing general-case selectors in `:has()`: https://chromestatus.com/feature/5794378545102848
CSS actually used to have a bunch of system colors and fonts and so on but by far the most popular use was fake virus adverts. Nobody wanted to make a webpage that didn't know what system it was going to be opened on assume the styling of that system as it would immediately clash (and possibly be unreadable).
To some extent this problem even occurs in terminals with TUI and/or color enabled apps. The focus on being a block of text output makes it reasonably possible to fix. Most people don't use/want the web to just serve blocks of text, there are other protocols and tools that do that much better anyways.
You are more than welcome to create a browser extension which disables all externally rendered CSS. Of course, even the semantic-html-centric would look like garbage, because what is "appropriate" for one site would look absurd on another.
I realize I'm arguing from a semantic-html world, now long lost. However, we _are_ left w/ a situation where straight text is rendered poorly (style du jour & out the control of the user), alongside user interface components that are a huge step backwards from prior models. Maybe in another few decades we'll sort out this pickle.
However I do agree with the sentiment of the article that CSS did a pretty good job of enabling a huge amount of change in web design over the years despite the lack of good options for layout in the early days
And tacking on to that: shorthand properties. They’re basically handwavy magic if you’re not constantly tethered to MDN.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positio...
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Mod...
The whole idea of different levels of boldness is not great anyhow. If you really care you would use a spercific font to get the weight you want.
We do? That's why we have font families.
Roboto Bold 700 ->
font-family: 'Roboto', sans-serif; font-weight: 700;
font: RobotoBold.ttf
font: RobotoBlack.ttf
font: RobotoThin.tff
As they are named here. https://fonts.google.com/specimen/Roboto
using Roboto 600 is meaningless and should be an error.
Because the font designers have made specific decisions about how the font should change as it gets thinner or heavier. There is no continuum along which you can just choose how think you want the font.
The numbers are meaningless noise.