CSS, the wrong turn the Web has taken
As I have told in my last article, a very thorough one about HTML, Tim Berners Lee came up with the idea of a markup language and pages publicly available in a network as a way for scientists to exchange brief academic papers, but with links to other papers if desired, and so the Web was born. HTML was perfect for that, but even before the Web expanded and ended up mostly outside of academia into the commercial realm (partly because HTML was very accessible) the few updates to the markup were deemed insufficient for new directions of the Web.
Something had to be done about it, and in this context, an extension for more flexibility on styles working in parallel to the HTML markup seemed like a good idea. Unfortunately, we got CSS (Cascading Style Sheets), a concept from 1994. Even with the requirements mentioned and the 100% static Web at the time, we should have had something better.
The design choice made for CSS was a choice for an unnatural system that prioritises selectors and overriding (the cascade from the name). This is crucial, as the consequences of the choices packed with the Cascading Style Sheets standards haunt us to this very day.
An unnatural approach for coding
The CSS design choice is its fundamental flaw, and this flaw may be attributed as being a direct consequence of the fact that in 1994 there was no scripting language (JS) taking over the Web yet.
To talk about how ill-conceived is its concept, let us start by saying that programmers have a pretty standard way of thinking about structures. Things like variables and functions tend to be isolated, but also easily composable and reusable, as most of the language. Something with the same concept could have been just as well used for styles, even if kept very simple and accessible, but CSS came with a unique approach, based on selectors and overrides.
I am sure you know by feeling how CSS works (or you think you do), but diving into it we can see how complex and unnatural it feels, so bear with me: all styles defined on a stylesheet are by definition applicable to every element that can access the sheet, but they are applied to individual HTML elements according to selectors, that target either the type of element, the element’s attributes and one special attribute in particular called class (what a confusing name for a programmer, by the way). Then, all style declarations deemed as applicable to the element are, in the end, stacked in layers of definitions for this element decided by arbitrary priority rules. Now, individual rules (lines) are applied for the element if they are the first in the queue for its type. Let us not forget four complicating factors:
- many HTML elements have native style definitions that sum up to this and add complexity to the stack;
- there is a
style
attribute on HTML elements that also adds to the stack; - those “arbitrary priority rules” mentioned above get very, very fuzzy. To learn the exact rules is a daunting task, very unpractical (there is a lengthy page on MDN for that), and usually, trial and error is the method used;
- last but not least, there is the infamous
!important
. This little agent of chaos can put the rule in which it lies on top of everything and, to me, it both attests to the fragility of CSS in its core design and signs that even the lads who created CSS knew at some point that they created an unmanageable monster.
Phew! This sounds not only too complex but also inefficient, right? Maybe a simpler approach would also make websites faster too… Well, back to the way programmers think, and the way programming languages usually work, we can say that the conceptual spaghetti above is completely alien to the type of logical thinking that usually goes into development. It shows, after all, why CSS is usually deemed as difficult by programmers, even without bearing any logic itself.
Consequences of a flawed concept
A less democratic Web
One might say that, if this language was not made with programmers in mind, then it would be good at least to make it more accessible for non-programmers, right? Well, not at all.
Bearing in mind the lack of information about who CSS was designed for, it seems that if it was designer for the non-programmer crowd, this would only mean that CSS failed on it.
Before stylesheets, non-professional developers could create web pages using simple and mostly self-explanatory HTML tags: b
, i
, font
, center
, img
. After CSS, they were told to create a separate file for a stylesheet with a second “markup” to learn (convoluted as it gets, as we have seen above) and attach tags to entries in this file taking care not to mess it all up.
No wonder why, at that time, so many people started using visual tools like FrontPage and Dreamweaver — because at that point web development got this esoteric aura and most people that created pages before probably thought that making things on the Web was not for them anymore.
A maintainability nightmare
Even if having more than one stylesheet file was possible since the beginning, CSS design still pushes for centralisation. Having a style rule applicable to a series of elements means that, ideally, you have to be aware of all rules, all the time. This can even work for very small web pages, which is exactly what they mostly had in 1994, but very shortly after that web pages started to get complex and the concept of “web apps” was born.
For those minimally complex applications, pure CSS is a maintainability nightmare and today most developers do not dare to use it without some sort of organisation methods like BEM or OOCSS or with modifications to the original intent of the stylesheets like variables (via preprocessors or not) and scoping (via JS or not). Even with those, CSS is still so clumsy and problematic to be organised that most developers simply avoid touching it as much as they can.
Themes: perfect for CSS, perfect for nobody
Feels like it was done on purpose, to assume that most websites would bother having completely different layouts for them to be customisable. To be fair, themes were never mentioned as a focus of the CSS concept but, well indeed, stylesheets and themes fit each other so well that it feels like they designed CSS especially for website theming. Not any theming: radical theming.
The infamous CSS Zen Garden was a website that had a fixed content and a select box to change themes, that indeed changed the looks of the website completely, powered by earlier iterations of CSS. Developers at the time (by the early 2000s) got so impressed with it that it is sometimes thought to be one of the driving forces behind CSS adoption (not saying that this is necessarily true, but it is true that the general CSS adoption was quite slow until then). I remember getting so excited about it that I started a side project with this sort of theme right away (dropped shortly after).
Soon enough, though, people (me included) realised that this sort of thorough theming was just not useful for real-world applications. Even today, in web apps that feature themes there is little to no demand for those themes to change visuals completely (which can also be costly). Even regardless of demand, changing only the CSS for theming would be not a smart way to achieve that, because the maintainability issues we already discussed would render it all a real headache.
The Zen Garden itself could be considered an interesting visual project, maybe even an art project, but aside from it, plus some forums from around the year 2000 that featured a couple of different themes, no palpable contribution to the Web came from this “full” approach to themes.
When your fans may suggest that you suck
CSS has its hardcore fans, for sure. By visiting websites that showcase little pieces of code like Codepen, one can instantly see some marvellous achievements like 3D scenes and complex drawings done only with pure CSS and no JS at all, just some little “host” HTML, usually empty tags.
Those showcases are very interesting indeed, but also very distant from the normal use one should make of CSS. They remind me more of obfuscation challenges or esoteric languages in their intent of being hard challenges that test one’s ability to overperform and extend current possibilities. In this sense, rather than convincing people of CSS’s good qualities, these fans (possibly not actual CSS fans) are exposing this little language and making it sound like it is a web-designer version of Malbolge (an “esoteric” concept language designed to be almost impossible to use).
CSS: the good parts
CSS is about applying style rules. How those rules are applied makes all the difference, and that is what I am pointing to as the place in which CSS is a regrettable disaster.
In all fairness, though, the CSS rules themselves are workable. They can, for sure, be questioned here and there about naming (justify-content
and align-items
come to my mind) but those are minor issues and, although they may get on the way and they should ideally be discussed and solved, they do not reach the architectural level of a project.
Until a couple of years ago, there was a shortcoming on CSS rules: with only floats and clears as layout rules, it could not achieve many layout solutions by itself (without JS to rescue it). Recently, though, with flexbox, grids, calc
, new units like vw
, media queries and others, it is in a much better state.
Grouping
There are more than 500 types of rules (or properties) and, unlike what happens in HTML, they are useful in their vast majority. Still, more than 500 means we humans tend to struggle to keep all those in our heads, and because of that so many of them risk not being used because the amount is too high.
There is one big detail, though, that helps a lot in this case: many of those properties pertain to a common group or are, in fact, sort of sub-properties like border-bottom-color
or overflow-x
. Like I mentioned above for justify-content
and align-items
though, this grouping does not happen all the time when it should, but it is fairly consistent overall.
The dilemma of CSS variables
For many years developers have been using variables for CSS values powered by preprocessors such as SASS or Stylus. More than that, with those tools they have been allowed to use variables that output whole groups of rules, or structures usually called mixins, which are function-like structures to output rules. Unfortunately, using one of those variables or structures also means the final CSS code generated will have at least a bit of repetition and that could have been tackled by native CSS variables and functions.
Not yet, though. Native CSS variables exist and are welcome but, by now, are not enough because they do not cover mixins or functions, only plain values. One rule that was meant to be successful and was already being used with polyfills by a lot of people called @apply
(similar to mixins) was abandoned, because of the problems in its applicability that (understandably) conflicts with the CSS model.
In a further analysis, variables make little sense within the CSS concept and having them or having a proposal for @apply
and even scoping (for that matter) shows how frail and blurry this concept is. The overwhelming success of both variables and @apply
even before the actual adoption by browsers is one more strong indication that the CSS concept does not make sense in developers’ heads, and they desperately want things that make sense to them.
Meanwhile, people with actual powers to push changes on the CSS syntax keep pushing for cases that make no difference to this issue. Rather than this being because of bad intentions or stupidity, I believe it is because they are bought into this ideal vision that is too complex, too abstract and, unfortunately, too disconnected from reality.
How I would change CSS if I could
If raised to enlightenment and given the sceptre of absolute power, I would, as a benevolent dictator of web development, in the name of my people, simply ditch all selectors, end the “stacking” model and make CSS more like a true language. Sounds dire?
Well, this could in theory be achieved by transforming stylesheets into a style
-like HTML attribute with CSS files hosting variables and mixins.
But using my imaginary total powers I would go further and change the browsers so we could if we wanted, finally make Web apps with 0% static HTML and selector-oriented CSS and 100% code, including some form of native JSX instead of HTML, or some easy templating like in Vue.js or Svelte. That would also better allow for CSS rules per element that could use variables and mixins and whatever else JS offers. JS? Oh sorry, I mean TypeScript, please. Or Rust. Or both.
The harsh reality
One may point that this crazy possibility above is possible right now, through the powers of WebAssembly. Without the proper tools, this is unfeasible though — right now WebASM is mostly used in small and very specific applications and we don’t even have a good alternative there to allow us to bypass the ancient (and awfully designed) integration between HTML and JS called DOM.
I wish I had the knowledge, the ability and the time to build those tools. Or, better, magical powers. Without the latter, this seems like a daunting task: the engines that power our browsers right now are highly optimised for our messy front-end world built on top of HTML and CSS (and JS). In other words, we got used to the mess, after 25 years of living with it, and now we don’t notice it anymore, or we like to pretend it’s not there.
The main stack could change, of course, but let us not hold our breath: the few people that can drive a real change on either HTML or CSS for them to improve conceptually are too busy discussing minor details or too bought into their concepts to see what people wanted in the first place. They will possibly watch HTML and CSS die while discussing a brand new ultra-hip CSS selector to be used on edge cases inside Shadow DOM.
Jokes aside, I predict that HTML and CSS will really die, eventually, as people will find ways to avoid this stack completely at some point in one way or another. If we stop to think, they already do this, but partially: people developing serious real-world projects on front-end by default now use frameworks, bundlers and other tools that keep HTML and CSS as tamed and distant as possible. We are not only putting a lipstick on this pig, we are dressing it up heavily and putting a snapchat filter for it to look human. It is still a pig though. Regardless, it is telling that developers want to opt-out and they are already going for it.
Perhaps, integrating solutions from outside the web like Flutter and Yoga (and ones I still don’t know about) may be the next step. If WebAssembly experts find a way to render layouts directly and efficiently without JS/DOM as a middleman, then you can bet on it to be the very future of the Web. Let’s see which are the next chapters, but the mid-term future looks promising.
Conclusion
I apologise for the long article, but it is an important issue that, in my view, needs a thorough discussion. CSS was created to solve a problem in HTML and ended up generating a general feeling that web development, once accessible, became just too hard to deal with.
It also has a flawed concept that is not friendly to how programmers usually think and its implementation suffers because of that. Its functionality was never the big issue, and today with flexbox and grids it is even better but, because of its concept, it is a bad match to any front-end architecture. Finally, as said, it is used today mostly under other tools that make it more bearable, which makes it likely to be eventually replaced.