by

CSS Sorcery: Performing Magic with the Attribute Selector

Last week I was tackling a CSS problem when I suddenly stumbled into the magical world of the attribute selector. It’s not that I didn’t know about it, it’s that I didn’t know how powerful it was. And I wasn’t alone; Joey Shirley, a coworker, was dealing with a few issues that attribute selector magic solved, too. With all the magic we discovered through the attribute selector, we’re comfortable teasing this as straight-up CSS sorcery.

The Magic of the CSS Attribute Selector

The attribute selector is any attribute that’s inside of an HTML element. The attribute selector is part of CSS2.1 as well as being IE7 friendly, so everything you see here will work in all the major browsers. It falls into the same category as a class with a specificity of 0, 0, 1, 0. So let’s start with a basic example:

< a href="google.com">

a[href]{color: red}

Essentially, we’ve selected every <a> that has an attribute called href. It seems odd to do this, but you’ll see why. You remember that there’s more than one attribute for <a>, right?

<a href="#something"></a>

<a name="something"></a>

a[href] { color: red}

a[name] {color:inherit}

Magic Spell #1: Select Everything That Has a Class

Just this week I was fighting a rich text editor where, by default, it would wrap content with a <div> instead of a <p> when the user hit enter. So how can I apply appropriate margin, padding, and line-height to a div in my article, when my article may very well have other  legitimate <div>s that don’t need wayward margins?

article.content div {line-height: 150%, margin-top: 20px}

article.content div[class]{line-height: 1; margin-top: auto;}

I apply my styles to a div, and then use the attribute selector to select any divs that have any classes to undo that style.

Magic Spell #2: Give an ID a Lower Specificity

This one will make your brain hurt, but let’s suppose you need to style an ID with color, but maybe you don’t want a descendant of that element to inherit your color.  Back to the attribute selector:

section[id="sideBar"]{color: red}

section .box {color:blue}

I target a section with the attribute of “ID” which matches the word sideBar. But instead of a specificity of 0,1,0, 0, it gets 0,0,1,1

Magic Spell #3  – 4: Style every kind of link a little differently

The attribute selector would hardly be awesome if you could only select attributes exactly equal to something.There’s three major substring selectors that you can use pretty regularly which make things pretty awesome. Let’s go back to a[href] and see:

a[href^="http"]{}

the ^ means starts with. So we select any href starting with http. Very useful if you wanted to style a link to a directory a certain way. Also nifty if you want to distinguish between external links and links to a place on the page:

img[src^="/demos"]{border: 1px solid blue}
a[href^="#"]{text-decoration:none}

a[href$=".zip"]{}

The $ means ends with. So here, we’re selecting any href ending with .zip. Very handy for dealing with download links and inserting assistive text:

a[href$=".zip"]:after{content:"(zip)"}

Magic Spell #5-6: Style Images based on their alts and srcs

There’s two other substring selectors which don’t work in the context of href. These deal with words with hyphens or spaces and they were meant more for the alt or lang attributes.

img[alt~="Insurance"]{}

The ~ is a whitespace selector, so what we’re doing is looking for images with the alt attribute where the word “Insurance” is one of the words present. This is a great way of dealing with odd requirements like, “all insurance related images get an orange border”.

img[src|="-april"]{}

The | is a hyphen selector. In this case, we’re looking for any image with -april- somewhere in the source. If you’ve got a naming convention for your images that included the month, you can target  every image created in april. Of course, you could also use this for targeting every link with the word CSS in it.

a[href|="css"]:after{content:"CSS";}

Magic Spell #7: Target every class that contains a word

This was the one that sparked the blog post. A client wants a rich text editor for a small <article>. They have three groups of classes that can be applied to any element. Those classes were .larger1, larger2, .larger3, .smaller1, .smaller2, .subtext1, .subtext2. Those classes could be used on any HTML element. They could be used in any order. The margins going from larger to smaller were different from the smaller to larger.

At first thought, it seems like your only option is to write out all the permutations: .larger1 + .smaller1, .larger2 + smaller1, .larger3 + .smaller1, .larger1 + .smaller2....etc{}

Alas, the any selector to the rescue!

[class*="larger"] + [class*="smaller"] {}
In this case, the attribute just so happens to be the word “class”. And I’m using the * to basically say that it should contain the words larger and smaller, respectively. Keep in mind that while you do this, you’re giving each of these classes their original specificity.

Magic Spell #8: Deal with jQuery-injected Inline Styles

Inline styles are evil. Even though you avoid writing them, there’s nothing to stop jQuery from doing it. What can you do when jQuery decides your <div> deserves -webkit-weird-margin and you whole-heartedly disagree?

div[style*="-webkit-weird-margin"]{margin-left:corrected}

Yeah. That just happened. You selected an element —based on its styles. You styled based on styles. Go ahead and scrape the brain matter off of your screen. My mind was blown when my coworker came up with that one.

Style, after all, is just another attribute. And style contains values, like any other attribute. Just make sure that in IE, your CSS style selector is in all caps. There seems to be a peculiar bug on that issue.

And don’t forget that you could still chain together your style selectors:

<div style="color:red; padding-left:10em;">Hello World!</div>

div[style*="color:red"][style*="-left:10em"]{
margin-right: 10em;
}

A Review of the Attribute Selector

The big point of the attribute selector is that everything in the element except the name itself is an attribute. The ID, the Class, the alt, title, or src are just the most common ones. You can construct selectors based on whether they exist, whether they are exactly equal to something, or just partially equal. Essentially, the attribute selector fills lots of gaps left open from selecting on elements, classes, or IDs alone. Don’t go crazy with the attribute selector, but don’t forget that it’s got some powerful magic, either.