Cascade and inheritance

Esta tradução está incompleta. Por favor, ajude a traduzir este artigo.

In a previous article, we got into the various CSS selectors. At some point in your work, you'll find yourself in the situation where multiple CSS rules will have selectors matching the same element. In such cases, which CSS rule "wins", and ends up being the one that is finally applied to the element? This is controlled by a mechanism called the Cascade; this is also related to inheritance (elements will take some property values from their parents, but not others.) In this article we will define what the cascade is, what specificity is, what importance is, and how properties inherit from different rules.

Prerequisites: Basic computer literacy, basic software installed, basic knowledge of working with files, HTML basics (study Introduction to HTML), and an idea of How CSS works (study the previous articles in this module.)
Objective: To learn about the cascade and specificity, and how inheritance works in CSS.

The final style for an element can be specified in many different places, which can interact in complex ways. This complex interaction makes CSS powerful, but it can also make it confusing and difficult to debug. This article aims to clear up some of that complexity; if you don't understand it immediately, don't worry — this is one of the hardest parts of CSS theory to comprehend. You are advised to give it a try now, but then keep it nearby as a handy guide to return to when questions about the cascade and inheritance come up.

The cascade

CSS is an acronym of Cascading Style Sheets, which indicates that the notion of the cascade is important. At its most basic level it indicates that the order of CSS rules matter, but it's more complex than that. What selectors win out in the cascade depends on three factors (these are listed in order of weight — earlier ones will overrule later ones):

  1. Importance
  2. Specificity
  3. Source order

Importance

In CSS, there is a special piece of syntax you can use to make sure that a certain rule will always win over all others: !important. Adding this to the end of a property value will give it superpowers.

Let's look at an example:

<p class="better">This is a paragraph.</p>
<p class="better" id="winning">One selector to rule them all!</p>
#winning {
  background-color: red;
  border: 1px solid black;
}

.better {
  background-color: gray;
  border: none !important;
}

p {
  background-color: blue;
  color: white;
  padding: 5px;
}

This produces the following:

Let's walk through this to see what's happening.

  1. You'll see that the third rule's color and padding values have been applied, but the background-color hasn't. Why? Really all three should surely apply, because rules later in the source order generally override earlier rules.
  2. However, The rules above it win, because IDs/class selectors have higher specificity than element selectors (you'll learn more about this in the next section.)
  3. Both elements have a class of better, but the 2nd one has an id of winning too. Since IDs have an even higher specificity than classes (you can only have one element with each unique ID on a page, but many elements with the same class — ID selectors are very specific in what they target), the red background color and the 1 pixel black border should both be applied to the 2nd element, with the first element getting the gray background color, and no border, as specified by the class.
  4. The 2nd element does get the red background color, but no border. Why? Because of the !important declaration in the second rule — including this after border: none means that this declaration will win over the border value in the previous rule, even though the ID has higher specificity.

Note: The only way to override this !important declaration would be to include another !important declaration of the same specificity, later in the source order.

It is useful to know that !important exists so that you know what it is when you come across it in other people's code. BUT. We would advise you to never use it unless you absolutely have to. One situation in which you may have to use it is when you are working on a CMS where you can't edit the core CSS modules, and you really want to override a style that can't be overridden in any other way. But really, don't use it if you can avoid it. Because !important changes the way the cascade normally works, it can make debugging CSS problems really hard to work out, especially in a large stylesheet.

It is also useful to note that the importance of a CSS declaration depends on what stylesheet it is specified in — it is possible for users to set custom stylesheets to override the developer's styles, for example the user might be visually impaired, and want to set the font size on all web pages they visit to be double the normal size to allow for easier reading.

Conflicting declarations will be applied in the following order, with later ones overriding earlier ones:

  1. Declarations in user agent style sheets (e.g. the browser's default styles, used when no other styling is set).
  2. Normal declarations in user style sheets (custom styles set by a user).
  3. Normal declarations in author style sheets (these are the styles set by us, the web developers).
  4. Important declarations in author style sheets
  5. Important declarations in user style sheets

It makes sense for web developers' stylesheets to override user stylesheets, so the design can be kept as intended, but sometimes users have good reasons to override web developer styles, as mentioned above — this can be achieved by using !Important in their rules.

Specificity

Specificity is basically a measure of how specific a selector is — how many elements it could match. As shown in the example seen above, element selectors have low specificity. Class selectors have a higher specificity, so will win against element selectors. ID selectors have an even higher specificity, so will win against class selectors. The only way to win against an ID selector is to use !important.

The amount of specificity a selector has is measured using four different values (or components), which can be thought of as thousands, hundreds, tens and ones — four single digits in four columns:

  1. Thousands: Score one in this column if the matching selector is inside a <style> element or the declaration is inside a style attribute (such declarations don't have selectors, so their specificity is always simply 1000.) Otherwise 0.
  2. Hundreds: Score one in this column for each ID selector contained inside the overall selector.
  3. Tens: Score one in this column for each class selector, attribute selector, or pseudo-class contained inside the overall selector.
  4. Ones: Score one in this column for each element selector or pseudo-element contained inside the overall selector.

Note: Universal selector (*), combinators (+, >, ~, ' ') and negation pseudo-class (:not) have no effect on specificity.

The following table shows a few isolated examples to get you in the mood. Try going through these, and making sure you understand why they have the specificity that we have given them.

Selector Thousands Hundreds Tens Ones Total specificity
h1 0 0 0 1 0001
#important 0 1 0 0 0100
h1 + p::first-letter 0 0 0 3 0003
li > a[href=*"en-US"] > .inline-warning 0 0 2 2 0022
#important div > div > a:hover, inside a <style> element 1 1 1 3 1113

Note: If multiple selectors have the same importance and specificity, which selector wins is decided by which comes later in the Source order.

Before we move on, let's look at an example in action. Here is the HTML we are going to use:

<div id="outer" class="container">
  <div id="inner" class="container">
    <ul>
      <li class="nav"><a href="#">One</a></li>
      <li class="nav"><a href="#">Two</a></li>
    </ul>
  </div>
</div>

And here is the CSS for the example:

/* specificity: 0101 */
#outer a {
  background-color: red;
}

/* specificity: 0201 */
#outer #inner a {
  background-color: blue;
}

/* specificity: 0104 */
#outer div ul li a {
  color: yellow;
}

