November 14th, 2007 - by Golgotha

Have you looked at other people’s style sheets lately? Were you baffled to find square brackets in the CSS code? If so, this article might be of interest to you.

What Does It Mean?

Curly braces should feel comfortable to any CSS author, since you cannot write any useful CSS without them. Regular parentheses should be fairly familiar, too, at least if you’ve used functional notations like background-image:url("/images/bg.png") or color:rgb(128, 128, 255). But square brackets?

The square brackets denote an attribute selector – a concept that was introduced in 1998 in CSS Level 2. An attribute selector modifies a simple selector by imposing an additional constraint on it. Does that sound like Greek to you? (Or like something other than Greek, for those of you who are, in fact, Greek?) Don’t worry, we’ll look at some examples in a short while.

Why Should You Even Bother?

But first, let’s address another question: If attribute selectors really are useful, why didn’t you already know about them? Or, to turn it around, since you’ve managed to get by without them, what’s the point of using them?

The reason you may not have heard about them is quite simple: Internet Explorer for Windows up to and including version 6 don’t support attribute selectors. Since the market share for those browser versions has been well above 80% until very recently, there hasn’t been much incentive for using attribute selectors in public-facing websites.

Version 7 of IE does support attribute selectors, though, and as more and more users upgrade from IE6, attribute selectors gain more interest.

What can those newfangled attribute selectors do then, that’s so useful that you should take some of your precious time to learn about them? The answer is that they allow you to do a lot of things that you hitherto have had no other way to achieve than to pollute your markup with class attributes.

How Does It Work?

As I said before, an attribute selector is a modifier on a simple selector. A simple selector, as you may recall, is made up by the following components:

  • a type selector, or an implicit or explicit universal selector
  • an optional ID selector
  • zero or more class selectors
  • zero or more pseudo-classes
  • zero or more attribute selectors

As we shall see, class selectors are really just a special case of attribute selectors.

Let’s look at some simple selectors and identify the different components.


This selector consists of a type selector and nothing else. It matches all elements whose element type is h1.


This selector appears to contain only an ID selector, but there’s a bit more here than meets the eye. The selector is actually *#nav, but it’s customary to omit the universal selector (*) when it’s implied. So there’s a universal selector and there’s an ID selector. The combination will match any element whose ID attribute has the exact value “nav”. Since IDs must be unique, this selector will match at most one element on the page. The implicit universal selector means that it will match this element regardless of what element type it has.


This selector consists of a type selector (a), a class selector (.external) and a pseudo-class (:visited). It matches some hypertext anchors (links) that the browser considers unvisited. Some? Yes, it only matches unvisited links that belong to the class external, i.e., whose class attribute contains that word.

All right, but what about those attribute selectors? There are four different flavors in CSS2, and another three that are defined in CSS3. All seven flavors are implemented by the latest versions of the mainstream browsers: IE7, Firefox, Opera and Safari. Note that IE6 is conspicuously absent from the list. It has no support at all for attribute selectors.

Let’s look at the different flavors, then.

Attribute Presence


This CSS2 attribute selector matches any element that has a title attribute specified. It doesn’t matter what value the title attribute has. As I’m sure you know by now, the selector is really *[title] with an implicit universal selector.

The attribute name is an identifier, so don’t put any quotation marks around it.

This may not appear to be very useful at first, but it actually does come in handy at times. Say that we want to provide a visual clue – a dotted bottom border – for any element that has a title attribute, to alert the reader that there’s an advisory title available which may be displayed as a tool-tip. We’ll also change the mouse cursor for those elements, to emphasise that the tool-tip is meant as some form of help to the reader.

  1. [title] {
  2.   border-bottom: 1px dotted;
  3.   cursor: help;
  4. }

Simple Attribute Value


This CSS2 attribute selector matches any input element whose type attribute has the value “submit”.

The attribute value can be specified as a string (enclosed in quotes) or as an identifier (no quotes). I generally prefer to use strings, myself.

The attribute name is case insensitive in HTML (including pretend-XHTML), but case sensitive in XML (including real XHTML). The attribute value may or may not be case sensitive in HTML, depending on the attribute. In real XHTML all attribute values are case sensitive.

We can use this to style form buttons without having to resort to a class:

  1. button,
  2. input[type="button"],
  3. input[type="reset"],
  4. input[type="submit"]
  5. {
  6.   background-color: #369;
  7.   color: #fff;
  8.   border: 2px solid;
  9.   border-color: #69c #036 #036 #69c;
  10. }

Note that [id="nav"] is not equivalent to #nav. The two selectors will match the same element in HTML or XHTML, but the latter has a much higher specificity than the former. (Specificity is a concept in the cascade, which decides which style rules take precedence over others in cases of conflict.)

Also, [id="nav"] matches an element with an attribute named “id”, whose value is “nav”. On the other hand, #nav matches an element whose ID attribute has the value “nav”. Does that sound like six of one and half a dozen of the other? It’s not, actually. An ID attribute is one whose type is declared to be ID in a DTD, XML Schema or similar. It doesn’t have to be named id at all. And an attribute named id doesn’t have to be an ID attribute. In HTML and XHTML, the only attribute of type ID happens to be named id, but that isn’t necessarily the case for XML applications in general.

Attribute List Value


