33

CSS Fundamentals: The Cascade & Specificity

 4 years ago
source link: https://medium.com/swlh/css-fundamentals-the-cascade-specificity-b499b58e90a8
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

In this article, we’re going to review some of the most fundamental concepts of CSS. The cascade (the ‘C’ in C ascading S tyle S heets), we’ll also look at the role of inheritance and finally, we’ll learn about how specificity works.

Let’s dive right in.

What is the Cascade?

It’s the ‘C’ in CSS. So conceptually it lies at the very core of CSS. It can be defined as the algorithm that determines the properties applied to each element on the page.

It’ll make this determination, based on a number of rules such as inheritance, specificity , importance , & rule order within our stylesheet.

It also ensures we have no conflicts. So if we had 2 or more competing CSS rules for the same property on the same element. It would determine which one needs to be applied.

So keeping the cascade in mind, let’s now look at the rules it uses to make these decisions!

Inheritance

CSS inheritance works on a property by property basis.

When you set properties on a selector in CSS, they are either inherited by all the children of that selector or not — it depends on the property!

The reason this happens is that some properties make sense to be inheritable, whilst others do not.

Take fonts, for example, you don’t need to apply font-family to every single tag on your page. You can simply set the body tag font, and every child will inherit it.

Whereas the background-color property, makes little sense to be inherited. So the children of the element that this is applied to, will not inherit this property.

You can easily check if a particular CSS property is inheritable here . Just look up the property in question & if it's inheritable by default, it’ll indicate “Inherited: yes” , if not it will state “Inherited: no” .

Inheritance exists to help us write our CSS much more concisely, as we reduce repetition by not having to explicitly set each property in every single child element.

Enforcing property Inheritance

In the case where you want to force a property to inherit to its children when it’s not inheritable by default — you can do so quite simply!

In the child selector, you set the property value to inherit .

For example:

body {
   background-color: red;
}p {
   background-color: inherit;
}

Avoiding property Inheritance

The reverse is also possible. You can use the revert keyword to revert the property to not inherit from its parent. In this case, the value is reverted to the original value the browser gave it in its default stylesheet.

In practice, this is rarely used, and most of the time you’ll just set another value for the property, which will overwrite that inherited value.

Initial & Unset

It’s also worth mentioning that when working with inheritance, we can also use the initial & unset keywords.

initial
unset

Let’s now move on to another rule that is considered by the cascade: Specificity.

Specificity

When a particular element is targeted by multiple CSS rules — this is where specificity comes into play!

For example, let’s take a look at the following element:

<p class="surname">
  Smith
</p>

We could have one rule selecting our class:

.surname {
  color: red;
}

And another rule targeting p , which sets the color to a different value:

p {
  color: green;
}

And we could even have another rule targeting p.surname .

So which rule will take precedence over the others, and why?

This is where the rules of specificity come into consideration. The more specific rule will always win. And if two or more rules have the same specificity, the one that appears last wins.

Specificity is in fact determined by a calculation. The more specific a CSS style is, the higher point value it accrues, and the likelier it is to be present on the element’s style.

How we calculate specificity

Knowing how specificity works will greatly reduce any frustrations we’re likely to have with CSS. If we’ve applied a style to an element that isn’t taking effect — in all likelihood the culprit is that our selector is not specific enough!

To perform the calculation, think of 4 slots with each of them starting at 0: 0 0 0 0 . The slot at the left is the most important, and the rightmost one is the least important.

So 1 0 0 0 is higher than 0 1 0 0 .

Slot 1

The first slot, the rightmost one ( 0 0 0 0 ), is the least important.

We increase this value when we have a type selector . A type is a tag name . If you have more than one type selector in the rule, you increment the value stored in this slot.

For example:

p {} 		 /* 0 0 0 1 */
span {} 	 /* 0 0 0 1 */
p span {} 	 /* 0 0 0 2 */
p > span {}      /* 0 0 0 2 */
div p > span {}  /* 0 0 0 3 */

Slot 2

The second slot is incremented by 3 things:

  • Class selectors
  • Pseudo-class selectors
  • Attribute selectors

Every time a rule is one of the above, we increment the value of the second column from the right.

For example:

.name {}	    /* 0 0 1 0 */
.users .name {}	    /* 0 0 2 0 */
[href$='.doc'] {}   /* 0 0 1 0 */
:hover {}	    /* 0 0 1 0 */

And naturally, slot 2 selectors can be combined with slot 1 selectors:

div .name {}	        /* 0 0 1 1 */
a[href$='.doc'] {}      /* 0 0 1 1 */
.pictures img:hover {}  /* 0 0 2 1 */

There’s also a bit of a hack you can use with classes, by repeating the class name to increase the specificity:

.name {}	    /* 0 0 1 0 */
.name.name {}       /* 0 0 2 0 */
.name.name.name {}  /* 0 0 3 0 */

Slot 3

Slot 3 holds the most important thing that can affect your CSS specificity: an id .

Every element can have an id attribute assigned, and we can use that in our stylesheet to target the element.

For example:

#name {}	/* 0 1 0 0 */
.user #name {}	/* 0 1 1 0 */
#name span {}	/* 0 1 0 1 */

Slot 4

Slot 4 is affected by inline styles . Any inline style will have precedence over any rule defined in an external CSS file, or inside the style tag in the page header.

For example:

<p style="color: red">Test</p>  /* 1 0 0 0 */

Even if any other rule in the CSS defines the color, this inline style rule is going to be applied. Except for one case — if !important is used, which could be thought of as filling “slot 5”.

Although nowadays importance is mostly shunned in favor of using a more specific selector. Let’s take a look!

Importance

Our specificity does not matter if a rule ends with !important :

p {
font-size: 18px !important;
}

This rule will take precedence over any rule with more specificity.

So adding !important in a CSS rule is going to make that rule more important than any other rule, according to the specificity rules.

Note: Importance seems like a magic way to ensure you’re style is applied, however, it can become a nightmare to work with down the line. As the only way, you can override !important is with another !important . Thus you can really make a mess of your CSS when you go down that path.

Using Specificity

A great rule of thumb is to only use the amount of specificity you need, but no more. This way, you can craft other selectors to overwrite the rules set by preceding rules without too many difficulties.

Conclusion

And that’s it! We’ve covered the fundamentals of the CSS Cascade, Inheritance & Specificity. A solid understanding of these fundamentals is something that many programmers miss. Knowing the basics removes a lot of the potential for frustration with CSS — and will no doubt make you a stronger coder in the long run!

I hope you found this article useful. You canfollow me on Medium. I’m also on Twitter . Feel free to leave any questions in the comments below. I’ll be glad to help out.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK