Hacker News new | past | comments | ask | show | jobs | submit login
CSS Utility Classes and “Separation of Concerns” (2017) (adamwathan.me)
280 points by aarondf on Nov 16, 2019 | hide | past | favorite | 106 comments



I use a method called Context and Components. The idea being to build components, and to modify those components if they need to change base on context.

If I need to change the product card on my site it is at component/product-card.scss. If I want it to be different on thr homepage I change it at context/home-page.scss and I targetit with .home-page .product-card. Simple stuff, no inheritance issues either.

From my experience, reusable CSS is somewhat of a red herring. Maintainable and easily located CSS is where you get productivity gains. If you don't know what you have because there are hundreds of utility classes then what good is it.

Also, if you are using utility classes why not just inline CSS? "red-border white-background pad-20" is just as bad.

I wrote an article explaining the method here: https://polylab.co/articles/ccm-contexts-and-components-css....


I didn't know there was a name for this method, but it's what I've settled on as well: Namespace the classes by their component's class name, and then override them, if necessary, in another namespaced context. It's pretty simple, as safe as can be expected, and works well for sites of all sizes.

The only bullet you have to bite is occasionally repeating yourself, but as you say, that part of CSS never really worked well anyway.

If using a pre-processor like Stylus or Sass, you can get a lot of composability with mixins and extensions, if that's what you want, and these can even be cleaner and more flexible than utility classes, because they can use parameters and basic logic.


> I didn't know there was a name for this method

I just made that one up when I started formalizing the method!

> The only bullet you have to bite is occasionally repeating yourself, but as you say, that part of CSS never really worked well anyway.

I find as well that if you write clean, concise CSS that doesn't have to override anything you get away with far less CSS anyway. So repeating yourself isn't so bad. Similarly, in a project of any longevity, especially if clients are involved, chances are pretty high the things you repeated will eventually diverge. So had you made it DRY you would have to de-compose the coupled components and write it again anyway. With the Contexts, you can make most diverging modifications without ever touching the components, and I feel any more levels of inheritance than that leads to CSS that is more complex than it needs to be.


> Also, if you are using utility classes why not just inline CSS? "red-border white-background pad-20" is just as bad.

Those of us who’ve used Tailwind in particular might write “just as good, but better”. The utility classes are satisfyingly regular and well documented. They are higher level than inline CSS, and though obviously congruent, I'd reject a claim of direct equivalence.

Tailwind is to inline styles what assembler is to machine code, and that’s a good thing. With inline styles there is no opportunity to use combinatorial selectors, or to specify units, breakpoints, and other stylistic preferences as part of the compiled utilities.

My experience of a semantic or domain-specific approach to class-based styling is a drop in maintainability and a rise in complications, duplication, and special cases. Especially so in larger, componentised applications. Thinking of elements as purely on-page structures (and not representational of anything greater) helps avoid layering violations, promotes generality of style, and creates more opportunities for extension and substitution.


I have heard good things about tailwind. Do you find a lack in flexibility with Tailwind? To use the same example, what if the client wants a product card to look different on the home page compared to the listing page, and again in the mini cart and checkout? One approach I have seen is four different components for each location, in which case you have traded cascading of CSS for duplication of markup/logic code.


I've used a similar approach in the past but found that having styles for each component also defined in vaious 'contexts' became quite confusing. Using modifier classes defined alongside the component I found to be easier to understand / follow and also improved usability of those those styles across the codebase.


I have been playing with bringing modifiers in for when the context isn't why something gas changed. Like a normal product card and a special product card.


I really like this.

At the risk of being a broken record, this is similar to an approach that I discovered and have talked about on HN before. I think your approach is a form of "separation of concerns" that makes sense because I've found that CSS becomes less tangled and more comprehensible if styles that represent a concept like a .product-card aren't concerned with how they are sized or positioned on a page; that's the job of something like `.home-page .product-card`, or, in my own practice, `#home-page-product-card` if the element is a layout singleton or `.home-page__product-card` if the element is repeated.