/* specificity: 0113 */
#outer div ul .nav a {
  color: white;
}

/* specificity: 0024 */
div div li:nth-child(2) a:hover {
  border: 10px solid black;
}

/* specificity: 0023 */
div li:nth-child(2) a:hover {
  border: 10px dashed black;
}

/* specificity: 0033 */
div div .nav:nth-child(2) a:hover {
  border: 10px double black;
}

a {
  display: inline-block;
  line-height: 40px;
  font-size: 20px;
  text-decoration: none;
  text-align: center;
  width: 200px;
  margin-bottom: 10px;
}

ul {
  padding: 0;
}

li {
  list-style-type: none;
}

The result we get from this code is as follows:

So what's going on here? First of all, we are only interested in the first seven rules of this example, and as you'll notice, we have included their specificity values in a comment before each one.

  • The first two selectors are competing over the styling of the link's background color — the second one wins and makes the background color blue because it has an extra ID selector in the chain: its specificity is 201 versus 101.
  • The third and fourth selectors are competing over the styling of the link's text color — the second one wins and makes the text white because although it has one less element selector, the missing selector is swapped out for a class selector, which is worth ten rather than one. So the winning specificity is 113 versus 104.
  • Selectors 5–7 are competing over the styling of the link's border when hovered. Selector six clearly loses to five with a specificity of 23 versus 24 — it has one fewer element selectors in the chain. Selector seven, however, beats both five and six — it has the same number of sub-selectors in the chain as five, but an element has been swapped out for a class selector. So the winning specificity is 33 versus 23 and 24.

Note: If you haven't already, review all the selectors one more time, just to make sure you understand why the specificity values have been awarded as shown.

Source order

 

Como mencionado acima, se vários seletores concorrentes têm a mesma importância e especificidade, o terceiro fator que entra em jogo para ajudar a decidir qual regra vence é a ordem de origem - regras posteriores ganharão regras anteriores. Por exemplo:

p {
  color: blue;
}

/* This rule will win over the first one */
p {
  color: red;
}

 

Enquanto neste exemplo a primeira regra vence porque a ordem da fonte é anulada pela especificidade:

/* This rule will win */
.footnote {
  color: blue;
}

p {
  color: red;
}


Uma nota sobre a mistura de regra

 

Uma coisa que você deve ter em mente ao considerar toda essa teoria em cascata, e quais estilos são aplicados sobre outros estilos, é que tudo isso acontece no nível da propriedade - as propriedades substituem outras propriedades, mas você não recebe regras inteiras substituindo outras regras. Quando várias regras CSS correspondem ao mesmo elemento, todas elas são aplicadas a esse elemento. Só depois disso são quaisquer propriedades conflitantes avaliadas para ver quais estilos individuais ganharão sobre os outros.

 

Vejamos um exemplo. Primeiro, alguns HTML:

<p>I'm <strong>important</strong></p>

 

E agora alguns CSS para estilo com:

/* specificity: 0002 */
p strong {
  background-color: khaki;
  color: green;
}

/* specificity: 0001 */
strong {
  text-decoration: underline;
  color: red;
}

Resultado:

 

