Wednesday, May 27, 2015

How CSS Specificity Works


Learning about CSS specificity will give you a deeper understanding of how CSS property values are resolved when two or more style rules match the same set of HTML elements.

Troubleshooting your CSS will become easier when you know how CSS specificity is calculated. For example, when there's a style rule that isn't working as intended, there's probably another style rule somewhere that's overriding it. You'll be able to quickly correct these issues if you're able to determine the specificity values of your selectors.

A good grasp of CSS specificity helps developers make smart choices whenever they're crafting their selectors. For example, some recommend that selector specificity be kept as low as possible because it can improve the efficiency and scalability of your CSS.

How It Works

If multiple CSS selectors are targeting the same set of HTML elements, and if the CSS selectors are trying to assign the same property/properties to the HTML elements, the selector with the highest specificity value will "win".

In other words, the most specific selector gets to assign its property values to the HTML elements.

It's easier to explain with an example.

Let's say this is our HTML:

<div class="container">
  <div id="main">
    <p>
      <a href="#">Link</a>
    </p>
  </div>
</div>

Below are five style rules that can target and assign a color to our <a> tag:

#main a {
  color: green;
}
p a {
  color: yellow;
}
.container #main a {
  color: pink;
}
div #main p a {
  color: orange;
}
a {
  color: red;
}

Since all five style rules are trying to assign a color property value to the <a> tag, the browser gets confused. Should the link be green, yellow, pink, orange or red? The browser needs a way to negotiate which color it should give to our <a> tag.

The way the browser makes the decision is by first calculating each selectors' specificity value. Then it sees which one has the highest specificity value. The highest value is the winner, and gets to set the color property value for our <a> tag.

Here are our five style rules again, in order from most specific to least specific.

Selector Specificity value
.container #main a 111
div #main p a 104
#main a 101
p a 2
a 1

So our <a> tag is pink.

If we remove .container #main a from our stylesheet, our link will become orange because the next most specific selector is div #main p a.

How did I know the specificity values for each selector? I calculated them.

Figuring Out Specificity Values

Understanding CSS selector specificity rules will all seem complicated at first.

For example, when I was still learning about CSS specificity, I had to write down my calculations on a piece of paper. Just like back in school when solving math problems.

It will take time and practice before this all becomes second nature.

OK, so let's actually go over how to calculate a selector's specificity value.

The method I'll show you for determining specificity values is from W3C's CSS specs.

The Basics

The specificity value is:

abc

Where:

  Total number of...

a

  • ID selectors

b

  • Class selectors
  • Attribute selectors
  • Pseudo-classes

c

  • Type selectors
  • Pseudo-elements

Visual illustration of CSS selector specificity groupings.

Example

#header .navbar li a:visited
a b c
1 2 2
Specificity value: 122

We'll go through more examples in greater detail in just a bit.

Selector Types

Before you can calculate specificity values, you'll need to be familiar with the types of CSS selectors.

Type Description Examples

ID selectors

They begin with a hash.

#id

#container

#main

#sidebar

Class selectors

They begin with a period.

.class

.navbar

.logo

.primary-color

Attribute selectors

They're in brackets.

[attribute]

[type="text"]

[rel="nofollow"]

[class^="cont"]

Pseudo-classes

They begin with a colon.

:pseudo-class

:visited

:hover

:active

Type selectors

They're the name of HTML elements.

div

ul

a

Pseudo-elements

They begin with two colons.

::pseudo-elements

::before

::after

::first-line

Special Rules

  • When calculating CSS specificity values, ignore the universal (*) selector.
  • The :not() pseudo-class (negation pseudo-class) only gets counted once, even if it contains another psuedo-class.
  • In case of a tie, the selector that's farthest down the stylesheet wins.

My Technique for Calculating Specificity Values

I'm terrible with numbers. So I had a tough time calculating specificity values in my head at first.

So whenever I needed to figure out a specificity value, I'd sketch out a sort of grid matrix on a piece of paper. Then I'd count each selector type and log them in the appropriate column. Figuring out the specificity value is a piece of cake after that.

CSS specificity grid

To double-check my work, I'll first count the number of selectors. Then I'll add up a + b + c. The total number of selectors must be equal to the sum of a, b and c. Otherwise, something went wrong.

For example, if the CSS specificity value is 122, then there should be five selectors.

a b c
1 2 2
Specificity value: 122
Double-check: 1 + 2 + 2 = 5 selectors

This technique is slow. And there are tons of tools out there that can do this work for us.

But I figured that if I wanted to understand this concept, I needed to do it slowly and manually. This allowed me to absorb the idea of CSS specificity fully.

CSS Specificity Examples

Let's go through some examples.

Example 1

div#container #main ul li

a b c
2 0 3
Specificity value: 203
Double-check: 2 + 0 + 3 = 5 selectors

Example 2

table tbody tr.even td.odd

a b c
0 2 4
Specificity value: 24
Double-check: 0 + 2 + 4 = 6 selectors

Example 3

.navbar ul.menu li#first a:not(:visited)

a b c
1 3 3
Specificity value: 133
Double-check: 1 + 3 + 3 = 7 selectors

Remember: Selectors inside the :not() pseudo-class are not counted.

Example 4

.footer #menu li#sponsor a[rel=nofollow]::before {
  content: "sponsored link: ";
}

a b c
2 2 3
Specificity value: 223
Double-check: 2 + 2 + 3 = 7 selectors

Quiz

You're not getting off that easy!

Here's a quick challenge for you. See how many questions you can get right.

1. What are the values of a, b and c in the following CSS selector?

.wrapper h1 a

See the answer

Answer

a b c
0 1 2

2. What's the specificity value of the following CSS selector?

.nav ul#menu li a

See the answer

Answer

a b c
1 1 3
Specificity value: 113

3. What's the specificity value of the CSS selector below?

.footer span a:not(:visited)

See the answer

Answer

a b c
0 2 2
Specificity value: 22

If you answered 23 for this question, remember that the :not() pseudo-class counts as 1 even if it contains another pseudo-class inside it.

So :not(:visited) is 1. Not 2.

4. Which letter does the universal selector get counted in? a, b or c?

See the answer

Answer

None

The universal selector should be ignored when calculating CSS specificity.

In the following example, <h1> tags will be green.

* { color: red; }
h1 { color: green; }

5. What's the font size of the <p> elements in the following example?

HTML

<body>
  <div class="main">
    <div class="intro">
      <p>Paragraph 1</p>
      <p>Paragraph 2</p>
      <p>Paragraph 3</p>
</div>
  </div>
</body>

CSS

body p {
  font-size: 16px;
}
div.main p {
  font-size: 18px;
}
div.intro p {
  font-size: 20px;
}

See the answer

Answer

20px

In this case, the last two selectors have the same specificity value.

div.main p
a b c
0 1 2
Specificity value: 12
div.intro p
a b c
0 1 2
Specificity value: 12

When there's a tie, the selector farthest down the stylesheet wins.

6. What's the color of the <h1> element in the following example?

HTML

<div class="container">
  <div class="post">
    <h1>My Blog Post Title</h1>
    <p>This is my blog post.</p>
  </div>
</div>

CSS

.container .post h1 {
  color: yellow;
}
.post h1 {
  color: red;
}
h1 {
  color: blue;
}
div.container div.post h1[class="heading"]  {
  color: green;
}

See the answer

Answer

Yellow

If you answered green -- you should know this was a trick question. (Sorry!)

When you do the math, the selector with the highest specificity value is the last selector: div.container div.post h1[class="heading"].

But... the h1 element doesn't have a class attribute of heading. So the last selector won't be able to select the h1 element in our example.

In the comments, tell us how well you did with this quiz.

References

Jacob Gube is the founder of Six Revisions. He’s a front-end developer. Connect with him on Twitter and Facebook.

The post How CSS Specificity Works appeared first on Six Revisions.


by Jacob Gube via Six Revisions

No comments:

Post a Comment