dbohdan/classless-css: A list of classless CSS themes/frameworks with screenshots
A collection of stylesheets that don’t use class selectors. Think of them as alternatives to default user-agent stylesheets.
A collection of stylesheets that don’t use class selectors. Think of them as alternatives to default user-agent stylesheets.
A terrific tour of just some of the fantastic ways you can use :has()
in CSS.
The section on using it with sibling selectors blew my mind:
How often have you wanted to adjust the margins on a headline based on the element following it? Now it’s easy. This code allows us to select any h2 with a p immediately after it.
h2:has(+ p) { margin-bottom: 0; }
Amazing.
In two of my recent talks—In And Out Of Style and Design Principles For The Web—I finish by looking at three different components:
In each case you could use native HTML elements:
button
,select
, andinput type="date"
.Or you could use div
s with a whole bunch of JavaScript and ARIA.
In the case of a datepicker, I totally understand why you’d go for writing your own JavaScript and ARIA. The native HTML element is quite restricted, especially when it comes to styling.
In the case of a dropdown, it’s less clear-cut. Personally, I’d use a select
element. While it’s currently impossible to style the open state of a select
element, you can style the closed state with relative ease. That’s good enough for me.
Still, I can understand why that wouldn’t be good enough for some cases. If pixel-perfect consistency across platforms is a priority, then you’re going to have to break out the JavaScript and ARIA.
Personally, I think chasing pixel-perfect consistency across platforms isn’t even desirable, but I get it. I too would like to have more control over styling select
elements. That’s one of the reasons why the work being done by the Open UI group is so important.
But there’s one more component: a button.
Again, you could use the native button
element, or you could use a div
or a span
and add your own JavaScript and ARIA.
Now, in this case, I must admit that I just don’t get it. Why wouldn’t you just use the native button
element? It has no styling issues and the browser gives you all the interactivity and accessibility out of the box.
I’ve been trying to understand the mindset of a developer who wouldn’t use a native button
element. The easy answer would be that they’re just bad people, and dismiss them. But that would probably be lazy and inaccurate. Nobody sets out to make a website with poor performance or poor accessibility. And yet, by choosing not to use the native HTML element, that’s what’s likely to happen.
I think I might have finally figured out what might be going on in the mind of such a developer. I think the issue is one of control.
When I hear that there’s a native HTML element—like button
or select
—that comes with built-in behaviours around interaction and accessibility, I think “Great! That’s less work for me. I can just let the browser deal with it.” In other words, I relinquish control to the browser (though not entirely—I still want the styling to be under my control as much as possible).
But I now understand that someone else might hear that there’s a native HTML element—like button
or select
—that comes with built-in behaviours around interaction and accessibility, and think “Uh-oh! What if there unexpected side-effects of these built-in behaviours that might bite me on the ass?” In other words, they don’t trust the browsers enough to relinquish control.
I get it. I don’t agree. But I get it.
If your background is in computer science, then the ability to precisely predict how a programme will behave is a virtue. Any potential side-effects that aren’t within your control are undesirable. The only way to ensure that an interface will behave exactly as you want is to write it entirely from scratch, even if that means using more JavaScript and ARIA than is necessary.
But I don’t think it’s a great mindset for the web. The web is filled with uncertainties—browsers, devices, networks. You can’t possibly account for all of the possible variations. On the web, you have to relinquish some control.
Still, I’m glad that I now have a bit more insight into why someone would choose to attempt to retain control by using div
, JavaScript and ARIA. It’s not what I would do, but I think I understand the motivation a bit better now.
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 detailed proposal from Miriam for scoping CSS is well worth reading—it makes a lot of sense to me.
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.
Oh, this is smart! You can’t target pseudo-elements in JavaScript, but you can use custom properties as a proxy instead.
I love, love, love this experiment from Matt—messin’ around in websites!
If we, as a community, start to appreciate the complexity of writing CSS, perhaps we can ask for help instead of blaming the language when we’re confused or stuck. We might also stop looking down on CSS specialists.
While a handful of form controls can be easily styled by CSS, like the button element, most form controls fall into a bucket of either requiring hacky CSS or are still unable to be styled at all by CSS.
Despite form controls no longer taking a style or technical dependency on the operating system and using modern rendering technology from the browser, developers are still unable to style some of the most used form control elements such as
select
. The root of this problem lies in the way the specification was originally written for form controls back in 1995.
Stephanie goes back in time to tell the history of form controls on the web, and how that history has led to our current frustrations:
The current state of working with controls on the modern web is that countless developer hours are being lost to rewriting controls from scratch, as custom elements due to a lack of flexibility in customizability and extensibility of native form controls. This is a massive gap in the web platform and has been for years. Finally, something is being done about it.
Amen!
A handy tool for getting an overview of your site’s CSS:
CSS Stats provides analytics and visualizations for your stylesheets. This information can be used to improve consistency in your design, track performance of your app, and diagnose complex areas before it snowballs out of control.
I wrote a little something recently about using ARIA attributes as selectors in CSS. For me, one of the advantages is that because ARIA attributes are generally added via JavaScript, the corresponding CSS rules won’t kick in if something goes wrong with the JavaScript:
Generally, ARIA attributes—like
aria-hidden
—are added by JavaScript at runtime (rather than being hard-coded in the HTML).
But there’s one instance where I actually put the ARIA attribute directly in the HTML that gets sent from the server: aria-live
.
If you’re not familiar with it, aria-live
is extremely useful if you’ve got any dynamic updates on your page—via Ajax, for example. Let’s say you’ve got a bit of your site where filtered results will show up. Slap an aria-live
attribute on there with a value of “polite”:
<div aria-live="polite">
...dynamic content gets inserted here
</div>
You could instead provide a value of “assertive”, but you almost certainly don’t want to do that—it can be quite rude.
Anyway, on the face it, this looks like exactly the kind of ARIA attribute that should be added with JavaScript. After all, if there’s no JavaScript, there’ll be no dynamic updates.
But I picked up a handy lesson from Ire’s excellent post on using aria-live
:
Assistive technology will initially scan the document for instances of the aria-live attribute and keep track of elements that include it. This means that, if we want to notify users of a change within an element, we need to include the attribute in the original markup.
Good to know!
Sara tweeted something recently that resonated with me:
Also, Pro Tip: Using ARIA attributes as CSS hooks ensures your component will only look (and/or function) properly if said attributes are used in the HTML, which, in turn, ensures that they will always be added (otherwise, the component will obv. be broken)
Yes! I didn’t mention it when I wrote about accessible interactions but this is my preferred way of hooking up CSS and JavaScript interactions. Here’s old Codepen where you can see it in action:
[aria-hidden='true'] {
display: none;
}
In order for the functionality to work for everyone—screen reader users or not—I have to make sure that I’m toggling the value of aria-hidden
in my JavaScript.
There’s another advantage to this technique. Generally, ARIA attributes—like aria-hidden
—are added by JavaScript at runtime (rather than being hard-coded in the HTML). If something goes wrong with the JavaScript, the aria-hidden
value isn’t set to “true”, which means that the CSS never kicks in. So the default state is for content to be displayed. There’s no assumption that the JavaScript has to work in order for the CSS to make sense.
It’s almost as though accessibility and progressive enhancement are connected somehow…
An excellent and clear explanation of specificity in CSS.
I think this a solution worthy of Solomon. In this case, the Gordian knot is the select
element and its inevitable recreation in order to style it.
What if we instead deliver a native select by default and replace it with a more aesthetically pleasing one if possible? That’s where the “hybrid” select idea comes into action. It’s “hybrid” because it consists of two selects, showing the appropriate one at the right moment:
- A native select, visible and accessible by default
- A custom select, hidden until it’s safe to be interacted with a mouse
The implementation uses a genius combination of a hover
media query and an adjacent sibling selector in CSS. It has been tested on a number of device/platform/browser combinations but more tests are welcome!
What I love about this solution is that it satisfies the stakeholders insisting on a custom component but doesn’t abandon all the built-in accessibility that you get from native form controls.
I never thought of combining the datalist
element with input type="color"
—it’s pretty cool that it just works!
I can see this coming in very handy at Codebar—pop any CSS selector in here and get a plain English explanation of what it’s doing.
This is a wonderful interactive explanation of the way CSS hierarchy works—beautiful!
Everyone wants it, but it sure seems like no one is actively working on it.
Zach traces the earliest inklings of container queries to an old blog post of Andy’s—back when he was at Clearleft—called Responsive Containers:
For fun, here’s some made-up syntax (which Jeremy has dubbed ‘selector queries’)…