Here’s what I didn’t know about :where() - Manuel Matuzović
I feel like I’m starting to understand how the CSS :where
pseudo-class works and why it’s useful. The cogs are slowly turning in my brain.
I feel like I’m starting to understand how the CSS :where
pseudo-class works and why it’s useful. The cogs are slowly turning in my brain.
This is supposed to be a defence of utility classes …but it’s actually a great explanation of why classes in general are a great mechanism for styling.
I don’t think anyone has ever seriously suggested using inline styles—the actual disagreement is about how ludicrously rigid and wasteful the class names dictated by something like Tailwind are. When people criticise those classes they aren’t advocating for inline styles—they’re advocating for better class names and making more use of the power of the class selector in CSS, not less.
Anyway, if you removed every instance of the word “utility” from this article, it would still work.
This would be such a great addition to CSS—a parent/ancestor selector!
With the combined might of :has()
, :not()
, nth-child()
, and calc()
, CSS has become a powerful language for specifying rules to account for all kinds of situations.
Monica shares the little snippet of handy CSS she uses at the start of any project.
Some very smart ideas in here for resetting default browser styles, like only resetting lists that have classes applied to them:
ul[class],
ol[class] {
padding: 0;
}
I select only lists that do have a
class
attribute because if a plain ol’<ul>
or<ol>
gets used, I want it to look like a list. A lot of resets, including my previous ones, aggressively remove that.
This is a great explanation of the difference between the [lang]
and :lang
CSS selectors. I wouldn’t even have thought’ve the differences so this is really valuable to me.
In which Matthew disects a multiple choice quiz that uses CSS to do some clever logic, using the :checked
pseudo-class and counter-increment
.
Oh, and this is how he realised it wasn’t using JavaScript:
I have JavaScript disabled on my phone because a) it cuts out most of the ads, b) it cuts out lots of bandwidth and I have a limited data plan, and c) my battery lasts longer because it’s not processing tons of code to show me some text (cough, Medium).
A really interesting proposal from Lea that would allow CSS authors to make full use of selectors but without increasing specificity. Great thoughts in the comments too.
Adam Wathan wrote an article recently called CSS Utility Classes and “Separation of Concerns”. In it, he documents his journey through different ways of thinking about CSS. A lot of it is really familiar.
Phase 1: “Semantic” CSS
Ah, yes! If you’ve been in the game for a while then this will be familiar to you. The days when we used to strive to keep our class names to a minimum and use names that described the content. But, as Adam points out:
My markup wasn’t concerned with styling decisions, but my CSS was very concerned with my markup structure.
Phase 2: Decoupling styles from structure
This is the work pioneered by Nicole with OOCSS, and followed later by methodologies like BEM and SMACSS.
This felt like a huge improvement to me. My markup was still “semantic” and didn’t contain any styling decisions, and now my CSS felt decoupled from my markup structure, with the added bonus of avoiding unnecessary selector specificity.
Amen!
But then Adam talks about the issues when you have two visually similar components that are semantically very different. He shows a few possible solutions and asks this excellent question:
For the project you’re working on, what would be more valuable: restyleable HTML, or reusable CSS?
For many projects reusable CSS is the goal. But not all projects. On the Code For America project, the HTML needed to be as clean as possible, even if that meant more brittle CSS.
Phase 3: Content-agnostic CSS components
Naming things is hard:
The more a component does, or the more specific a component is, the harder it is to reuse.
Adam offers some good advice on naming things for maximum reusability. It’s all good stuff, and this would be the point at which I would stop. At this point there’s a nice balance between reusability, readability, and semantic meaning.
But Adam goes further…
Phase 4: Content-agnostic components + utility classes
Okay. The occasional utility class (for alignment and clearing) can be very handy. This is definitely the point to stop though, right?
Phase 5: Utility-first CSS
Oh God, no!
Once this clicked for me, it wasn’t long before I had built out a whole suite of utility classes for common visual tweaks I needed, things like:
- Text sizes, colors, and weights
- Border colors, widths, and positions
- Background colors
- Flexbox utilities
- Padding and margin helpers
If one drink feels good, then ten drinks must be better, right?
At this point there is no benefit to even having an external stylesheet. You may as well use inline styles. Ah, but Adam has anticipated this and counters with this difference between inline styles and having utility classes for everything:
You can’t just pick any value want; you have to choose from a curated list.
Right. But that isn’t a technical solution, it’s a cultural one. You could just as easily have a curated list of allowed inline style properties and values. If you are in an environment where people won’t simply create a new utility class every time they want to style something, then you are also in an environment where people won’t create new inline style combinations every time they want to style something.
I think Adam has hit on something important here, but it’s not about utility classes. His suggestion of “utility-first CSS” will only work if the vocabulary is strictly adhered to. For that to work, everyone touching the code needs to understand the system and respect the boundaries of it. That understanding and respect is far, far more important than any particular way of structuring HTML and CSS. No technical solution can replace that sort of agreement …not even slapping !important
on every declaration to make them immutable
.
I very much appreciate the efforts that people have put into coming up with great naming systems and methodologies, even the ones I don’t necessarily agree with. They’re all aiming to make that overlap of HTML and CSS less painful. But the really hard problem is where people overlap.
The older I get, the more every problem in tech seems to be a matter of getting humans to work together effectively, and not tech itself.
— Laurie Voss (@seldo) August 23, 2017
A great one-page intro to microformats (h-card in particular), complete with a parser that exports JSON. Bookmark this for future reference.
I’m crap at object-oriented programming (probably because I don’t get get enough practice), but I’ve had a quick read through this and it looks like a nice clear primer. I shall return and peruse in more depth next time I’m trying to remember how to do all this class-based stuff.
I understand how bloated and non-reusable code can get when a dozen people who don’t talk to each other work on it over a period of years. I don’t believe the problem is the principle of semantic markup or the cascade in CSS. I believe the problem is a dozen people working on something without talking to each other.
Depending on how you’re currently structuring your CSS and class attributes, web components might not make all that much of a difference to your workflow.
Ensure that your class names never go out of sync with your style declarations with this one simple trick:
Take any CSS rule you want to apply, replace : by -, and dots by -dot-, and you get the name of the corresponding universal css classname.
The only thing missing is immutability, so I would suggest also putting !important
after each declaration in the CSS. Voila! No more specificity battles.
I like CSS pseudo-classes. They come in handy for adding little enhancements to interfaces based on interaction.
Take the form-related pseudo-classes, for example: :valid
, :invalid
, :required
, :in-range
, and many more.
Let’s say I want to adjust the appearance of an element based on whether it has been filled in correctly. I might have an input
element like this:
<input type="email" required>
Then I can write some CSS to put green border on it once it meets the minimum requirements for validity:
input:valid {
border: 1px solid green;
}
That works, but somewhat annoyingly, the appearance will change while the user is still typing in the field (as soon as the user types an @ symbol, the border goes green). That can be distracting, or downright annoying.
I only want to display the green border when the input is valid and the field is not focused. Luckily for me, those last two words (“not focused”) map nicely to some more pseudo-classes: not
and focus
:
input:not(:focus):valid {
border: 1px solid green;
}
If I want to get really fancy, I could display an icon next to form fields that have been filled in. But to do that, I’d need more than a pseudo-class; I’d need a pseudo-element, like :after
input:not(:focus):valid::after {
content: '✓';
}
…except that won’t work. It turns out that you can’t add generated content to replaced elements like form fields. I’d have to add a regular element into my markup, like this:
<input type="email" required>
<span></span>
So I could style it with:
input:not(:focus):valid + span::after {
content: '✓';
}
But that feels icky.
Update: See this clever flexbox technique by Kitty Giraudel for a potential solution.
Funny because it’s true:
The thing I regret the most is how my class addiction affected my relationship with HTML.
This nifty place in Brighton is just down the street from me:
Our classes allow kids to get creative with exciting, cutting-edge technology and software.
I love that Tantek is as pedantic as I am …although I don’t think “pedantic” is exactly the right word.
This is a well-reasoned, thoughtful article on avoiding class names in CSS …but I don’t agree with it. That said, perhaps there’s a reasonable middle ground to be found between this extreme stance and the opposite (but in some ways just as extreme) stance of OOCSS.
The thought process behind trying to abstract class names that are used for layout in responsive designs (and can therefore refer to different widths depending on the context). Here, the author settles on letters. In the past, I’ve approached the same kind of abstraction by using latinised names.