"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.
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.
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.
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.
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?
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.
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.
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.
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.
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.
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.
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:
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.
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 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.
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 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.
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.
>> 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
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.
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.
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.
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.
(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.
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.
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 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.
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.
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.
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.
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.
> (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`.
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.
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.
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.
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).
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).
107 comments
[ 3.0 ms ] story [ 158 ms ] thread"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.
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
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.
If you're doing this in React, you should probably be reusing a component.
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.
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.
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.
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.
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.
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!
.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.
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.
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...
"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.
I'm glad that backbone and jQuery apps are in my rear view mirror at this point.
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.
All that said, 100% agreed with your closing sentence! :)
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.
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
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.
1. https://styled-system.com/ 2. https://theme-ui.com/
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.
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.
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.
(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'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.
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 :/
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.
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`.
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.
Would you mantain .display--block? how? .color--red?
Product-card is not an utility, that's why it's a problem to maintain such classes.
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.
https://tailwindcss.com
A-b_c is so multiplicative