Thinkings About CSS
Here's a thing that will get me intro trouble: I don't think most developers actually understand CSS. Now, sure, you can argue that most developers don't need to understand CSS because they're not front-end developers, but the issue kinda goes beyond the immediate use of the technology, because I have this awful feeling a lot of related tools are being created or shaped around perceived weaknesses in CSS that simply don't exist.
(I should say that I am in the early stages of a migrane so this may veer into abject incoherency at any moment)
The thing about CSS is that it's Cascading Stylesheets, right? Cascading. Attributes trickle down where possible, and if you put a bunch of elements within another element, you can talk to those sub-elements by referring to their parent. It's a very simple concept, but also very powerful. Intuitive, even.
But then I see things like developers re-defining fonts and font sizes through each successive child element, and I wonder how intuitive it actually is. If I say tell the parent its font is Lato, all the sub-elements use Lato too — unless I override it. Wasting keystrokes re-writing the same font definition is nonsensical, no?
OK, so you know how in Typescript or React or most other languages how you define a component as, say, a <Fish/>
, and all the variables you assign therein belong to the Fish and nothing else? Like if we say:
export function Fish() {
const banana = "abc";
return (
<div>{banana}</div>
)
}
... we know that banana
means abc
in this one case only, yes? Nice and simple, yes? The stuff dreams are made of, right? Every time we use a Fish, that banana
is instantiated. It's logical. So why do we have so many frameworks and libraries dedicated to preventing CSS from doing this:
.fish {
background-color: #fff;
}
We've made a component and we've defined a variable within it. If we want to re-use .fish
, all we have to do is assign the class to an element, and it instantiates with all the right variables baked in. If we had sub-classes like so:
.fish {
background-color: #fff;
.taco {
font-size: 2em;
}
.lemon-pie {
color: green;
}
}
We can be fairly certain that every instance of .fish
is going to style the sub-elements appropriately. What we've created is a re-usable component in CSS — if we want to extend it via .fish.pike{}
then we can adjust sub-values quickly and easily. But at a baseline, we have a definition that can be used almost anywhere, and is functional and useful on its own.
The thing about Cascading, though, is that it works best if the definitions are logically grouped and called in order. Redefining the background color of .fish
is pointless if .fish
doesn't exist yet. But that's exactly the kind of thing that happens when you bake your CSS into your class components in many modern frameworks: you're defining each piece in isolation, so you need to redefine a lot of the same things multiple times to accomplish extremely elementary things.
If I have a style defined for lists on my site, that style should be as portable as writing .list-style-1
on anything I damn well choose. I love Tailwind, but between it and React, it sometimes feels like they're doing everything they can to keep you from solving simple problems simply. I can figure out how to "domain" my classes so they don't pollute each other — why do I have to find workarounds to make that happen?
All of which leads me to this nagging feeling that these solutions are being dreamed up by people who fundamentally misunderstand how CSS works. Yes, if you make sub-classes irresponsibly, you can create a mess in any application. But if you approach it like the component-based logic it actually always has been, it will let you write much less code for much greater impact, and save you oodles of suffering along the way.
Yup. None of that made sense. But I stand by my assertion: CSS doesn't need saving. Developers just need to learn how to write CSS.