The Skinny on CSS Attribute Selectors

Avatar of Chris Coyier
Chris Coyier on (Updated on )

CSS has the ability to target HTML elements based on any one of their attributes. You probably already know about classes and IDs. Check out this bit of HTML:

<h2 id="title" class="magic" rel="friend">David Walsh</h2>

This single element has three attributes: ID, class, and rel. To select the element in CSS, you could use an ID selector (#title) or a clasmagicalector (.magic). But did you know you can select it based on that rel attribute as well? That is what is known as an attribute selector:

h2[rel="friend"] {
   /* woohoo! */
}

There is a lot more to attribute selectors though, so let’s look closer at all the different options and try to cover some “real world” scenarios on when they might be useful.

Attribute Exactly Equals Certain Value

In the example we used above, the attribute of the h2 element was “friend”. The CSS selector we wrote targeted that h2 element because it’s rel attribute was exactly “friend”. In other words, that equals sign means just just what you think it does… an exact match. See another basic example:

<h1 rel="external">Attribute Equals</h1>
h1[rel="external"] { color: red; }

A great real world example of this is styling a blogroll. Let’s say you had a list of links to friends sites like this:

<a href="http://perishablepress.com">Jeff Starr</a>
<a href="http://davidwalsh.name">David Walsh</a>
<a href="http://accidentalninja.net/">Richard Felix</a>

Then you wanted to style each link slightly differently. The traditional way would probably be to give each link a class name in which to target, but that requires additional markup which is always a nice thing to avoid (semantics and all). Another way might be to use :nth-child, but that requires their order to never change. This is the perfect use for attribute selectors… the links already have a unique attribute in which to target!

a[href="http://perishablepress.com"] { color: red; }

I believe the most common use of regular attribute selectors is on inputs. There are text, button, checkbox, file, hidden, image, password, radio, reset, and submit (did I miss any?). All of them are <input>’s, and all of them are very different. So doing something like input { padding: 10px; } is a bad idea most of the time. It’s very common to see things like:

input[type="text"] { padding: 3px; }
input[type="radio"] { float: left; }

It’s really the only way to get your hands on certain types of inputs without screwing up the others and without adding extra markup.

Note on Quotes: You can usually get away without using quotes in attribute selectors, like [type=radio], but the rules for omitting quotes are weird and inconsistent across actual browser implementations. So, best practice, just use quotes, like [type="radio"]. It’s safer and always works.

Attribute Contains Certain Value Somewhere

This is where it starts getting more interesting. The equals sign in attribute selectors may be prefaced by other characters which alter the meaning a bit. For example, “*=” means “match the following value anywhere in the attribute value.” Look at this example:

<h1 rel="xxxexternalxxx">Attribute Contains</h1>
h1[rel*="external"] { color: red; }

Remember that classes and ID’s are attributes too, and can be used with attribute selectors. So let’s say you were writing CSS for a site where you couldn’t control the markup and a sloppy developer had three DIVs you need to target:

<div id="post_1"></div>
<div id="post_two"></div>
<div id="third_post"></div>

You could select them all with:

div[id*="post"]  { color: red; }

Attribute Begins with Certain Value

<h1 rel="external-link yep">Attribute Begins</h1>
h1[rel^="external"] { color: red; }

A real-world example of using this would be, say, that you wanted to style every single link to your friends site different than other links. Doesn’t matter if you are linking to their homepage or any subpage, any links to them you want to style up.

a[href^="http://perishablepress.com"] { color: red; }

That will match a link to their homepage, but also any other subpages as well.

Attribute Ends with Certain Value

We can select based on how attribute values begin, why not end?

<h1 rel="friend external">Attribute Ends</h1>
h1[rel$="external"] { color: red; }

A good use case for these is labeling file download anchor links with icons based on what type of file they are. For example, PDF’s get a PDF icon and Word Documents get a Word icon:

a[href$=".pdf"] { background: url(icon-pdf.png) left center no-repeat; padding-left: 30px; }
a[href$=".doc"] { background: url(icon-doc.png) left center no-repeat; padding-left: 30px; }

Attribute is within Space Separated List

You probably already knew that you could apply multiple classes to elements right? Well if you do that, you can still use .class-name in CSS to target any one of them. Attribute selectors aren’t that easy. If your rel attribute has multiple values (e.g. values in a space-separated list) you’ll need to use “~=“:

<h1 rel="friend external sandwich">Attribute Space Separated</h1>
h1[rel~="external"] { color: red; }

You might be thinking, why would I use this when *= would also match this and be more versatile? Indeed it is more versatile, but it can be too versatile. This selector requires the spaces around the value where as *= would not. So if you had two elements one with rel=home friend-link and one with rel=home friend link you are going to need the space-separated selector to target the second one properly.

Attribute is the start of a Dash Separated List

This will select if the start of a dash-separated list of attribute values matches the selector.

<h1 rel="friend-external-sandwich">Attribute Dash Separated</h1>
h1[rel|="friend"] { color: red; }

Note that even though it matches based on the start of the selector, the entire first part of the string before the first dash needs to match. So in the above example, if the rel attribute was friend2-external-sandwich, it would not be a match while the ^= attribute selector would have.

Multiple Attribute Matches

Vital to note is that you can use multiple attribute selectors in the same selector, which requires all of them to match for the selector itself to match.

<h1 rel="handsome" title="Important note">Multiple Attributes</h1>
h1[rel="handsome"][title^="Important"] { color: red; }

Case-Insensitve Attribute Selectors

By default, the strings inside attribute selectors are case sensitive, but rather than matching multiple permutations of case in the case that you need to, you can pass a value that makes it case-insensitve:

/* Will match
<div data-state="open"></div>
<div data-state="Open"></div>
<div data-state="OPEN"></div>
<div data-state="oPeN"></div>
*/
[data-state="open" i] { }

Using Attribute in CSS

You can not only select via attributes, but use attributes in CSS content, like…

.el::before {
  content: attr(data-prefix) ": ";
}

Hopefully someday we’ll get support for types and fallback in the attr() function in CSS, like:

.el {
  /* <div class="el" data-font-size="18"> */
  font-size: attr(data-font-size px);

  /* <div class="el"> */
  font-size: attr(data-font-size px, 18px);
}

Browser Support

Every single example above works in all modern browsers: Safari, Chrome, Firefox, Opera, and IE. Internet Explorer has perfect support for all of these down to version 7, but zero support in 6. To test in your browser, see the test page. If the line/selector style is in red, it works.