4

I am trying to understand specificity in CSS.

My current understanding is that specificity is very similar to inheritance, but in some way more specifically defined.

Mozilla Specificity Definition:

Specificity is the means by which browsers decide which CSS property values are the most relevant to an element and, therefore, will be applied. Specificity is based on the matching rules which are composed of CSS selectors of different sorts.

The current task is:

Refactor the CSS declarations for .active a and .copyright so that the !important rule can be removed.

CSS:

.main li a {
  color: #7ab2c1;
}
.active a {
  color: #826c55 !important;
}
.primary p {
  font-size: 12px;
}
.copyright {
  font-size: 10px !important;
}

And relevant HTML:

<nav class="main">
  <ul class="group">
    <li class="active"><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>

[...]

<footer class="primary">
      <p><a href="#">Sign up</a> for our newsletter, it's a racket!</p>
      <p class="copyright">Copyright &copy; Sven's Snowshoe Emporium. All Rights Reserved.</p>
</footer>

Can anyone guide me through the process of refactoring in such a way that helps me to grasp the fundamental concepts?

Peter David Carter
  • 2,180
  • 6
  • 21
  • 38
  • 1
    some general guidance: http://stackoverflow.com/a/35657646/3597276 – Michael Benjamin Jun 08 '16 at 20:49
  • 1
    *Refactor the CSS* , could be made based on your actual markup ... Share your HTML too – DaniP Jun 08 '16 at 20:53
  • 1
    @DaniP Ok. Just having a look and trying to [MCVE] it. E.g. cut it down without losing any of it. – Peter David Carter Jun 08 '16 at 20:56
  • 1
    You probably also want to look into CSS specificity calculators, like http://specificity.keegan.st/. It shows you how the specificity for any rule is calculated. – j08691 Jun 08 '16 at 21:09
  • 1
    Or here it's more simple to understand https://css-tricks.com/specifics-on-css-specificity/ – DaniP Jun 08 '16 at 21:10
  • 1
    First, think of *specificity* as meaning *priority*. The rules describe how to determine which rules take priority over other rules. – RBarryYoung Jun 08 '16 at 21:16
  • 1
    @RBarryYoung - Specificity is only one part of CSS priority. CSS priority is determined by the *cascade* of which specificity is just one component. – Alohci Jun 08 '16 at 21:49
  • Pretty much grasped it now, but after I've napped I'll look over all this info more thoroughly as it seems there may be quite a lot more to this... – Peter David Carter Jun 08 '16 at 22:23
  • 1
    @PeterDavidCarter-Poulsen - take your time. The mechanics of specificity are relatively easy to grasp. The *philosophy* - why specificity is a great design if you use it well, but a minefield if you don't - will take longer and much practice to get clear. – Alohci Jun 08 '16 at 23:39
  • 1
    It should be noted that "Refactor the CSS declarations for .active a and .copyright so that the !important rule can be removed." is an impossible task. A CSS declaration is the `property:value` pair inside the curly brackets. There's no way to change those such that the `!important` flag can be removed. The task should read "Refactor the CSS *rules* for .active a and .copyright so that the !important *flag* can be removed." – Alohci Jun 09 '16 at 00:10

4 Answers4

2

A class has a specificity of 10. An element has a specificity of 1.

Therefore, in the first instance:

  • the .main li a selector has a specificity of 12.
  • the .active a selector has a specificity of 11

Because they both target the same element, and the former has a higher specificity, the latter loses the battle to style the element.

In the second instance:

  • the .primary p selector has a specificity of 11.
  • the .copyright selector has a specificity of 10.

Again, because they both target the same element, and the former has a higher specificity, the latter loses the battle to style the element.

The !important annotation trumps all specificity. Hence, with that applied, .active a and .copyright re-take the elements.

If you want to remove !important, which would be the right thing to do as it's not necessary here, you can instead boost the specificity of the selectors.

An ID has a specificity of 100. So that can quickly move a selector up in priority.

Here are some examples:

