demosthenes.info

I’m Dudley Storey, the author of Pro CSS3 Animation. This is my blog, where I talk about web design and development with , and . To receive more information, including news, updates, and tips, you should follow me on Twitter or add me on Google+.

web developer guide

my books

Book cover of Pro CSS3 AnimationPro CSS3 Animation, Apress, 2013

my projects

A Sass color keyword system for designers. Replaces CSS defaults with improved hues and more memorable, relevant color names.

CSSslidy: an auto-generated #RWD image slider. 3.8K of JS, no JQuery. Drop in images, add a line of CSS. Done.

tipster.ioAutomatically provides local tipping customs and percentages for services anywhere.

Negating CSS Rules With :not

css / selectors

Estimated reading time: 2 minutes, 54 seconds

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

comments powered by Disqus

This site helps millions of visitors while remaining ad-free. For less than the price of a cup of coffee, you can help pay for bandwidth and server costs while encouraging further articles.