This CSS2 attribute selector matches any paragraph element that belongs to the class literary. To be more specific, it matches paragraphs whose class attribute is a space-separated list of words, one of which is exactly equal to “literary”.

In other words, it will match all of the following paragraphs:

  1. <p class="literary">…</p>
  2. <p class="rather literary">…</p>
  3. <p class="literary you bet">…</p>
  4. <p class="somewhat literary sometimes">…</p>

But it doesn’t match either of the following paragraphs:

  1. <p class="quasi-literary">…</p>
  2. <p class="literaryrary">…</p>

“Hold on!” I hear you cry, “that’s just like p.literary, isn’t it?” Indeed it is. That’s why I said before that the class selector is really just a special case of an attribute selector. Class selectors only match class attributes, though, while the full syntax can be used for any space-separated attribute value, like td[headers~="price"].


This CSS2 attribute selector matches any element whose natural language is specified as English. To be more specific, it matches elements whose lang attribute is a hyphen-separated list of words beginning with “en”.

In other words, it will match all of the following elements:

  1. <div lang="en">…</div>
  2. <html lang="en-US">…</html>
  3. <blockquote lang="en-gb">…</blockquote>

But it doesn’t match an element with lang="sv" or lang="fr-be".

The CSS2.1 specification doesn’t state whether it’s allowed to use a value that contains a hyphen with this syntax (like [lang|="en-gb"]). Browsers generally accept it, though.

This flavor is similar – but not equivalent – to the :lang() pseudo-class selector, which isn’t supported by IE7 or Safari. The main difference is that the pseudo-class selector also matches elements that have inherited the language value from an ancestor element.

Partial Attribute Value


This CSS3 attribute selector matches link elements whose href attribute value starts with the string “http:”.


This CSS3 attribute selector matches image elements whose src attribute values ends with the string “.png”.


This CSS3 attribute selector matches any input element whose name attribute value contains the string “choice”.

Words of Warning

There must be no white space between a type selector (or universal selector) and an attribute selector meant to modify it. White space is the descendant combinator in CSS, so a [href] means a *[href], which is something quite different from a[href].

Some attributes in HTML and XHTML have default values: values which will apply even if the attribute isn’t even specified for an element. One example is the method attribute for form elements, which defaults to method="get" if omitted.

Attribute selectors in CSS are only guaranteed to match attributes and values that are explicitly specified. The selector form[method="get"] is not guaranteed to to match a form element with a start tag like <form action="vote.php">.

There are also some issues concerning value matching of minimized attributes. Attribute minimization is an SGML feature that is commonly supported for certain attributes in HTML (but not XHTML). A minimized attribute consists solely of the attribute value; the name and equals sign are omitted. For instance, <select multiple> is equivalent to <select multiple="multiple">.

Firefox and other Gecko browsers treat a minimized attribute as if it were specified as an empty string (multiple=""). Opera, on the other hand, treats it as if it were specified as multiple="true".

But What About IE6?

Right, this all sounds lovely, but IE6 and older don’t support attribute selectors and are still used by several million people. Isn’t this just an Lose Weight Exercise in futility?

It’s not. I wouldn’t have bothered writing this article if it were.

Of course we cannot rely on attribute selectors any time soon. What we can do, however, is to use them for progressive enhancement – adding value for modern browsers without causing any harm to older browsers.

My earlier example on how to style form buttons, for instance, shows one way to progressively enhance the aesthetics. In IE7, Firefox and Opera, buttons will be blue, while in IE6 they will have the default Windows look. Safari doesn’t allow styling of form controls, so it will retain the native look, too, although it does support attribute selectors.

The point is that we can use attribute selectors today. As the market share for IE5 and IE6 diminishes, attribute selectors will become more and more useful and our markup can become leaner and cleaner.

10 Responses to “Hip to Be Square”

1 Golgotha

Good article Tommy, I wasn’t aware of attribute selectors. Now, I just have to remember them and try to use them. The ‘Partial Attribute Value’ seems real cool – just gotta think of an area to use them?

2 John

Maybe I need to get more creative, but I still haven’t found a situation where I can use attribute selectors yet.

[…] Hip to be square – Are you baffled to find square brackets in other peoples CSS code? If so, you might find this of interest. […]

4 Golgotha

Probably a way to use it to tell if links are external or not?

You could also put a little musical note icon next to .mp3 links…

Just thinking out loud here…

Any other ideas?

5 Dan Schulz

Tommy, from what I’ve seen first hand, Safari 3 will allow developers to style form controls. Of course it’s still in beta, which means the vendor could change its mind at the last second, but at least it’s a promising development. 🙂

6 Paul OB

That has the attributes of a good article as usual Tommy 🙂


Great post! I will store it away for use sometime in the future. The only problem I foresee using this now is that IE 6 is still very popular. So I would end up having to create classes anyways to make the site look correct in IE 6. Sounds like double the work at the moment. Maybe one day when IE 6 is down to around 10% of the market share.

8 Links of Interest - CSS-Tricks

[…] a recent Search-This article: “Have you looked at other people’s style sheets lately? Were you baffled to find […]

9 Chris

Guess I’ll have to start using these soon, I have no reason NOT to!

[…] a longer list of ways to use this neat little trick, check out this post Hip to Be Square. There’s also a list of the different ways to search for values (like ^=) – which will be […]

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators

Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

You need to download the Flash player from Adobe

Other Sites