A woman showing an open hand to the screen

Traditional web design has been about crafting a series of explicit declarations with inline, embedded and linked styles. Weaving through the different layers of stylesheets, these rules come together to form a final presentational ruleset. Undoing those rules or forming exceptions to them has been a difficult task, often relegated to “napalm the forest” CSS resets or the tedious reversal of property values. Until very recently, it’s been impossible to easily create a rule that says, “apply these values to everything but this element.”

The Power of No

CSS3 introduces the :not selector, which does exactly that. It’s such a reversal of normal web development practices that it can take a little getting used to.

A simple, if not terribly practical, example: let’s say that we wanted to italicize every paragraph on a page except content that was marked up with a class of .special. The traditional CSS approach would require two separate declarations: one setting up the general rule for italicizing every paragraph, and the other creating an exception to that rule:

p {
	font-style: italic;
	}
.special {
	font-style: normal;
	}

We could reduce this to a single rule by the use of the :not selector:

p:not(.special) {
	font-style: italic;
}

This would italicize every paragraph except those that had a class of .special.

You have to be careful in choosing what goes before the colon in the selector, as a poor choice can overwrite the rule and nullify any exceptions. For example, although you’ll find variations of this on many “tutorial sites” online, the following will not work:

:not(.special) {
	font-style: italic;
}

In that case, what’s presumed to be before the colon is a wildcard selector, which overwhelms the :not rule. That rule is equivalent to the following, which will also not work:

body:not(.special) {
	font-style: italic;
}

It’s too broad a rule: the body part of the selector will make everything italic, ignoring the portion of the rule that follows it.

The key, therefore, is being specific enough at the start so as not to overwhelm any :not rule that you make.

Practical Examples Of :not

Let’s say you wanted to make every internal, local link on your website have a different appearance to absolute, external links. For example, in the following code:

<p>The <a href="http://en.wikipedia.org/Peace_of_Westphalia">
Treaty of Westphalia</a> created a new system of political order in central 
Europe that was based upon the concept of a sovereign state, and established an 
international protocol forbidding interference in another nation's domestic affairs. 
The treaty signalled the end of the destructive wars that had ravaged Europe in the 
centuries before, and represented the triumph of national rule over the personal 
writ of the <a href="hapsburgs.html">Habsburg Emperors</a>. The treaty’s 
regulations became integral to the constitutional law of the 
<a href="holy-roman-empire.html">Holy Roman Empire</a>, and were the 
genesis of the modern nation-state concept.</p>

…we want to have the first, external link to have a different appearance from local links at the end of the paragraph.

While we can’t know anything about the internal links in advance, we can say that any external links will begin with http. To that end, we can create a general, default rule for links, then follow it with another rule for links that do not begin with http using a combination of :not and an attribute selector:

a {
	text-decoration: none;
	border-bottom: 1px dashed #333;
	color: #333;
}
a:not([href^="http"]) { 
	border-bottom: 2px solid #000;
}

Applying those rules will create the following result:

The Treaty of Westphalia created a new system of political order in central Europe that was based upon the concept of a sovereign state, and established an international protocol forbidding interference in another nation's domestic affairs. The treaty signaled the end of the destructive wars that had ravaged Europe in the centuries before, and represented the triumph of national rule over the personal writ of the Habsburg Emperors. The treaty’s regulations became integral to the constitutional law of the Holy Roman Empire, and were the genesis of the modern nation-state concept.

Note that the attribute selector still requires hard braces around it. Also note that the local links will still inherit presentational rules from first declaration that are not directly contradicted in the second.

Support For :not

There are many instances where :not is the most efficient method of dealing with exceptions to CSS rules, but it will sometimes require a lateral, even counter-intuitive, approach.

This shift in mental models is made slightly more difficult by the issue of browser support: while :not has been a feature of all modern browsers for a long time (Firefox 3.5+, Safari 3.2+, and Chrome since its inception) Internet Explorer has only supported it since version 9.  Gaining support for older versions of IE would typically mean adding a JavaScript polyfill such as selectivizr or IE9.js

Photograph by Richard Clark, used under a Creative Commons Attribution-NonCommercial 2.0 Generic license

Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.