By doing this, not only can I look at my markup and understand what everything means(which I can't do easily with utility classes), but I never find myself needing to use things like `!important` which have consequences to their use.


The money quote for me:

"The reason I call the approach I take to CSS utility-first is because I try to build everything I can out of utilities, and only extract repeating patterns as they emerge."

I've been puzzling over the same "Separation of Concerns vs. Mixing Concerns" dichotomy ever since the rise of Bootstrap. Something about using Bootstrap's classes never felt right to me, but I was never happy with the amount of duplication in my traditional CSS either... I eventually settled on BEM, but that didn't 100% solve the issues either, and it seems to be getting left behind as the ecosystem gets older.

The idea of starting with the Bootstrap-like functional CSS, and then compositing repeated patterns into components, definitely seems to have tremendous upsides... Looking forward to trying this methodology out in a future project.


Two decades ago I was overjoyed to discover that Scheme was finally going to have a useful application beyond illustrating SICP and writing koans to amuse myself, because DSSSL was on the cusp of evolving into the last document styling language anyone would ever need.

Unfortunately following an incident with a broken Lisp machine, a liquid lunch, and an unlicensed particle accelerator, I became trapped in a parallel universe where the HTML ERB anointed CSS by mistake during a drunken night out in Oslo.

The fundamental concept of CSS (best revealed by H.W.Lie's thesis IMO[1]) was to create a rich and versatile and non-Turing-complete set of structural selectors in lieu of DSSSL's recursive logic, and to allow styles to overlay one another; two design choices that only by the application of gallons of irony can explain why most web pages are composed of a bunch of nested DIV elements with hashed IDs and overloaded semantic class attributes, and everyone compiles their assets into a static file.

I switched to Tailwind CSS months ago. Adam Wathan is the hero we deserve.

[1] https://www.wiumlie.no/2006/phd/css.pdf


As an aside, XSLT 1.0, based on DSSSL and created by its author (as is groff and SP SGML), is 20 years old to the date.


The fundamental problem I see is that CSS is far too weak for proper separation of concerns. You can't make a nice structure in HTML, and then style it with CSS. You have to structure your HTML from the start in a way that it's feasible to style it with CSS.

(That's why every CSS question on Stack Overflow has an answer that says "use this HTML: ... and this CSS: ...". It's rarely possible to use some random HTML and style it in an arbitrary way.)

The CSS designers decided to pick a purely declarative stylesheet language, which is a cool idea and has some interesting properties. One of the things you sacrifice with this decision, though, is the ability to structure the HTML as you wish. You've got two languages you need to play with, and you've got to tweak them in concert.

There's an alternate universe where they chose to use JavaScript as the styling language. The style layer runs in its own sandbox completely separate from any other JS on your page, and all it does is accept HTML trees and lay out and style them. You can structure your HTML in any way you want, and then write 3 lines of JS to style it any way you want. You can implement TeX-style word wrapping or media queries as a library. Your designers don't have to talk to your programmers when they change something, because the HTML is generic from the start.


I agree with you that CSS is weak, especially from today's POV, and that HTML & CSS can be unwieldy together. Also that "It's rarely possible to use some random HTML and style it in an arbitrary way."

However it's not true that "can't make a nice structure in HTML, and then style it with CSS." That is one of the design goals of CSS, and it works.

In a former life I did this for many years, with many CMS and front-end systems. In a well-structured Drupal or Wordpress site, for instance, you can link to one additional stylesheet and override any aspect of the design. Some of the CSS might be ugly, and every now and then you might need the HTML tweaked to add a class, but it works.

Check out [http://www.csszengarden.com]. This is an old site, nearly 20 years old, put up by designer Dave Shea precisely to disprove your point :) It sports hundreds of interesting designs with non-trivial layouts, really pushing the boundaries of what was possible back in the day. All of the designs are CSS-only, and hang off the same HTML skeleton. If you view the source, it's pretty simple.

Doing this with JavaScript introduces all sorts of other concerns: accessibility, security, privacy, maintainability, future-proofness, compute necessary to render, render time, etc. jQuery did basically this, right? Selecting markup and content with CSS syntax to munge them, or attach triggers.

I rarely see people write vanilla CSS these days. Most folks abstract it with SCSS or LESS. That removes a lot of the warts. It's still too easy to end up with 5000 lines of CSS that can only be tested by manual inspection :/


You can re-style arbitrary (or well-designed) HTML in lots of different and cool ways with CSS. But you can't re-style it to the new particular design that management wants.

And even if I'm wrong, the last decade has proven that your regular above-average developer can't typically do it, and that amounts to the same thing.


Writing code to transform arbitrary XML/HTML trees to a layout is really hard. Naive solutions tend to break down as soon as you get weirdly structured trees. Expressing "Handle <span> nodes like this unless there is a child with class 'foo', or we are descended from a <p> with class 'bar'" in imperative code is hard.

I've worked on a moderately complex codebase that did something like this and it took a long time to get to a place where new feature requests didn't end up introducing additional complexity and the codebase wasn't a big ball of mud.

For all CSS's faults, most developers can still ship code that is understandable.


> (That's why every CSS question on Stack Overflow has an answer that says "use this HTML: ... and this CSS: ...". It's rarely possible to use some random HTML and style it in an arbitrary way.)

I think that's a different issue that has to do with the web not having proper layout tools. Where in order to position a group of elements, you had to div them. Nowadays, we have `align-self` and `display: contents`.


> Isn't this just inline styles?

Yes it is.

I personally don't like the end result, where by "separating the concerns" you end up hardcoding your style in the HTML markup. For me the utility classes are just exposing the CSS rules to the HTML markup, which I think is actually the opposite of separation of concerns because I when I think of "separate" I think the most of writing code in two different files.

> The amazing thing about this is that before you know it, you can build entirely new UI components without writing any new CSS.

So, if you want a responsive/mobile version you would have to either serve a different HTML for mobile or also have all the CSS rules for mobile in the inline class names. Before you know, you have a list of 30 cryptic CSS classes written inside the HTML markup for an element.

> How many times have you needed to style some HTML and thought, "this text needs to be a little darker," then reached for the darken() function to tweak some base $text-color?

Well, why not just use $text-color--darker? Define your swatches globally beforehand and do not allow the creation of new colors anyhwere else in the code. I guess his solution is similar, but with using another CSS class instead of a variable.

Also, what if at some point you decide to redesign your site and change the margin of all text? So you would have to replace all "mar-6" with "mar-12", but only where the margin is for text. This looks like a complex update invloving a lot of bug-prone search and replace. If it was written as ".text-margin { margin: 6px; }" then it was just a matter of changing one number and you know it would only affect the text-related margin. Sharing style across components is not always a good thing, it makes changing things much harder. I guess with this approach you should never change the initial values, as the entire design might be affected in weird ways.

I am not saying this is completely bad, I am just saying there's no perfect way of doing things and everyone and every project is different.


>> If it was written as ".text-margin { margin: 6px; }" then it was just a matter of changing one number

These types of examples basically never match real-world experience, it is never as easy as it sounds. Are you telling me the giant text in headers and small text inside buttons and condensed text in tables and indented text in lists and plain body text all share the same margin size? What happens with text adjacent to an image that itself has a margin applied to it? Or text next to an icon (which technically may be an icon font text glyph).

>> all the CSS rules for mobile in the inline class names.

most of the time, this works great. desktop and mobile can share, for example, font family, color, weight, background color, and use different font-size and padding, to account for the smaller dimensions on mobile. As a developer, having multiple styles inline are a constant reminder to be responsive-minded before making any style changes that might look fine on a dev machine with a huge screen.

you're correct there is no perfect way and projects differ -- but Tailwind's approach is often superior to alternatives


No it's not.

You cannot do this in inline styles:

<div class="md-display--none xl-display--block">…</div>

It's a false premise to say this is "inline CSS". Inline styles are one subset of the entire CSS world and functional classes can hold dozens of advantadges inline CSS doesn't have.


The subatomic class names aren't cryptic if you spend any time at all using them. But more objectively, you skipped the critically important composition phase! That's where you take those class names and group them in ways that make sense for your component hierarchy. Tailwind supports this directly via `@apply`. (Other equivalent mechanisms for composition exist.) If you're hand-writing raw HTML and manipulating the DOM directly, you're really missing out. Component-oriented architecture (exemplified by React) is powerful, and implies a different "shape" for the boundaries implied by the phrase "separation of concerns". In a world where everything can be encapsulated in components -- including styling and error boundaries -- hanging on to certain rules of thumb or best practices applicable to older paradigms can be limiting and problematic. "The difficulty lies not in the new ideas, but in letting go of the old."

All that said, 100% agreed with your closing sentence! :)


> There's no perfect way of doing things and everyone and every project is different.

Yep. I like utility classes (F.K.A. OOCSS, Atomic CSS, and Functional CSS) and use them all the time. But it's one tool amongst many. It's not reason to give up small namespaced components (e.g., BEM) or using inheritance when you're doing so clearly and deliberately (Zen Garden Method).

This debate, which is something like 25 years old at this point, always seems to assume a need for absolute purity. But one of the best things about CSS is, depending on what you're trying to build, these techniques can work really well together.


In addition to meeritas point about pseudo classes and media queries, I'd add that the fact that it narrows down the space is an important factor. The classes mean that I need to find the best fit rather than spend hours matching pixels by hand. It's like going from drawing charts on blank paper to grid paper. You stay within certain boundaries. It seems like a detail but I find that in practice (and in fairness, I've only been using Tailwind a bit so far), this makes a significant difference to the way I think and work with UI.


This is the equivalent of predefined variables (usable in any preprocessor and now even in plain CSS), nothing specific about Tailwind here. Except for the fact that in the case of Tailwind they are tied to properties, but they are defined globally under the hood, so this doesn't change anything.


(Article is from 2017). TailwindCSS is a terrific library.

One area that wasn't covered was the ease of creating truly responsive layouts, inline, by defining different utility classes to the same elements based on screen size. "Responsive" is so much more than just the placement -- quite often, mobile version needs different font sizes, overflow behavior, thinner margins (since there is less screen space), etc. Very easy to do with the utility approach.


I find Bulma strikes the right balance in this regard. It feels like bootstrap, only much cleaner, but then it also has these nice responsive classes you can apply. It makes it very, very easy work with.


The real issue with css is that there is an enormous amount of code re-use while at the same time almost no code-reuse at all. The author's example highlights this perfectly: he has a "media-card" representing both the "author-bio" and "article-preview" but the "author-bio", in this case, needs to be slightly different. This, to me, is the quintessential css problem.

Almost nothing in css is identical, but almost everything is similar.

This becomes especially true as you move up the complexity spectrum. Primitive things can be identical (fonts, colors, input boxes, etc.), but the real higher-order actual components like pages, forms, sections rarely are. In fact, the little differences, tweaks and custom-tailoring that are manually applied based on context are what separate professional design from robotic enterprise-style Frankenstein design.

I think the answer is that you need both semantic css and utility css. Utility css is used to define the rigid primitives that make up the general design language, while semantic css provides the hooks and separation needed to be able to uniquely compose those primitives into custom higher-order components.

So to answer the author's question regarding how to model "author-bio" and "article-preview", I would personally keep their separate semantic titles, but style them using common utility primitives classes and custom css within the css.


In programming, this problem would be solved with something like higher order functions or parametric data types, allowing us to both abstract out the commonalities and maintain incredibly specific, easily modifiable, highly customized functionality. Is there an analog in the CSS world?


Placeholders maybe? https://sass-lang.com/documentation/style-rules/placeholder-...

I use these a bit when I’m being more thoughtful, it’s a nice way to think about creating chunks of style that don’t get included in the output, bit surprised they weren’t mentioned yet.


There doesn't need to be, given CSS-in-JS!


It's wild to me that most of the discourse around CSS-in-JS is about personal preference for how separation of concerns should be when its biggest advantage is totally orthogonal to that--it almost completely solves the issues of scope, specificity, and mapping styles to markup that so many different libraries and methodologies have been invented to cope with over the years.


upvoted and agreed


From my experience, using utility classes like this just means that you'll have a lot of messy overriding to do when your reusable components need to look different in different places.

Personally I think visual consistency is important and you shouldn't make things look different in different places, but it's not always up to me.


At least React's "pass an object to the `style` prop" makes it relatively easy to do that overriding.

With utility classes, your code has no way of knowing that "bg-red" should override "bg-blue". (And frequently it won't, if "bg-blue" happens to come later in the CSS file.) So people end up inner-plaforming their own clunky solutions on top.


You would be surprised how many people do not know that the order of classes in the source file, not the class="" attribute, matters.

See my (totally unscientific, yet scary) poll of my audience, which heavily leans towards frontend with a focus on React: https://mobile.twitter.com/mxstbr/status/1038073603311448064...

Only 43% got it correct!


If you do not know basic stuff like that how can you even write CSS at all? Trial and error?


From experience with co-workers: Yep, and lots of !important


Let me see this:

.body--homepage .searchbox { color: red }

but, you use .searchbox on other section and you want it green

.body--article .searchbox { color: yellow }

To me this sounds an akward usecase but you can do this with functional classes no problem: just write the class to the point you want to change on whatever place you are instead of relegating these conditionals to the CSS.


As a designer, the only thing that's important for me in managing CSS is isolation of styles. I apply a reset at the top to make everything as minimal as possible and then apply styling to each element and the naming convention would be such that it applies pretty much only to that element (or only that and its children if I'm being lazy).

If the markup changes, the CSS changes. The nested SCSS should closely mirror the DOM.

I can only imagine utility classes will simply create many problems with naming down the road. I would hate to have to deal with all that.


I can definitely see the advantages! But don't you find yourself writing the exact same CSS hundreds or even thousands of times with this approach?


Yes and if anything I think I spoke too strongly. I do use classes that encompass a broader pattern, but they definitely don't go as far as "text-right", but perhaps something like, "card" for card based layouts.


I think one of the major advantages of Web Components is that styles can be isolated without the need for name-spacing. There is no need to carefully structure CSS according to the DOM, because this isolation is included with the shadow DOM. Incorporating CSS grid takes this even further, allowing these isolated designs to be responsive to the layout without needing to know what it is.


Absolutely agree. My only gripe is that consuming a blackbox (ie third party) Web Component inside a Web Component can get problematic. Your options become create a global override system or (shudder) Shadow DOM piercing.


Author here — a common question I’ve seen in the comments that I didn’t cover in the article is how you do responsive design with this approach.

Here’s a link to the responsive design guide in the Tailwind CSS docs that covers it in detail:

https://tailwindcss.com/docs/responsive-design

The TL;DR is you have breakpoint-specific versions of your utilities, so you can define all of your responsive behaviour directly in your markup.

For example this element would be `block` by default (on mobile) and `flex` when the browser is at or above some defined “medium” breakpoint:

<div class=“block md:flex”>

Two years after writing that article I can say CSS definitely feels “solved” to me, and every time I have to go back to an old Tailwind project it’s very easy to make changes.

If you’re building things with React, I’d also encourage you to explore projects like Emotion and Theme UI which allow you to work with the same philosophical approach (styling elements directly instead of through “hooks” and some separate style layer) but with a bunch of neat advantages that aren’t possible with a regular class/CSS-based API, like having better control over how style definitions override each other when applied to the same element.

Personally I’m still very happy using Tailwind even in React projects, because the syntax is more terse and it’s nice to have a singular styling paradigm that I can use even outside React projects.


Thanks for the fantastic library! I've really enjoyed using it and it has sped up dev time phenomenally. However, I am curious: what is it like using tailwind on huge projects? I can imagine with many developers working on a codebase the "extract repeated patterns to their own new class" philosophy can get easily ignored, or difficult to track where some series of classes is being repeated.


I think utility classes _first_, and not utility classes _only_, is a reasonable approach. My purist mind would prefer something like semantic classes as a sort of 'public', 'HTML-facing' API, implemented using 'private' utility mixins, keeping the separation of concerns. But in practice, I know I have wasted a lot of time thinking about class hierarcies and separating components, especially when the design is nowhere finalized and I just want a 4px padding.


I think the utility-based approach overlooks an important point: semantic class names are useful for a lot of things besides writing your styles.

"Codeless tracking" systems let you put in the CSS selector for a button and find out how many people clicked on it. UI test automation tools let you specify the CSS selector of an element to click on. User stylesheets let people make tweaks to your site if they have accessibility, usability, or aesthetic concerns.

If all your elements have class names like "mt-2 bg-black font-semibold text-white pt-2 pb-3 flex justify-left", you're making it a lot harder for you, your users, and your co-workers to take advantage of this ecosystem. At the very least, you might want to consider also putting semantic classes on your elements.


Nothing stops you from adding a semantic class name or ID to a tag for easy reference.


Right, but it goes from being something you get for free to being something you have to go out of your way to do. Which can matter, especially on projects where you're designing a site/theme to hand off to someone less technical.


I've found that using the same class name for styling and attaching behaviors to be dangerous... refactor the styling and lose the functionality, or break the tests, or disable the analytics.

I'm glad that backbone and jQuery apps are in my rear view mirror at this point.


The reason why you're finding this dangerous is because you've coupled your class names too closely with your style. Class names should describe what the content is about, and so if the class names change, that implies that the content itself is different.


I never liked to do CSS, but I must admit with the library this guy released (tailwindcss), it's really fun :)


>What if we wanted to change how the author bio looked without changing how the article preview looks?

>Before, we could just open up our stylesheet and choose new styles for either of the two components. Now we'd need to edit the HTML! Blasphemy!

The reason you can't is because the markup declares two things to be equivalent, obviously then CSS can't tell them apart. You're not mixing concerns you're lamenting the fact that CSS can't be concerned with markup.

Throwing separation of concerns overboard and making HTML concerned with styling doesn't seem the best resolution.


There are lots of positive comments in this thread in support of this approach and I think it's great when anyone challenges the status quo.

It is more common these days than it was for websites to support multiple styles/layouts. Whether that's because they're responsive or because they allow you to enable dark mode or because they support rtl layouts. Class names such as text-dark-soft or align-right will be misleading if text-dark-soft ends up closer to white and align-right is left aligned as a website is evolved to support these features.

Not a criticism of this approach; this is easily fixed by using names such as text-emphasized-soft or align-start (for example), just pointing out the examples in this article could be lead to problems

CSS variables can also be used to encourage picking colors or padding/margin from a curated list. The approach in this article is not required to solve that problem


MODS: OP is from August, 2017; maybe add "(2017)" to the title given how long 27 months is in webdev?


Maintenance of these utility class CSS codebases is such a pain. I've had the pleasure of dealing with it. What if you want to tweak one of your utility classes ever so slightly? If your codebase is big enough, you've just created enormous amounts of potential regressions.


This is why CSS-in-JS solutions outshine utility classes IMO – if you deal with stylesheets directly, it's hard to avoid treating CSS as append-only files that grow linearly with the size of your codebase. With CSS-in-JS, on the other hand, the styles get generated for you, at a size that grows logarithmically to the size of your codebase (style rules of the same value get pulled into their own deduped classes).


Give me an example of that.

Would you mantain .display--block? how? .color--red?


It would be some domain-specific component. Like .product-card. I don't see the examples you've given. Those are so literal, you might as well use inline styles at that point.


That's the problem functional CSS solves: class naming doesn't relay on developer intervention, it's just a translation of the utility.

Product-card is not an utility, that's why it's a problem to maintain such classes.


Changing the saturation of the red and causing it to look messy alongside surrounding elements/images? Or introducing colorblindness concerns elsewhere in the app?


That means two things: you need extra utitilies to have different reds or, you don't mind to adjust the same red that will impact in the rest of the website. As a designer I do this all the time. If my design is complex to the point I would need several reds, then i would use a different value in the class name, like numbers or other options.

Then my workflow for that case would be: create the new color value, compile the CSS, change the class name in those places where I want to use the new red.


The biggest win when using functional css, or css utility classes, is that it is extracted out into a library already, in which case there is nothing to create or maintain (just the downside of messy classnames).

https://tailwindcss.com


Adam is an awesome follow on Twitter. I still haven't come around to his way of thinking on utility classes. It feels messy compared to a component based approach. But, I totally respect his work and can see myself adopting something like this in the future.


I've been writing sites like this for years.

It can look sloppy, but I find that it's important to provide as many "hooks" as possible to elements; especially dynamically-generated elements.

This is because I've written tools that were meant to be integrated into sites, as opposed to the end site, itself.

It was important that the user of the tool be able to exert as much control as possible over the rendering.

It does look messy as hell, though. Inspect Element is very helpful. Since a lot of the dynamic code is optimized anyway, or rendered by AJAX, display page source is kinda worthless.

It's all about keeping the specificity as weak as possible, while allowing the CSS to focus on individual elements, or collections of elements.


Also, for anyone that cares, I wrote up a series on CSS-based Web design about ten years ago: https://littlegreenviper.com/series/cssdesign/

It's dated, but still absolutely relevant.

Here's the start of the specificity section, which goes on for some time: https://littlegreenviper.com/miscellany/stylist/introduction...


You can have many classes. So in your markup you can have an item that is both class article and class bio. Then on another page that is the same but different the class can be article preview. Then in the CSS you make rules for .article and where bio and preview differs you use .article.bio or .article.preview respectively.

In CSS specific rules overrides general rules. So .article.bio would inherit all .article rules and also override.

I like to start out my style sheet (CSS) by only using the semantic HTML elements like h1, button, etc. Then when the design advances and I go down to the small details - I add more and more specific rules.


This very long article leads to the following point:

---

> Utilities force you to choose:

Is this text-sm or text-xs?

Should I use py-3 or py-4?

Do I want text-dark-soft or text-dark-faint?

You can't just pick any value want; you have to choose from a curated list.

Instead of 380 text colors, you end up with 10 or 12.


This is a particular dilemma I've tried a lot of different approaches for. One thing the article didn't touch on is what happens on responsive, where often margins can change multiple times between desktop and mobile.

For a while now I've been effectively writing semantic css (nested or more recently bem) composed out of non semantic sass helper functions. The benefits of this are being able to think about namespacing in very simple terms. It can make for fairly large css output files though, something BEM helps with a bit.


This article is interesting, but not for anything having to do with CSS:

1. Start with a given approach, but say you feel something "off" because it doesn't quite fit "best practice xyz".

2. Use another approach, which also doesn't fit "best practice xyz".

3. Argue that the best practice shouldn't be a best practice.

This of course, should mean that the very first approach is just as alright as the second, yet here it is used to defend only the second (sure, there's a token acknowledgement of the first approach being valid too under the new assumption, but everything afterwards is a long "but not really, second one is the true better one").

Back to the topic at hand, the article depicts a circle: let's move away from inline css by... moving it one attribute over, to "class". The token attempt at contradicting this is unsuccessful one because, as much as there's no limit in the inline css you can do, there's no limit to the amount of classes you can add. So it all ends up feeling a bit self-defeating.

Ultimately, this article, IMO, is a good example of this: https://christine.website/blog/experimental-rilkef-2018-11-3....

Then again, I'm a developer first and foremost, maybe I'd like this better were I a designer.


I love the analysis in this post. I think utility functions along with a set of design tokens (Styled System [1] / ThemeUI [2]) is a better mechanism and achieves the same end goal as utility-first CSS, at least in the React ecosystem.

1. https://styled-system.com/ 2. https://theme-ui.com/


Yeah, it's technically better than Tailwind CSS, but unfortunately JS/React only.


I wanted to point out some of the downfalls of utility classes, but then realized that my main objections are with the HTML-CSS model itself. Adam was, as we all are, trying to make the best of this weird web dev situation. It is the discussion itself that is the most valuable imo.

Architecture is not a striving toward perfection, it's a collaborative process of finding heuristics that give good results based on real-world constraints.

Things to consider:

Utility classes do not do well when there are multiple states involved (as a simple case, consider :hover). Libraries that use the CSS utility classes do not follow the "Open-closed principle" or the "Dependency Inversion Principle" – depending on the mental model you use.

The term "functional CSS" is a misnomer, since the composition of styles happens at the HTML layer. Calling it "mashup CSS" would be far more accurate.

One huge problem in writing any software is figuring out how to make good decisions about where and how to compose smaller building blocks into bigger ones. Category Theory helps with many of these questions, but is far from sufficient to answer all of our questions. So it's quite valuable to discuss and try new things.


I’ve been using utility classes for a few years now. Some thoughts I’ve come up with:

For content heavy sites like ecommerce/marketing/blogs, I use pretty much utility classes exclusively. There usually isn’t much reuse of UI components on these types of sites so maintenance is much simpler compared to semantic classes. With semantic classes you’ll have a lot of one off styles.

I actually really enjoy writing sites like these since I can code a site start to finish without touching any CSS files. Using utility classes I probably finish 25%-50% faster than if I were to use semantic classes.

On more web app type things like admin panels, I use a mix of mostly semantic classes and a few utility classes. I only use utilities to make sure there aren’t a million different padding/margin/font size values.

In the earlier days of React I tried using all utility classes and it just felt like there was too much going on in the JSX. If you use utility classes, you know the class attribute can get pretty long - sometimes needing to be broken into 2 lines. The CSS tooling with Webpack has come a long way and solves a lot of the problems that all the utility class frameworks were trying to solve around 2015.


I really like how the author progressed from semantic to utility with examples. This approach made it really easy to understand the... uh... utility of utility classes.

The answer to anyone asking "how is this not inline styles", is in the article. With utility CSS, you don't use 100% of everything that CSS can do, and just pick the exact snippets you need for your theme.


What's always missing from these perennial CSS deep dives is that HTML already gives us a paradigm worth extending: generic constructs, used in domain specific contexts. Generic constructs are those that are devoid of domain specifics and can be used by HTML documents from other domains, e.g. links, paragraphs, buttons, tabs, and modals.

A link can refer to a user profile page or a news article. Both use the generic anchor "component", which comes from the wider universe of components applicable to most/all HTML docs. HTML: `<A class="user">`, CSS selector: `A.user`.

To extend this, a media card could represent a video or a book or a sidebar item. Both use the media card component's HTML structure but can be tweaked visually with CSS. The root element of the video media card would be `<DIV class="MediaCard video">` and would be identified with the selector `DIV.MediaCard.video`.

(PascalCase is arbitrary but I like that it harks to class naming conventions from OOP languages. You'd need some other naming conventions as well. I like `_title` for internal element class names, like private class members from OOP languages. Internal selectors would be built using the performant child combinator. Some of these patterns are more verbose than current alternatives, but it's also the minimum necessary to get crystal clarity around inherited and cascaded values. Preprocessor nesting makes this less painful. And `-highlight` for variants, because they resemble CLI switches. What about non-generic components? Those aren't "components" as defined here - they are simply higher-level HTML fragments, typically organized in source as an HTML template.)

This gives you two dimensions along which to flexibly organize things - the generic forms and the domain-specific applications, and should keep you from slipping down the slope to utility-dominant CSS.


The decision to make CSS libraries that are reusable across all parts of your application is spot on. Also it helps with theming, eg dark mode. To avoid listing tons of classes on each element, you can use something like less:

    .my-class {
      .utility-class-1;
      .utility-class-2;
    }
Reusable constants also help a lot.


On the dark mode thing, another way to do this is using css variables like --color-foreground for example. The whole site can have dynamic colour themes with minimal effort after that.


Question: I used CSS utility classes for building components in VueJS. The problem I ran into was that I wanted to apply classes only when certain conditions are met, i.e. style the component slightly differently based on its state. This caused me to check the condition repeatedly – once per class I want to apply. Is there a better way, e.g. applying all classes together after checking once?

TypeScript/JavaScript:

    export default Vue.extend({
        data() {
            return {
                isActive: false,
            };
        },
        computed: {
            componentClasses() {
                return ["margin-4", "padding-3", {
                    "color-red": this.isActive,
                    "font-size-30": this.isActive,
                    "font-weight-700": this.isActive,
                }];
            }
        }
    });


Add a class called "active" or similar, and write your css to target the element when that class is present.

    .element.active {
        color: red;
        font-size: 30px;
        font-weight: 700;
    }


Wouldn't it be possible to do: `["margin-4", "padding-3", ...(this.isActive ? ["color-red", "font-size-30", "font-weight-700"] : [])]`


the docs:

https://vuejs.org/v2/guide/class-and-style.html#Binding-HTML...

https://vuejs.org/v2/guide/class-and-style.html#Array-Syntax

In your template:

a) <div :class={active: isActive} />

b) <div :class="{isActive? 'active' : 'inactive' }"/>


B) is not valid. It needs to be wrapped in an Array, not an Object.


I feel like one thing that isn't addressed is the way designs are often made. Using utility classes requires that your designer is also aware of this and uses it. My experience is that most of the time this is not the case. You will end up having to make a lot of utility classes for single cases.


In terms of applying styles to pages / component hierarchies, I find it useful to think in terms of "global / baseline", "layout", and "utility classes". I wish layout were always viewed as a first-class concern, entirely separate from branding, colors, etc.

I think "Every-Layout" (https://every-layout.dev) makes an extremely compelling case for this approach. I'd love to see an example of a design system leveraging these beautiful, coherent, logically sound typography-based layouts, incorporated w/ modern component architecture, ready to be customized and themed. IMHO that'd be as transformative now as twitter bootstrap was when it first arrived.


Separating HTML from CSS has no basis, they are both concerned with the visual organisation of information. I feel that the real problem is not with CSS, but with how HTML forces you to jointly specify the semantic structure of data with its layout.


Anyone interested in a framework to produce functional CSS in SCSS/Sass, this is my project https://github.com/meerita/utilcss


I use a method called Context and Components. The idea being to build components, and to modify those components of they need to change base on context.

From my experience, reusable CSS is somewhat of a red herring. Maintainable and easily locates CSS is where you get productivity gains. If you don't know what you habe because there are hundreds of utility classes then what good is it. Also, if you are using utility classes why not just inline CSS? "red-border" is jusr as


CSS felt "solved" for me when the React team introduced inline styles. I've been using them ever since and it has made styling a breeze. I know people balk at inline styles, but I still haven't heard a convincing argument as to why they are a bad thing.


Lots of rule duplication and no pseudo-selector support with inline styles. If you like using inline styles, I think you'd like CSS-in-JS, because it has a similar feel when writing components with the benefit of deduped atomic classes as critical CSS + pseudo-selector support.


The mistake in my opinion is trying to write HTML and CSS that is a Swiss army knife of everything you'll need. Understand the problem at hand in the project you are working on first and write HTML and CSS to tackle that problem.


What I figured out over the years, is that CSS is not an afterthought. You need to engineer a solution for your design as you are building the html.


If you treat your CSS as a value-add, I've found you can often treat it that way. I've designed sites that work fine in text-based browsers, and then I stick CSS on it to make it look pretty on your phone.


Ended up looking a lot like Bootstrap to me.


Too much work.

A-b_c is so multiplicative


In my opinion the problem is that CSS apply styles and positioning to markup

Components have been a solved problem in desktop apps for decades

You have layout and styles applied to components positioned in the layout

What's really problematic is having a presentation layer that's split in layout and styles in the same context (CSS) while content and structure are both exposed in HTML

If we had layout in HTML and styling in CSS it would be easier to reason about it

HTML was born to give the document structure, layout is in the same league if you ask me, but then styles became the only way to lay out content, HTML lost its purpose of being the way to structure content in a meaningful way so you have the same HTML behaving diffentely with different layouts just because CSS can work on both of them

If footer meant "stuck at the foot of content no matter what the content is" we could have saved a lot of engineering hacks around making it reusable


This just seems primitive to me, use a UI framework and make ur life easier...


For me, CSS has been a Solved Problem™ for 5 years now.

If a website is small then I write plain HTML/CSS/JS in the old school way and all of these abstractions/systems are YAGNI.

If a website is large enough for these abstractions to matter then I'm using React with inline CSS. I get reusability and composition without a noticeable performance tradeoff. You can still build your components to decouple style from content where needed. Up to you.

Years later, no issues.


How do you handle responsive with inline in react? Case switching in js?


Media queries as normal.


How do you re-use this inline CSS?


Not the parent, but the approach I've seen in React is to treat inline CSS as objects like "{ fontWeight: "bold", color: "#000" }". So to re-use it, you can either put it in a constant or make a component that applies the styles to an element (and maybe takes props to override them).


I was asking because doing this just looks like normal CSS, where you define a class and use it in multiple places, only that it's in JS instead, so you still have all the "problems" mentioned in the article.


The major downside of reused inline CSS is when you have to do minor tweaks (where active manipulation in the browser devtools is by far easier to find the right values) and those inline styles are on the page multiple times. Editing one class's rules is significantly easier than all the repeated inline styles.


With the inline CSS approach, components are your reusable entities not CSS classes.


>where you define a class and use it in multiple places

If you're doing this in React, you should probably be reusing a component.


Under the hood it’s still CSS classes. You just define your CSS classes as element properties and the library takes care of the rest.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: