Stylist Logo

The Basics of Specificity

This entry is part 4 of 15 in the series Stylist

ABSTRACT

Now that we have a bunch of styles assigned, we can start using them, and demonstrating how specificity works. We’ll build on the list of markup elements that we defined in example 11, and add styles to them.

REVIEW

We’ll use local styles, but defined in the <head> section of the page, in order to make it easier to show. As I’ve mentioned before, you’ll probably want to define your styles in a separate .css file. It makes for easier-to-read files and easier maintenance.

Let’s first review our markup:

<div class="container_class" id="main_container">
	<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
	<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
	<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
	<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
	<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
	<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
	<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
</div>

I took the liberty of showing just the contents of the <body> section of the file, in order to keep things simple.

APPLYING SPECIFICITY

Each of the <div> elements above has various ways in which specificity can be defined.

The first element has no class or ID, so it will be affected by a generalized <div> CSS class, like so:

div { font-style:italic }

This will affect every one of the <div> elements in the <body> section:

Example 12

<html>
	<head>
		<title>Example 12</title>
		<style type="text/css">
			div { font-style:italic }
		</style>
	</head>
	<body>
		<div class="container_class" id="main_container">
			<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
			<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
			<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
			<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
			<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
			<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
			<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
		</div>
	</body>
</html>

You will notice that all of the text now displays as italic. This is because the “general” rule we defined in the <head> applies to all <div> elements.

We can test that by adding a non-<div> element, like so:

Example 13

<html>
	<head>
		<title>Example 13</title>
		<style type="text/css">
			div { font-style:italic }
		</style>
	</head>
	<body>
		<div class="container_class" id="main_container">
			<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
			<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
			<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
			<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
			<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
			<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
			<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
		</div>
		<p>This isn&apos;t a &lt;div&gt; element. It is a &lt;p&gt; element.</p>
	</body>
</html>

Notice that the text in the <p> element is not italicized. That’s because the rule only applies to all <div> elements, not other types of elements, such as <p> elements.

Now, we’ll make the <p> element a child of the <div> element:

Example 14

<html>
	<head>
		<title>Example 14</title>
		<style type="text/css">
			div { font-style:italic }
		</style>
	</head>
	<body>
		<div class="container_class" id="main_container">
			<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
			<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
			<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
			<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
			<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
			<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
			<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
			<p>This isn&apos;t a &lt;div&gt; element. It is a &lt;p&gt; element.</p>
		</div>
	</body>
</html>

Hey! Why does the <p> element display as italic? I thought the rule only applies to <div> elements?

Good question. Glad you asked. When we apply style to markup elements, the style applies to the element’s node value, and the node values of all child elements of that element. When we moved the <p> element into the <div> element, its node value (contents) became subject to rules applied to the <div>.

Got that? It means that the text inside the <p> element is now being affected by the rule we applied to <div> elements, because we made the <p> element a child element of a <div> element.

Now, it’s pretty easy to override the rule we made, because it has such a low specificity. Let’s make our <p> element non-italic, even though it’s a child of a <div> element:

Example 15

<html>
	<head>
		<title>Example 15</title>
		<style type="text/css">
			div { font-style:italic }
			p { font-style:normal }
		</style>
	</head>
	<body>
		<div class="container_class" id="main_container">
			<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
			<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
			<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
			<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
			<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
			<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
			<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
			<p>This isn&apos;t a &lt;div&gt; element. It is a &lt;p&gt; element.</p>
		</div>
	</body>
</html>

Now the <p> element displays normally. However, it was corrected by a “general” rule, which shouldn’t be any more specific that the rule it overrode. Why did it work?

Maybe it was because we declared the “p” rule after the “div” rule making the “p” rule just a wee bit more specific than the “div” rule. CSS rules are evaluated consecutively, so ones that are declared later trump earlier rules, if the other specificity factors are even.

What Ees Thees “Specificity Factors” of Which You Speak?

Glad you asked. This is the heart of determining specificity. Here are the basic factors that go into determining the specificity of a CSS rule:

  1. Element Parent Rules (i.e. Rules applied to the containers of the element)
  2. Element Name (i.e. “all <div> elements”)
  3. Element Class (i.e. class=”some_class”)
  4. Element ID (i.e. id=”some_unique_id”)

They are evaluated in the order displayed above. The higher the number, the more specific the rule.

These can be combined in certain ways to monkey around with specificity. There are also a couple of modifiers that can make a difference, all other things being equal:

  1. Taking the parent elements into account when specifying the rule.
  2. The order in which rules are defined (later ones trump earlier ones)

In example 15, it looks like it was this second modifier that made the difference. Classes and rules that come after other classes and rules have greater specificity.

If I’m right, then switching the order should make the <p> element’s node vale display as italic, right?

Example 16

<html>
	<head>
		<title>Example 16</title>
		<style type="text/css">
			p { font-style:normal }
			div { font-style:italic }
		</style>
	</head>
	<body>
		<div class="container_class" id="main_container">
			<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
			<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
			<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
			<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
			<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
			<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
			<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
			<p>This isn&apos;t a &lt;div&gt; element. It is a &lt;p&gt; element.</p>
		</div>
	</body>
</html>

Wrong. It still displays normal. What happened?

The fact is that the specificity factors aren’t even. The “div” rule applies to <div> elements, and the node values of <div> elements and the node values of child elements.

The “p” rule is more specific for <p> elements than it is for child element node values of <div> elements. The <p> element is affected by the “p” rule, which is specificity level 2, and that overrides the style applied to its parent <div> element, which is specificity level 1 for the <p> element.

Now do you see why CSS design is difficult? These types of “gotchas” pop out all over the place.

Using the example above, let’s illustrate examples of each type of rule:

Example 17

<html>
	<head>
		<title>Example 17</title>
		<style type="text/css">
			div { color:#900 }
			.special_class {color:#090}
			#special_id {color:#c60}
		</style>
	</head>
	<body>
		<div class="container_class" id="main_container">
			<div>This &lt;div&gt; has no specific assignment. It is just a &lt;div&gt;.</div>
			<div class="special_class">This &lt;div&gt; has a class assignment. It is a "special_class" &lt;div&gt;.</div>
			<div class="special_class second_class">This &lt;div&gt; has two class assignments. It is a "special_class" and a "second_class" &lt;div&gt;.</div>
			<div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>
			<div style="font-weight:bold">This &lt;div&gt; has inline style. It displays its node value as bold text.</div>
			<div class="special_class" id="second_id">This &lt;div&gt; has a class assignment and an ID. It is a "special_class" &lt;div&gt;, and its ID is "second_id".</div>
			<div class="special_class" id="third_id" style="font-weight:bold">This &lt;div&gt; has a class assignment, an ID and inline style. It is a "special_class" &lt;div&gt;, its ID is "third_id" and it will display its node value as bold.</div>
			<p>This isn&apos;t a &lt;div&gt; element. It is a &lt;p&gt; element.</p>
		</div>
	</body>
</html>

Now, let’s catalog what we did, and explain the results that we got:

The first rule: div { color:#900 } says that “All <div> elements will be displayed as red.” It is specificity level 2 for <div> elements, and specificity level 1 for child elements of <div> elements.

The next rule: .special_class {color:#090} says that “Any element that has a class of ‘special_class’ will be displayed as green.” This is specificity level 3 for any element with a class attribute set to “special_class”, and specificity level 1 for child elements of elements with a class set to “special_class”.

Most of the <div> elements have this class, so most of them display as green.

The third rule is aimed at any element with its id attribute set to a value of “special_id”: #special_id {color:#c60}

There is only one element that has the ID set to “special_id”: <div id="special_id">This &lt;div&gt; has an ID. It is "special_id".</div>

That displays as orange.

The <p> element displays as red, because it does not have a rule that says it should display as anything else.

Next, we’ll start to play around with the markup and styles.