.main li a      { color: #7ab2c1; }  /* previous winner; specificity 12 */
.main .active a { color: #ff0000; }  /* added class selector; specificity now 21 */
.primary p      { font-size: 12px; } /* previous winner; specificity 11 */
#copyright      { font-size: 8px;} /* switched to ID selector; specificity now 100 */
<nav class="main">
  <ul class="group">
    <li class="active"><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
<footer class="primary">
  <p><a href="#">Sign up</a> for our newsletter, it's a racket!</p>
  <p id="copyright">Copyright &copy; Sven's Snowshoe Emporium.
                    All Rights Reserved.</p>
</footer>

References:

Community
  • 1
  • 1
Michael Benjamin
  • 265,915
  • 79
  • 461
  • 583
  • 1
    Another good article on where specificity values come from: http://sixrevisions.com/css/css-specificity/ – Jeff Jenkins Jun 08 '16 at 21:17
  • I ended up finishing the challenge another way (seemed like cheating otherwise), but your answer ended up being one I referred back to most, so that's the one I accepted. Thank you. – Peter David Carter Jun 08 '16 at 22:20
  • @PeterDavidCarter-Poulsen, you're welcome. Glad I could help. With regard to "cheating", that would be the use of `!important`. Using selectors to boost specificity is a proper method. Good luck! – Michael Benjamin Jun 08 '16 at 23:06
1

You can change .copyright to a lot of things, but one of the following two seems the most logical to me:

.primary .copyright

or

p.copyright

What specificity is supposed to do, is look at an how specific your selector is, and deciding whether that rule should be followed.

  • CSS inside a media-query is more specific than the exact same CSS outside of it
  • Ids are more specific than classes
  • html body section p.special.selected:hover is more specific than p
  • Etc.

There are a whole bunch of rules that give your selector 'points' with every part. The more points, the more specific. After a lot of practice, you can write over-ruling CSS without even thinking about it.

Gust van de Wal
  • 4,519
  • 18
  • 39
  • Thanks, I'm going to take a look through the other resources linked in the comments, take the time to read through this answer, probably have a nap or even a proper sleep (it's fairly late in the UK), then come back to things after and see what I can work out, then hopefully I'll be able to accept an answer. – Peter David Carter Jun 08 '16 at 21:13
1

In this example, you're trying to make the selectors that are setting properties that you wish to override less specific. That way, you won't have as far to go to override them.

Let's take a look at

.main li a {
  color: #7ab2c1;
}
.active a {
  color: #826c55 !important;
}

.main li a is pretty darn specific: it's selecting all anchor tags within an li within an element with main in its className. How could you make that less specific? Based on your markup,

.main a {
  color: #7ab2c1;
}

is less specific, is still applicable, and would be overridden by your .active selector as it has the same specificity (a class + an element). nav a or even plain old a would work as selectors, too, depending on how much (or how little) you want that rule to apply.

Now, let's look at the footer.

.primary p {
  font-size: 12px;
}
.copyright {
  font-size: 10px !important;
}

How can we make that first selector less specific? What about changing it to

p {
  font-size: 12px;
}

Your .copyright selector is more specific and would override it (however, all p elements everywhere will have a default font-size of 12px and that may not be what you want).

We could limit that to the footer:

.primary {
  font-size: 12px;
}

That would limit the font-size property to just footer elements and would allow you to override it with the subsequent rule.

In general, you're attempting to refactor based on specificity values to make the things you want to override have the smallest specificity values possible. You do this by using the most general selectors that would apply the rules you want without applying those rules to elements that should not have them.

Peter David Carter
  • 2,180
  • 6
  • 21
  • 38
ajm
  • 18,564
  • 3
  • 30
  • 34
  • 1
    Thanks, I'm going to take a look through the other resources linked in the comments, take the time to read through this answer, probably have a nap or even a proper sleep (it's fairly late in the UK), then come back to things after and see what I can work out, then hopefully I'll be able to accept an answer. – Peter David Carter Jun 08 '16 at 21:17
  • 1
    The CSS Tricks article on specificity that has been posted a number of times in a number of answers should put you on the right path. – ajm Jun 08 '16 at 21:19
1

Basically using html tags as a selector adds a small amount of specificity, using a class adds a medium amount of specificity, using an ID adds a large amount of specificity, and using !important trumps all.

The .main li a selector uses 1 class + 2 html tags while .active a only uses 1 class + 1 html tag. The former has more specificity than the latter, but using !important overrides this and forces the latter style to apply.

To remove the need for !important you either need to a) reduce the amount of specificity in .main li a or b) increase the amount of specificity in .active a. I would recommend option a and changing the selector to .main a. This carries the same amount of specificity as .active a, but due to the cascading nature of CSS, the style that appears last will get applied, no !important needed.

Same principle in the 2nd scenario - .primary p has 1 class + 1 html tag, while .copyright only has 1 class. In this case, I'd go with option b and change the selector to .primary .copyright. 2 classes have more specificity than 1 class + 1 html tag and the style will apply without needing !important.

Final CSS:

.main a {
  color: #7ab2c1;
}
.active a {
  color: #826c55;
}
.primary p {
  font-size: 12px;
}
.primary .copyright {
  font-size: 10px;
}
Peter David Carter
  • 2,180
  • 6
  • 21
  • 38
JeffreyPia
  • 411
  • 2
  • 5
  • Thanks, I'm going to take a look through the other resources linked in the comments, take the time to read through this answer, probably have a nap or even a proper sleep (it's fairly late in the UK), then come back to things after and see what I can work out, then hopefully I'll be able to accept an answer. – Peter David Carter Jun 08 '16 at 21:24