CSS is enjoyable to write until it’s getting really messy in big projects, the problem with CSS isn’t CSS, it’s humans. This problem is compounded as styles grow, each developer needs to know more context in order to style effectively.
CSS was initially designed with simplicity in mind and it worked very well as dominant styling language for the web. The things that many JavaScript developers hate about CSS are the same things that make it so powerful.
Let’s look at some noted problems with CSS at scale:
Lacking of built-in namespaces - Any programming languages lacking built-in namespaces will have problems at scale and CSS is obviously one of them. Global namespace was designed as core feature of CSS to enable portability and cascading. This is the DNA of CSS, CSS-in-JS fixed that very well when build tools can intercept and generate scopes automatically for you.
Too static to change - Vanilla CSS is just a set of static layout rules; even though variables and expression have been added recently, CSS is still too simple to keep up with dynamic web pages. It’s hard to implement theming and dynamically changing styles based on incoming data from JavaScript.
Unavoidably repeating yourself - Lack of variables so we have to repeat colors all over the place. Lack of nesting so we have to repeat huge blocks of CSS all over the place. In short, CSS violates the living crap out of the DRY principle.
Stuck with the past - Three cornerstones HTML, CSS, JavaScript must not break the web; maintaining backward and forward compatible is the number one priority when design new features. Even though we can introduce new features but we can’t get out of bad decisions from the past completely, adoption rate and browser support are too important to revolutionize the language.
Resistant from static analysis - How can we apply some static analysis like dead code elimination and minification to CSS? we can’t! the global nature and cascading styles from inline, internal and external sources make it impossible to perform those kinds of optimization.
Non deterministic resolution to human - According to how css works, styles are merged from multiple sources (inline, internal, external stylesheets) and origins (user agent, user, author, !important, …), going though specificity calculation, inheritance and defaulting. This complicated process is not for human, it is for machine.
The modern web is moving very fast, more dynamic and at a higher level of abstraction. People don’t build websites with vanilla HTML, CSS, JavaScript anymore, it’s possible but too slow and missing out too many cooked production optimizations provided by frameworks and tools.
How can CSS meet the incompatible demands for simplicity (from developers), flexibility (from designers), and responsiveness (from users)? It can’t by itself, it needs help from more abstract high-level tools and techniques like CSS-in-JS, preprocessors to make it closer to a programming language.
Above problems will prevent CSS from being used on daily basis by developers but it still mostly works just fine behind the scenes. We’re generating plain vanilla CSS using general-purpose programming languages, this could be done at project build time, or even dynamically on every page load if you have a good caching strategy.
We don’t need to make CSS great again and accept it as a low-level technology, we should focus on building more supporting tools and languages that ultimately compiled to vanilla CSS so it can run perfectly in all browsers.