In Defense of Utility-First CSS (2018)
frontstuff.ioTo each their own, but I personally learned to hate this approach. In my experience, it leads to a CSS spaghetti full of overrides and `!important` just to get all the utility classes to play nicely across a site. And of course the markup becomes less readable.
I prefer to just write classes for specific components with some modifier classes to toggle variations. People resist this because they've been taught to avoid repetition, but I've found that repetition is a good trade-off for things just making more sense because it's really not that hard to go in and change the same pattern repeated among CSS selectors if there's a site-wide design change. If you really hate repetition, you can still use CSS variables and SCSS mixins. But the end product of the CSS definitions should be styles that are easy to use, don't tangle with each other, and make it clear what an element represents.
What I describe becomes even more practical if you separate your CSS concerns into concepts like "layout" and "component" or "design". That way the styles that handle your page layout and responsiveness don't get tangled with the styles that handle the appearance of elements.
Here's a blog post I wrote that goes into more detail about my approach to CSS: https://tenbit.co/blog/my-approach-to-writing-maintainable-c...
(I only recently discovered that the page heading is kinda broken on mobile. Sorry.)
>To each their own, but I personally learned to hate this approach. In my experience, it leads to a CSS spaghetti full of overrides and `!important` just to get all the utility classes to play nicely across a site. And of course the markup becomes less readable.
The entire point of utility CSS frameworks is that you barely mess with the css, the css is already baked in, you just pick from it within html.
>What I describe becomes even more practical if you separate your CSS concerns into concepts like "layout" and "component" or "design". That way the styles that handle your page layout and responsiveness don't get tangled with the styles that handle the appearance of elements.
Frameworks like tachyons or tailwind have basically inverted the specificity/explicity/reach pyramid that is known from soft CSS frameworks like ITCSS. Their css file is quite similar.
I could see that working if the designers commit to limiting themselves to what is in the CSS. However, in my experience they generally want pixel perfect implementation of any design they come up with. As soon as that happens, I think that utility CSS becomes a major liability.
Design systems that UI designers come up with can be baked into the utility css stylesheet in advance, before devs or other designers access it through html. Kinda like a living style guide, but in code. That's really the point, the css stylesheet is basically an intermediary step and single source of truth for the styles in the design. Then when stuff is being built devs don't have to think about styling, only layout and applying the correct values that are predefined in the css.
That said, if you're on your own, have your own boilerplate and design skills that you can apply in real time and know css/html, you might be better off with regular css.
Design systems that UI designers come up with... and then break them later every chance they get, because unlike what developers believe, design is not always lego blocks and styles will be tweaked to fit the context. A developer sees the sum of all UI components on a page, but the designer sees missing accents or not enough spacing and will adjust those to fix issues or achieve a particular look... the result being new styles for that page.
+1. A lot of design systems assume that, for instance, there are only a few amounts of vertical padding you'll ever want to have on an element. But sometimes, the designer really will tell you that something needs 10 pixels of padding, your 8-pixel "p-2" value is too small, and your 12-pixel "p-3" value is too large.
The problem that I see is that by making the decision that something needs to be pixel perfect the designer is often "volunteering" the engineer for an hour or more of fighting with CSS. In my experience the engineer is then expected to spend that time in addition to their normal workload.
The only ways I can see it working are either:
- Designers are obligated to follow the DLS.
- Any divergence from the DLS is pointed and therefore takes away from the number of points the engineer commits to for other tasks during a sprint.
This is why I really like tailwinds, because for all the dynamically generated classes (90% of their utility classes) you can choose to use their scale (1unit=0.25rem) or just switch them all wholesale to a smaller increment so that when you need more specificity it's there.
That's the designers fault then. Most alignment issues are caused by fonts and their bounding boxes that are based on line height (fonts have a default line height they ship with). One of the errors I often see is that designers define font sizes based on the letter sizes, not based on their bounding boxes or how well they fit into the bounding boxes that should match the defined component sizes within their design system. Design systems have spacing scales, and fonts (and their bounding boxes) should be part of it.
I wish you lots of luck in finding these mythical designers out there to work with throughout your entire web development career. You can spend plenty of time thinking of how things ought to be but the flexibility of CSS and HTML will always be utilized in real world applications where it's practical. Asking for a few more iterations from the design team to make their concepts fit your teams existing set of baked utility classes or even their own style guide (issued more than a few months ago) instead of simply writing a few more lines of CSS is not a good trade off in the eyes of most everybody including many developers.
Is that really the case though? With flex box and grids it seems like it should be as simple as making sure that your design is based on proportions instead of static values (e.g. "evenly space the three columns across 80% of the page" instead of "Make three columns separated by 10pt with 30 pt before the first column and after the last").
It also seems like it's a whole lot easier to make changes to a wireframe than to fight with CSS rules.
It's been the case in my experience working with designers who themselves work with product owners. When there is a business urgency around a new feature or design then pushback from the dev team because they dont want to modify CSS or write an ad hoc class isn't likely to be successful.
The design team is responsible for the baked in utility classes in that case, therefore I don't really understand your point.
My point is design teams that do CSS are rare. I've actually never heard of this unless it's a designer who is now working as a developer, on a development teams.
I agree that most design teams are not going to actually write CSS. However, it seems reasonable to me to expect them to organize and communicate their design in terms of classes.
I see two advantages to that approach:
- It requires the design team to take responsibility for structuring the design. E.g. determining parts of the UI that share the same design and defining a hierarchy of design elements.
- It makes the work that the design team is creating for the engineers more transparent. Communication can be something like "this new wireframe requires 5 new classes" rather than something vague like "just tweak the styles we used for the other components to fit this new wireframe".
We have bad terminology and insufficient training I think. We are deep into metric dysfunction now thinking the repetition of very small blocks of text is wasteful, even shameful.
That’s not the duplication that matters. The duplication that matters is the effort. Having to do the same action over and over, and ensuring the same result occurs. That’s expensive. That’s draining.
Trying to deduplicate code that is structurally similar but has different aims just creates a problem later on.
> Trying to deduplicate code that is structurally similar but has different aims just creates a problem later on.
This is one of the most important lessons I've learned in software. Abstractions work well when the snippets in question have similar, coupled requirements. The proposed abstraction must target the shared requirements, or it will soon cause more problems than it solves as the snippets diverge due to their different purposes. Structural similarity alone provides very limited opportunity for a robust abstraction.
A rough heuristic that may indicate one of these problematic abstractions is the number of special cases and if-elses that are continually being added to make it work.
The issue, at least as I understand it, isn't so much in the fact that code is being duplicated. Rather, the problems that I see are:
- Having lots of utility classes applied to the tags in HTML make it difficult to read. In particular, when it becomes necessary to split a tag onto multiple lines the HTML can become less effective at visually indicating how tags are nested.
- Including styling in HTML obscures the intent of the HTML. For example, is this div here because this is actually a new semantic section or just because we needed somewhere to put utility classes?
I'm with you.
I think Trello's CSS guide they put out a few years back was the sanest approach to writing manageable CSS I've found. It's something I try to follow in every project.
https://github.com/trello/trellisheets/blob/master/styleguid...
> To each their own, but I personally learned to hate this approach. In my experience, it leads to a CSS spaghetti full of overrides and `!important` just to get all the utility classes to play nicely across a site. And of course the markup becomes less readable.
I wrote many many CSS lines in my life and !Important is part of OOCSS world more than utility first. How do you write !Important in a functional space? It's kinda impossible unless you want to overwrite things too much from outside the funcional classes. That would be a problem and it would tell you that your approach was not good from start.
I think it’s a good option if:
- you build js components
- you don’t know css that well
- you don’t want the cognitive load of naming styles, esp. as a team.
I do know CSS, do not use react, and am used to BEM, so this is not a solution for me.
They makes a very poor case IMHO, and come off as just preaching to the choir.
> Make no mistake: just because style composition is performed in the HTML document doesn’t mean it’s done in HTML.
That is 100% what that means. Sure, you could make .font-italic do anything, yet if it turns everything bold or anything other than italic it’s a horrible sin.
Make no mistake, you are editing your HTML to adjust styling. It’s “done in html”.
Truly semantic CSS has been dead for around a decade, killed by the likes of Bootstrap. God I miss it. I miss the goal of just cleanly naming things what they are, not how they look. Taking pride in the quality of the HTML, versus today’s rush to get an MVP out the door as quick as possible.
> God I miss it. I miss the goal of just cleanly naming things what they are, not how they look.
I think utility-first CSS has its benefits as well as it's drawbacks, but just regarding the statement above: wouldn't you say that when naming things for the purpose of targeting them with styling, what they look like is indeed what they are?
As in, referring to, for example, ".comment" and ".testimonial" in your CSS, when those classes have been added purely for the purpose of styling the elements as what is commonly called a media component, could be considered less semantic than just naming them according to how they look -- as that's the reason for naming them in this case?
(I think these are two different ways of looking at the issue, none of which is clearly the right or wrong one.)
> wouldn't you say that when naming things for the purpose of targeting them with styling, what they look like is indeed what they are?
What do you mean? A "comment" is likely to stay a "comment" forever, whereas its bold'ness or italic'ness can/will likely change relatively often.
Well, yes. So, in the hypothetical situation where classes are added just for styling, is it a given that the correct way to name it is a way that stays the same when the styling changes?
> in the hypothetical situation where classes are added just for styling
OK, a style-based class naming system
> is it a given that the correct way to name it is a way that stays the same when the styling changes
Not with a style-based naming system, in that case it's ok for the class name to change, and you can expect it to change often, which a lot of people argue is ok.
But like @welly said, herein lies the problem, or preference. The argument is exactly about whether you should name things in unchanging "decoupled" ways, or whether that doesn't work out in practice and it's simpler to just have utility styles.
And therein lies the problem. You don't add classes just for styling. This is terrible practice that I thought we'd stopped doing.
I might be wrong, but I have the definite impression that semantic CSS was invented mainly by people working in publishing, so typical semantic class names map to content types you would create in a CMS. The developer mainly controls the CSS and users generate most of the HTML. Developers who work on app-like experience might be less interested in this style of semantic CSS because users are extremely constrained in how they can influence the layout anyway.
You're naming stuff as a comment or a testimonial or whatever else because that's what they are. The html defines what a component is and the css then describes what a comment or a testimonial looks like. You seem to have it the wrong way round.
It is certainly not semantic to name elements according to how they look. What if a div with classes that define the colour, the font size, the horizontal alignment etc. are later changed to be aligned right rather than left? Do you change your css class of "align-left" to a float: right? No. You don't. You name your component to describe its purpose and style the component as required.
I'd say the class name can be semantic whether it's semantic with regards to the components function, its form or something else. It's not self-evident to me that a name given to something in order to affect its form should be semantic with regards to its function, not its form.
As I understand utility-first CSS, changing the classes as in your example is very much what you might do. Why would this make sense? Because the situation where we want to "change how this component looks in the sidebar, but keep it the same as before in the footer", or "show this component slightly differently in a new context, without changing its appearance in its old contexts" is much more common than the situation where we want to change the look of a component everywhere it appears. In this case, utility-first CSS makes it very easy to make all these small, "one-off" changes.
> I think utility-first CSS has its benefits as well as it's drawbacks
What drawbacks?
You add a class called font-bold which adds a bold style to the element. Your client decides the element should be italic not bold. You then have to go back and change all your bold elements to use font-italic.
That's not a drawback at all. First, you would replace those font-bold with font-italic (assuming you name the utilities like that) and problem solved. You don't need to change .font-bold and add font-style: italic; in the font-bold class. That's they convinience of utilities: they aren't mutable.
What if you have 500 pages which need to have font-bold replacing with font-italic? Or more? 1000 pages?
Sure, you can probably write a script but if you name your elements semantically, you potentially only have to change it once.
I 100% agree with your opinion on “utility-first CSS”.
I wouldn’t declare CSS dead though. Some folks, like myself, continue to do things the right (IMHO) way. I sometimes even consider creating a new site like CSS Zen Garden (haven’t bothered to check whether such already exists)... imagine the creations people could make nowadays.
I also use Bootstrap, and I love it, but I don’t use it to design my apps / websites; I use it for its utilities (responsive utilities, form styles, etc.). I realize there are smaller frameworks for this purpose, and I sometimes use them also. I still design most of the internal layout from scratch (e.g., I don’t use “cards” and other shortcuts to bypass meaningful design, etc.).
Maybe I just have an unusual learning style, or haven't gotten the right resources, but I've found traditional, semantic CSS to have a brutal learning curve. When you're trying to build complex apps, you're constantly rearranging your taxonomy of classes to break down the page into an appropriate logical hierarchy. I appreciate that in principle this is a good thing to do, and once you get good at it there is less rewriting, but when you're trying to learn all of the other aspects of this craft at the same time, it can be a draining experience.
And I mean this on the scale of years, not just the 6-12 month "just getting the basics" stage of learning to be a dev.
If we still had the position of "front end developer" in the old sense of writing HTML, CSS, and maybe some light JS, that's someone who could dedicate their resources to mastering semantic CSS. Sometimes I wish there was still a job like that, but for whatever historical reasons, at most companies what we have is a combined role called "front end developer" that involves fairly heavy duty development with client side frameworks like React, but also all of the HTML and CSS stuff. And asking these folks to get good at the semantic side of CSS at the same time as learning all the rest, is asking a lot. Maybe worth it, but it's no joke.
I should have mentioned that I don’t apply the semantic concepts completely and dogmatically. They just act as a guiding philosophy.
I definitely have to agree that the complexity of “front end development”, as a role, has increased drastically, meaning there is much less time to dedicate to learning and applying these types of traditionalist techniques, compared to pragmatically and quickly implementing things with heavy framework usage.
I also think there is a bit of a vicious circle with that mindset. When people use frameworks they tend to build more complicated things than they might without those frameworks, which makes plain ol’ CSS/ JS look like an untenable solution. When I think of building an app with plain CSS and JS with only jQuery, I think of it as a helpful constraint that will lead to simpler code and simpler functionality, not to mention what could be megabytes less of tools and frameworks that users will need to load.
Exactly. The other thing is that the tools you use define how you think. Nobody is using HTML properly, it is as if the only elements are div and span. Why can't we have people using the full vocabulary?
If you only think in terms of div and span with a gigantic mess of CSS making it look like a web page then you are never going to write good content.
Content means articles with sections with asides, headers, details and summaries and regular HTML goodness such as lists. If you can write your content in a sensibly structured way then you can style the elements consistently with a minimal amount of classes.
Also to add to the mix is CSS variables. People that aren't using them in their CSS for making pages responsive are just not using CSS sensibly and are doomed to use a hacky scheme to manage untold bloat-CSS.
Utility-classes like `font-16 font-bold font-purple` are essentially just shorthand for writing inline CSS. You are defining the styling in HTML, with a utility CSS file as go-between, true, but if you use Tachyons or Tailwind the way they’re supposed to be used, the way to change the look of an element is to go edit the HTML.
For component libraries, that makes a lot of sense. You re-use snippets of HTML that is styled a certain way. No need to set up another re-use layer using CSS.
I expect the next level of utility-first CSS will do away with the CSS file altogether, and start baking the resulting styles directly into the HTML, so <div tx(['font-bold', 'font-16', 'font-purple'])> would be transformed by whatever you use for HTML rendering into <div style="font-weight: bold;font-size: 16px;color: purple">. That would complete the circle and cut away a lot of complexity.
What you describe sounds like the way some use CSS-in-JS frameworks as emotion or Styled Components.
Yeah, they’re currently just one step away, generating class names on the fly and attaching those classes to elements.
> I expect the next level of utility-first CSS will do away with the CSS file altogether, and start baking the resulting styles directly into the HTML
It's not exactly the same thing, but Atomizer [0] generates a CSS file from HTML, by translating class names into functional CSS rules.
The problem with inline CSS is that it has some limitations, notably lack of support for selectors like :hover, :focus, etc, and pseudo-classes like :before and :after.
[0] https://github.com/acss-io/atomizer / https://acss.io/guides/atomizer.html
That already exists in email newsletter creation tools so I guess you were right there :)
Also in the React community, there are already ultra-generic component collections like https://rebassjs.org/.
If you're not sold on Utility-first CSS, your gut reaction would be, how's it different from inline styles? The author does a great job at listing out the differences, but I think that kinda misses the point.
If you've to accept Utility-first CSS, you should unlearn the fact that there is something inherently wrong with inline-styles. Often, they are much cleaner solutions than creating an entirely different class that won't be used more than once. Utility-First CSS only makes it easier to use inline styles (by reducing verbosity) and provides a standard set of classes so you don't end up creating 100 variants of margins.
I have found it hard to convince folks this is indeed a good approach because inline styles have acquired a reputation of being a disgusting hack. A while ago, my outlook was not very different. But then, I started seeing how often I was writing the same styling rules again and again. Our 1MB stylesheet was nothing more than a repetition of a few basic rules. Utility-first CSS builds on that idea and to me, it feels natural.
If your "standard set" has 3 varieties each for top/bottom/left/right margin, you've already got 81 combinations of margins available at each element.Utility-First CSS only makes it easier to use inline styles (by reducing verbosity) and provides a standard set of classes so you don't end up creating 100 variants of margins.I was just today watching some of the videos Adam Wathan put together for Tailwind [0] and this one on "Optimizing for Production"[1] is especially relevant to your comment.
You can introduce a build step (in his example, PurgeCSS) to filter down to only the styles that you actually use. So during development you'd have thousands of available classes, but in practice you only use a handful, and that final CSS file can be significantly reduced.
I'm not (yet?) fully on board the utility-first bandwagon and I have yet to give it a solid try, but I was excited by the idea that it should be pretty optimizable.
[0] https://tailwindcss.com/course/
[1] https://tailwindcss.com/course/optimizing-for-production
Lately I’ve been intrigued by https://every-layout.dev/ and so-called ‘intrinsic’ CSS approaches. It’s like having utilities for whole layout chunks, instead of single properties. I would describe it as trying to extract whole atomic layouts like ‘sidebar’, with CSS rules that make the objects behave ‘well’ no-matter what the surroundings are. In comparison, semantic CSS can be too tied to single page elements (main__header) while utility-first in a sense is not ambitious enough (because it limits atomicity to single properties).
I've switched to this approach a while ago, and haven't looked back since. It makes everything so much simpler, hands down.
I have utility classes, grouped semantically into separate css files. I've built up a library of components that I use across my projects (so eg. if I need to change a button, I just change it on the component server). Encapsulating style, function and semantics in separate layers has really increased my efficiency as a developer.
Interesting challenges arise when collaborating with UX / UI designers. Quite a few of their tools (XD, Figma, etc) can output ready-made CSS blobs for front-end dev copypasta, but it's the old-school semantic CSS.
What I have found reassuring though is that in general, designers eventually come up with UI kits, and there are certain stylistic consistencies inherent to those. The kits usually translate very well to a functional CSS implementation because of that.
I’m not familiar with Utility-First CSS: is it where you add class=“color-blue underline font-big” to your links instead of class=“header-link” and add the CSS to do the styling to the class? If so, I’m not sure I can shake the “yuckiness” I feel by choosing to not annotate an element with its semantic meaning. It seems awfully likely that you’d get the same issues you’d see with styling divs instead of using actual HTML elements…
I disagree with the author but I appreciated very thorough explanation of various CSS structuring approaches - it was very helpful for me. Disclaimer: my knowledge of CSS is 2 out of 10 at best, but my personal preference is the semantic way: use header, footer, article tags and use either div’s with semantically name classes (like ‘card’) or React components or web components. If CSS is more complicated as a result of that - I don’t care, there are ways to deal with that (extend, variables, preprocesssors etc). HTML is not the place to be concerned whether your text is green or card has a ribbon.
I came across tachyons a few years ago and it made CSS finally click with me.
The main advantage for me was that I didn’t have to switch back and forth between two files to style something.
Utility-first CSS feels more like using a REPL than a compile-debug-reload workflow.
I've wrote an extensive piece (p1: http://minid.net/2019/04/07/the-css-utilitarian-methodology/) about this too called "In Defense of Functional CSS" (p2: http://minid.net/2019/08/12/in-defense-of-functional-css/) I give all the arguments I think are valuable for this discussion.
I skimmed the article, but I don't think it covered one of the reasons why I prefer utility-first CSS. When all the CSS is in a separate CSS file I can look at a page's HTML and have no idea what it will actually look like. But with utility-first CSS, just by looking at the classes on the HTML elements I can make a pretty good guess at what the HTML will look like when rendered. I'm sure a lot of people won't see this as useful, but I really really appreciate it.
This was how I adopted CSS from day one. My standard home-evolved CSS library has a large set of very simple classes that standardize the options I have to choose from. As the article mentions one of the fallouts from this is consistancy of design across multiple pages. I'd like to say I had some grand epiphany about how CSS should be used but this just seemed like the most obvious way to use it.
If you are building a totally generic CSS library to use on a bunch of independent sites, then sure... utility first.
But the main reason I think semantic CSS is important has nothing to do with anything technical.
CSS is not just a technical contract with the browser, it is the place where your organization’s design language is made manifest.
If your pages match what’s in your designers’ mockups, that’s good. But if your CSS matches what’s in your designers’ heads that’s way, way better.
What that means is that “configurability” and “flexibility” and “composition” are anti-patterns.
Being able to do anything is bad.
The goal is the opposite: almost everything should be impossible to do.
The goal is that you can only do things that make sense within the design system.
That means making something that’s technically quite useless, but just barely can do the things your designers want to do.
The same applies to component names and arguments. That’s the other place where the design system contract becomes real.
So, if you’re a freelancer than yes, go utility-first. But if you work on one app day in and day out then you’re playing a different game with different goals.
I'd just like to mention that Jukka "Yucca" Korpela had some interesting observations, relevant to the discussion here, about CSS back in 1997. He might have been the first person to write about these issues:
I think this is an issue which needs to be addressed a bit more holisticly. The fact is that HTML, JavaScript and CSS (to name three) all use an element's _className_ for slightly different purposes.
The author seems to consider BEM an example of a _semantic_ CSS scheme, but really the semantic needs to be clear across all the consumers of the API being implicitly established by the markup.
Ultimately HTML is the original source of a web page, with CSS and JavaScript often augmenting this. For that reason, I think it makes sense to opt for the HTML spec's definition of _className_ semantics when there is a clash.
The spec effectively balances the importance of both CSS and JavaScript (or other user agent) uses, but cites an example useful to both:
https://www.w3.org/TR/1999/REC-html401-19991224/struct/globa...
I think what people are really gravitating to with "utility CSS" when they say they finally "get it" or it say "feels like REPL" is the fact that you can get instant feedback in the browser using the inspector.
It's a bit like when you first "get" TDD. Which in my experience happens soon after you've got your spec listeners and live reload hooked up properly and manage to get the spec runner to react in less than 300ms. A whole new world of possibilities open up.
I'm not taking sides, but just want to point out that this quick feedback loop _might_ be clouding people's judgement as to the benefits and drawbacks of using a coding style such as this.
One vying for this approach can wax poetic as much as one wants, but for me, seeing a difference between 'style="color: purple"' and 'class="color-purple"' (with '.color-purple { color: purple }' in the css file) is very much the same as seeing the emperor's new clothes. It looks and feels like indirection and I am aware of duck typing.
The "it limits options" defense is not really here nor there, since ultimately you could just rewrite all css rules into classes. Much like the style you can add is infinite, the classes you can add are infinite.
IMO, this is one of the best articles on utility CSS: https://adamwathan.me/css-utility-classes-and-separation-of-...
Just use inline styles and simplify your life. If you’re using React/Angular/Vue/etc, your markup is styling; so why are you separating styling (html) from other styling (css)??