Things Worth Noting About CSS Attribute Selectors

The main reason CSS attribute selectors have been avoided up to this point is their complete lack of support in IE6. But since IE6′s market share is continuing to slowly but steadily decline, it’s becoming safer to use them.

I’m not going to go through the basics of CSS attribute selectors and their syntax. There are some pretty good resources explaining them, which I’ll link to at the bottom of this post. So if you don’t have at least some grasp of what this CSS feature is all about, please check those out first.

This article will go a little further and focus on some interesting facts and bugs surrounding attribute selectors that you may not have known.

You Don’t Have to Specify an Actual HTML Element

Normally when you see examples showing attribute selectors in action with accompanying code, you’ll see something like this:

a[style] {
	color: red;
}

The example above contains a very specific target: HTML anchor elements (represented by <a>) that contain the exact attribute “style”, with one or more values present. But that specificity is not required. You can also do this:

[style] {
	color: red;
}

That’s perfectly valid CSS, and allows you to use the attribute selector in a more general way.

UPDATE: As rightly pointed out by Ricardo in the comments, when you don’t reference an HTML element in the selector, you’re essentially using the universal selector (so evidently, [style] is the same as * [style]). For performance reasons, this kind of filtering should be avoided.

“id” Is Not Equal to #id

Suppose you have the following HTML:

<div id="box"></div>

You can target that element via CSS in many ways, and two of those ways directly involve the id element. The obvious way is:

#box {
	width: 400px;
}

But you can also target the element quite specifically using an attribute selector, like this:

[id="box"] {
	width: 400px;
}

Both methods shown above will target the box just fine. But according to CSS specificity rules, an ID selector has more weight than an attribute selector, so be careful when using the attribute selector in this way, as it’s not as specific as it appears.

To be honest, I think it would be next-to-impossible to have a situation that required that you use the attribute selector to target an element via its ID. But I think it’s good to keep this kind of thing in mind because it reminds us that CSS does have a natural cascade wherein element targeting is decided based on specificity.

You Can’t Target User Agent Attributes

HTML elements sometimes have default attributes with a default value. For example, take the following HTML:

<form action="index.html">
<fieldset>
<input />
</fieldset>
</form>

Although the above HTML form code is woefully lacking any substance, it’s perfectly valid HTML5 and XHTML strict. Two missing attribute/value pairs are of particular note: The method="get" on the <form> element, and type="text" on the <input> element. The defaults for those attributes are the ones I just mentioned. Although the user agent will serve those attributes and their respective values as defaults, and they’ll even appear in your developer tools as existing values from the user agent, you can’t target them using attribute selectors.

So, if you intend on relying on attribute selectors, be sure to explicitly declare in your HTML the exact attributes and values required for you to target them in all supporting browsers.

IE7 Can’t Target the “style” Attribute

Although IE7 does technically offer support for attribute selectors, its support is buggy, and it will not recognize the style attribute. This is quite a drag, since one of the reasons you might want to use attribute selectors is to target elements that have inline styles. Using a combination of the attribute selector and the !important declaration, in most supporting browsers you could override inline styles. But this will fail in IE7.

Of course, if you know what elements are going to have inline styles, then you could just use a different selector to override those styles, and it will work in IE7, but it won’t work if you use the style attribute in your selector.

This will fail in IE7:

a[style] {
	color: blue !important;
}

Value-less Attributes Can Be Tricky Across Browsers

Since HTML5 allows minified attributes, or attributes with no value (like disabled instead of the redundant disabled="disabled"), it will become more common to see this style of coding. But it should be noted that you may get different results in some browsers if you actually target the attribute with the implied specified value in the CSS.

For example, if you had an input element with the disabled attribute set to the implied “disabled” value, you might target it with the attribute selector in a number of ways, as shown below:

[disabled=disabled] {
	color: #ccc;
}

[disabled="disabled"] {
	color: #ccc;
}

[disabled] {
	color: #ccc;
}

[disabled=""] {
	color: #ccc;
}

input[disabled] {
	color: #ccc;
}

To give you an idea of how the above (all of which is valid CSS) behaves in different browsers:

  • Opera 9.2 will accept all of the above examples, and will also accept disabled="true" to target the element in question
  • IE7 will only match the element in question when using the last syntax example
  • IE8 will not accept the fourth example with the empty quotes, and in my limited testing even caused some funky behaviour (I’ll have to do some further testing and see if that’s a weird unknown bug or something)

Case Sensitivity is Tricky Across Browsers

If an attribute has a case-sensitive value (as in the case of ID values), Firefox up to version 3.5 (in some cases) and Safari up to version 4 (in all cases) will target the value while ignoring the case. So in other words, in Safari 4, if you had and element with an ID of “myValue”, you could target it using any of the following selectors:

[id="myvalue"] {
	width: 500px;
}

[id="MYVALUE"] {
	width: 500px;
}

[id="myVALUE"] {
	width: 500px;
}

[id="Myvalue"] {
	width: 500px;
}

