chan.dev

CSS-ing with Attribute Selectors

This post will be given as a lightning talk with lunch.dev. It's posted here so folks can read along.

Attribute selectors are my favorite selectors.

Their specificity is as low as a class. But unlike class — which only supports space-delimited strings with escaped special characters — attribute selectors give you complete control of your selection.

They're so powerful, you can even use them to surgically dissect a class selector.

In five minutes, I'll show you five ways to make practical use of attribute selectors.

First, the syntax #

Attribute selectors can target any attribute. href from an <a> tag, src from an <img> tag, aria- and data- attributes, you name it!

As syntax goes, attribute selectors wrap the name of the target attribute in brackets.

[href] { color: red };

This line turns anything with an href attribute red.

We have to be careful because other elements like <link> also have an href attribute. Combining attributes selectors with other selectors is a common for scoping intent.

a[href] { color: red };

While <links href> is display:none by default, it's a good practice to be explicit with attribute selectors.

Style attributes by value #

So how do we make attribute selectors useful?

We can use them to identify placeholder links by scoping our href selector to anchors with empty or "#" href attributes.

a[href=""],
a[href="#"]
{ color: red }

= selects an exact match for the attribute value. As shown above, we need to add a case for every exact match we want.

But there are other matching techniques.

We can match the beginning of a value as well. Let's add another case for insecure http links:

a[href=""],
a[href="#"],
a[href^="http:"]
{ color: red }

^= matches any value that start with the provided string.

Conversely, there's a $= matcher but I don't find it terribly useful. There can be any manner of appendages at the end of a URL.

Fortunately, there is a *= matcher to match a character set anywhere in the attribute value.

Let's use it to turn urls with a fragment identifier green:

a[href=""],
a[href="#"],
a[href^="http:"] { color: red }
+ a[href*="#"] { color: green }

Warning! This selector is inclusive of URLS that only have a pound value, too! Meaning are placeholder links have also turned green.

Not to fear, we can solve this by ensuring that the most specific rule is declared last:

+ a[href*="#"] { color: green }
a[href=""],
a[href="#"],
a[href^="http:"] { color: red }
- a[href*="#"] { color: green }

Style by state #

Styling by attribute means we can style by state as well. Consider the disabled attribute on an input. We can use that to style input[type="text"][disabled].

We can take this approach even further, using aria attributes. One aria label used for navs is aria-current. Let's use it to style mark and style the current page:

[aria-current="true"],
[aria-current="page"]
{
color: fuchsia;
}

Build your own language with data attributes #

Up to this point, we've only used standard element attributes. We can take that further with data attributes.

data is a an attribute prefix that may be used to safely create and utilize new attributes in your code.

Let's wrap all of our debugging selectors into a new data attribute selector: data-debug-links.

+ [data-debug-links] {
a[href*="#"] { color: green }

a[href=""],
a[href="#"],
a[href^="http:"] { color: red }
+ }

Now we can enable or disable this link debugging style by adding the data-dubug-links selector to a descendent.

There's so much more! #

Thanks for watching this quick intro to to data attribute selectors. There is so much more I wish I could share, but I can't.

If you'd like to learn how this can be used to build application stylesheets, checkout my post at chan.dev/avo.

And if you'd like to see the CSS framework I'm building with it, checkout chan.dev/colorway. And if you'd like to help me build it. Checkout my YouTube streaming channel at chan.dev/youtube