Neste exemplo, devido à sua especificidade, a propriedade color da primeira regra substitui a propriedade de cor da segunda regra. No entanto, tanto a background-color da primeira regra e text-decoration da segunda regra são aplicadas ao <strong> elemento. Você também notará que o texto desse elemento está em negrito: isso vem da folha de estilos padrão dos navegadores.

Inheritance

 

A herança CSS é a última peça que precisamos investigar para obter todas as informações e entender qual estilo é aplicado a um elemento. A idéia é que alguns valores de propriedade aplicados a um elemento serão herdados pelos filhos desse elemento, e outros não.

  • For example, it makes sense for font-family and color to be inherited, as that makes it easy for you to set a site-wide base font by applying a font-family to the <html> element; you can then override the fonts on individual elements where needed. It would be really annoying to have to set the base font separately on every element.
  • As another example, it makes sense for margin, padding, border, and background-image to NOT be inherited. Imagine the styling/layout mess that would occur if you set these properties on a container element and had them inherited by every single child element, and then had to unset them all on each individual element!

Which properties are inherited by default and which aren't is largely down to common sense. If you want to be sure however, you can consult the CSS Reference — each separate property page starts off with a summary table including various details about that element, including whether it is inherited or not.

Controle de herança

 

CSS fornece três valores especiais para lidar com herança:

  • inherit : Esse valor define o valor de propriedade aplicado a um elemento selecionado para ser igual ao de seu elemento pai.
  • initial : Esse valor define o valor de propriedade aplicado a um elemento selecionado para ser igual ao valor definido para esse elemento na folha de estilos padrão do navegador. Se nenhum valor for definido pela folha de estilos padrão do navegador e a propriedade for naturalmente herdada, o valor da propriedade será definido como herdado.
  • unset : Esse valor redefine a propriedade para seu valor natural, o que significa que se a propriedade é naturalmente herdada age como herdada, caso contrário ela age como inicial.

 

O valor de herança é o mais interessante - permite-nos fazer explicitamente um elemento herdar um valor de propriedade de seu pai.

 

Vamos dar uma olhada em um exemplo. Primeiro, alguns HTML:

<ul>
  <li>Default <a href="#">link</a> color</li>
  <li class="inherit">Inherit the <a href="#">link</a> color</li>
  <li class="initial">Reset the <a href="#">link</a> color</li>
  <li class="unset">Unset the <a href="#">link</a> color</li>
</ul>

Now some CSS for styling:

body {
  color: green;
}

.inherit a {
  color: inherit;
}

.initial a {
  color: initial
}

.unset a {
  color: unset;
}

Result:

 

Vamos explicar o que está acontecendo aqui:

  • We first set the color of the <body> to green.
  • As the color property is naturally inherited, all child elements of body will have the same green color. It's worth noting that browsers set the color of links to blue by default instead of allowing the natural inheritance of the color property, so the first link in our list is blue.
  • The second rule sets links within an element with the class inherit to inherit its color from its parent. In this case, it means that the link inherits its color from its <li> parent, which, by default inherits its color from its own <ul> parent, which ultimately inherits its color from the <body> element, which had its color set to green by the first rule.
  • The third rule selects any links within an element with the class initial and sets their color to initial. Usually, the initial value set by browsers for the text color is black, so this link is set to black.
  • A última regra seleciona todos os links dentro de um elemento com a classe unset e define sua cor para unset - nós desativamos o valor. Como a propriedade de cor é uma propriedade herdada naturalmente, ela age exatamente como definir o valor para herdar. Como conseqüência, este link é definido para a mesma cor que o corpo - verde.

Active learning: playing with the cascade

Neste aprendizado ativo, gostaríamos que você experimentasse a escrita de uma única nova regra que substituirá a cor e a cor de fundo
que aplicamos aos links por padrão. Você pode usar um dos valores especiais que analisamos na seção Controlling_inheritance
para escrever uma declaração em uma nova regra que redefinirá a cor de plano de fundo de volta ao branco, sem usar um valor de cor real?

If you make a mistake, you can always reset it using the Reset button. If you get really stuck, press the Show solution button to see a potential answer.

What's next

 

Se você entendeu a maior parte deste artigo, então bem feito - você começou a se familiarizar com a mecânica fundamental do CSS. O último pedaço da teoria central é o modelo de caixa, que abordaremos a seguir.

Se você não entendeu completamente a cascata, especificidade e herança, então não se preocupe! Esta é definitivamente a coisa mais complicada
que já cobrimos até agora no curso, e é algo que até mesmo desenvolvedores web profissionais às vezes acham complicado. Nós recomendamos que você
retorne a este artigo algumas vezes à medida que continua o curso e continua pensando nisso. Volte para aqui se você começar a se deparar com
problemas estranhos com estilos que não se aplicam como esperado. Poderia ser uma questão de especificidade.

Etiquetas do documento e colaboradores

 Colaboradores desta página: talitagoulart, ThiagoMSArrais
 Última atualização por: talitagoulart,