I once came across a CSS framework that claimed to be the most user-friendly and accessible of all frameworks. It was also incredible lightweight: just 0kb! ๐ Of course, any real web project quickly moves away from the browser defaults.
There are two ways to apply styling to HTML: the style
attribute and using CSS. While the style attribute can only change the style of the element itself, CSS lets you target classes, siblings, children and has additional features like media queries. Using the style attribute is considered an anti-pattern as it allows no abstraction and re-usability. While I think it's true that we shouldn't use the style attribute, I believe the original arguments in favor of CSS - abstraction and re-usability - no longer hold. With the coming of the component era, CSS classes have lost their appeal. Even CSS-in-JS libraries like styled-component and emotion seem to take the wrong approach. But let's back up a little first.
Before the rise of component-oriented frameworks like React, the main tool at your disposal for abstraction was the class
attribute. You could add a class btn-primary
and apply a bunch of styling rules all at once. You could target classes with jQuery and add behavior without having to implement that behavior for each individual element.
I remember trying out Bootstrap and seeing these utility classes like mb-1
and border
. I thought it was horrible. If you add classes that match one-to-one with a style rule, why not just use the style
attribute? Classes are for abstractions and these utilities were by definition no abstractions.
The irony is that nowadays I would argue that the utility classes are the only proper use of classes, and that it's the abstractions (like btn
) that are an anti-pattern. So what changed?
In one word: components. We now have a much better way of abstracting and reusing that includes styling, behavior, structure and data. A component in React is an isolation of all the former elements. You can - and probably should - create a component for every part of your website or web app. This can be a header, a button, a list or something simple like a link.
This ability to create components changed the need for CSS. We still want to style our components, but we don't actually have to share any styling between them. In fact, CSS modules was created for this very purpose.
But then the question arises: what's the purpose of classes at all? If all the classes I create are only used once, why not just put my styles in the style attribute? I don't need to leave my component and I don't need something like SASS for variables because I'm working with JavaScript (or I'm using CSS variables).
However, as mentioned before, there are other advantages of CSS over the style attribute. You cannot apply a hover style (you could, with a listener and state, but you don't want to); you cannot add media queries (you can of course check the window's width, but that's less performant and probably not SSR-proof).
The solution is a CSS utilities framework, the most popular being Tailwind CSS. This framework gives you CSS classes for all styling rules, such as mb-1
, text-sm
and sm:w-full
. You can prefix states (hover:
, active:
, etc) and breakpoints (sm:
, lg:
, etc). See the documentation for more things you can do with Tailwind. The important thing here is that the framework only creates minimal abstractions (e.g. color names and sizes). The component remains the main source of abstraction.
The Tailwind website mentions:
Now I know what youโre thinking, โthis is an atrocity, what a horrible mess!โ and youโre right, itโs kind of ugly. In fact itโs just about impossible to think this is a good idea the first time you see it โ you have to actually try it.
and the latter turns out to be a very true point. No longer do you need to invent class names like inner-wrapper
or button-icon-image-container
just so you can apply some layout styles. You just add the class names directly to the element that needs it. No more fake abstractions. It's brilliant!
So what about some of the other new approaches to CSS, like emotion or styled-components? Well, it actually looks like they fall into the same trap. Consider
const Button = styled.button`
background: red;
`
A styled component like this is just a disguised CSS class. Yes, you can use JS to generate the CSS and you can even do so in runtime. But in essence it's the same as a class. You notice this when the styled component is not the main export.
const ButtonStyles = styled.button`
background: red;
`
export default function Button({children, ...props}) {
// Think button implementation here
return <ButtonStyles>{children}</ButtonStyles>;
}
This is little different from a button
class. Similarly I found myself writing Container
, Wrapper
and Inner
styled components, just for layout purposes. How is that better?
So next time you start a web project, resist the urge for CSS modules, SASS or CSS-in-JS. Try a utility CSS framework and create a component for everything you would normally create a class for. Good chance you'll never go back.
Happy coding! ๐งโ๐ป
Top comments (0)