None of the above selectors should target the element in question, but evidently they do. As mentioned, this behaviour also occurs in certain versions of Firefox, but not as often as it does in Safari.

CSS3 Adds New Attribute Selectors

In CSS3, the following CSS selectors are now available:

The “starts with…” attribute selector, shown below, is identified by the characters ^=

a[href^="http:"] {
	color: blue;
}

The “ends with…” attribute selector, shown below, is identified by the characters $=

a[href$=".pdf"] {
	color: red;
}

The “contains…” attribute selector, shown below, is identified by the characters *=

div[class*="primary"] {
	clear: both;
}

Interestingly, while the bugs mentioned earlier still apply to these newer attribute selectors, the support for them across browsers is the same as the CSS 2.1 attribute selectors. So that means all attribute selectors (bugs aside) are supported in IE7+, Firefox 3.0+, Safari 1.3+, Chrome 2+, and Opera 9.2+. That’s not too bad.

Can They Be Used?

As always, with buggy stuff that isn’t completely cross-browser, just do the usual:

  • Consider potential maintainability and performance issues
  • Consider your known/potential audience for the project in question
  • Test like your plane’s going down

Some Links for the Basics and More

Advertise Here

16 Responses

  1. Maciej Baron:

    “(…)To be honest, I think it would be next-to-impossible to have a situation that required that you use the attribute selector to target an element via its ID.”

    How about targeting elements that have an ID starting or ending with a given string of characters?

  2. Very good information.

  3. HB:

    Nice article, I’ve been using the regular attribute selector for a while (because really, forget IE6), but I didn’t realize support for ^= and $= was just as prevalent.

    As for [id=...], I could see it being useful to manage specificity in a javascript-heavy app. Sometimes you may end up with a lot of IDs to use as unique javascript hooks, but it’s nice to be able to target those elements in CSS without their IDs hogging specificity, since “[id=widget7] .handle” has the same weight as “.widget .handle”

  4. Great guide – especially the ie7 tip

  5. Opus:

    I think most people might never bother with an attribute selector for an element that has a style hook, but it’s also good that the option is there. It also depends on specificity, as you already said.

    Weird how there’s no way to use UA defined attributes, but I guess it’ll keep us sharp. ;)

    I love the selectors new to CSS3. We’ve been given much more versatility!

  6. Nice overview on CSS attribute selectors tricks!

  7. Ricardo:

    When not using an element, id or class selector, you’re essentially using *[attribute]. As we all know the * selector is the worst performant of all in CSS, so the first example should be disencouraged. It has no special value anyway.

    The same applies to [id="x"]. You’re grabbing all the elements (*) and filtering by ID instead of using the engine’s shortcut for #IDs.

    • This is a good point, thanks. I’ll add a note about that when I get a chance.

      • I know it’s an old post but do remember that selectos are read right-to-left so although * can be expensive when doing somthing like #selector .class *, it’s not that bad when you’re actually wanting to look at everything.

        Although i’ll admit I stumbled on this post while double checking known performance problems for the contains selector [foo*="bar"] as i’m using it to match common modifiers for some of my of my BEM style CSS.

        • Joolss:

          @Phunky, I can’t find a source at the moment, but doesn’t the CSS parser go right-to-left in regards to the individual, comma-separated selectors, but left-to-right on each selector? In this case, the rules [style], a[style] and *[style] would be single selectors.

  8. Good post bro keep them coming

  9. Thanks for sharing bro keep it up

  10. Very good information, here is a basic study of attribiute selector
    http://www.corelangs.com/css/basics/ad-selectors.html
    manly

  11. Pankti:

    Can you please Provide solution for IE 11. i want to change disable text box color using CSS.
    But none of below solution is working.

    
    [disabled=disabled] {  
        color: #ccc;  
    }  
      
    [disabled="disabled"] {  
        color: #ccc;  
    }  
      
    [disabled] {  
        color: #ccc;  
    }  
      
    [disabled=""] {  
        color: #ccc;  
    }  
      
    input[disabled] {  
        color: #ccc;  
    }  
    

    My input tag is

    • Are you trying to change the “color” or the “background color”? You have “color” there, which is for the text color, which is probably why you don’t see a change. This works in IE11:

      http://jsbin.com/joyodipe/1/edit

      • Pankti:

        Thank you so much for quick reply.

        But i want to change text color however using selectors i can change background color but not text color.

        Style is

        input[disabled] {
        color: red !important;
        }

        My input element is
        input tage with these properties class="riTextBox riRead TextBox DisableTextBox" readonly="readonly" disabled="disabled"

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field. If you use keywords, your comment will be deleted, or your name will be replaced with the alias from your email address. No foul language, please. Thank you for cooperating.

Instructions for code snippets: Wrap inline code in <code> tags; wrap blocks of code in <pre> and <code> tags. When you want your HTML to display on the page in a code snippet inside of <code> tags, make sure you use &lt; and &gt; instead of < and >, otherwise your code will be eaten by pink unicorns.