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.)
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.
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.
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.
- 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 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...
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.
- 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.
> 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.
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.)
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.
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.
What drawbacks?
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.).
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.
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.
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.
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
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.
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.
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.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
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.
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.
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.
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...
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.
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.