Ramon Victor

Herança, especificidade e efeito cascata na CSS: Como funciona?

| 16 Comments

Esse assunto novamente? É pessoal, mesmo isto não sendo uma novidade, ainda é um dos problemas que continua atrapalhando a vida de muitos desenvolvedores. Não apenas os iniciantes, mas os experientes também. Por isso decidi ser um pouquinho ‘chato’ e explicar, mais uma vez, como os browser’s entendem as declarações CSS que nós escrevemos.

O que veremos?

“Árvore genealógica” do documento HTML

Inicialmente, veremos como funciona o modelo de árvore genealógica de todo documento HTML. Esta, conhecida também por árvore de nós (tree of node) . Observemos o código abaixo:

<!DOCTYPE HTML>
<html lang="pt-br">
<head>
	<meta charset="UTF-8">
	<title>Document Title</title>
</head>
<body>
	<header>
		<h1>...</h1>
		<form action="">
			...
		</form>
	</header>
	<article>
		<section>
		</section>
	</article>
</body>
</html>

Como poderíamos ilustrá-lo numa árvore de nós (tree of node)? É simples:

Onde:

  • <body> é pai dos elementos <header> e  <article>;
  • <header> é pai do <h1> e  <form>;
  • <article> é pai do <section>;
  • Por último, o <body> é avô do <h1>, <form> e <section>;

Entender essa idéia, nas tags do documento HTML, é um pré-requisito importante para extraímos o máximo de performance na hora de escrevermos  nossas folhas de estilo. Se você pretende estudar javascript, esse conhecimento servirá também como base essencial para trabalhar com DOM ( Document Object Model ).

Cálculo de especifidade

O cálculo de especificidade, nada mais é, do que o “peso” que a CSS dá a cada tipo de declaração. Entenderemos melhor visualizando o exemplo:

p { color: #000 }
p.azul { color: blue }

Se declararmos um <p class=”azul”>, em nosso HTML, veremos que a cor considerada, neste caso, será o azul. Até que foi fácil  identificar, não é? Pois, sabemos que a classe declarada, na folha de estilo, tem especificidade maior em relação ao elemento sem nenhum atributo adicional.

Porém, existem casos que a coisa fica um pouco mais complicada, vejamos este exemplo:

div p.entry { font-size: 15px }
#conten p { font-size: 12px }

E agora? Quem é mais específico? Para identificar com segurança, essas ocasiões duvidosas, precisamos entender como é dado o “peso” para cada uma das regras de estilo declarada.

Elemento (p), Pseudo elemento (p:first-letter) d = 1 (0,0,0,1)
Classe (.minhaClasse), Pseudo classe (a:hover),
Attributo (a[rel=externo])
c = 1 (0,0,1,0)
Id (#meuId) b = 1 (0,1,0,0)
Style inline (< p style=”color: #ccc”></p>) a = 1 (1,0,0,0)

Mesmo que pareçam chatas, são regras que devem ser entendidas para que tenhamos facilidade de identificar quais são as declarações mais específicas.

E, finalmente, como ficou o exemplo anterior?

div p.entry { font-size: 15px } /* (0,0,1,2) */
#conten p { font-size: 12px } /* (0,1,0,1) */ 

No exemplo acima, a segunda declaração é mais específica por ter um id declarado (b = 1). Porém, se a nossa marcação fosse da seguinte forma:

<div id="content">
<p class="entry" style="font-size: 18px">Lorem ipsum dolor sit amet</p>
</div>

A especificidade do style inline (1,0,0,0) seria  maior do que as mostradas nos exemplos anteriores, logo o texto seria exibido com font-size igual a 18px .

!important

Como toda regra, normalmente, tem suas exceções, essa não deixou de ter a sua. A declaração !important foi um hack criado para tornar a especificidade do elemento maior do que qualquer outra declaração dentro do documento CSS.

p.first { margin-left: 0 !important }

Então podemos usá-lo toda vez que as declarações, por algum motivo, não estiverem funcionando? Não! O !important é indicado apenas naquelas situações onde o código já chegou às suas mãos super mal estruturado e você precisa de uma solução imediata. Caso contrário, devemos usar o próprio conceito de especificidade e herança da CSS, evitando assim “sujeiras” no código.

Herança

O conceito de herança não tem complicação para ser entendido. Simplesmente, os elementos filhos herdam declarações do elemento pai. Só isso? Isso mesmo! Porém, devemos ficar atento, pois não são herdadas declarações relativas a posicionamento e tamanho (ex.: width, height, margin, padding, float, border e etc).

Para que o elemento filho herde valores como os citados acima é necessário declarar o valor da propriedade desejada como inherit . Por exemplo:

HTML

<div>
    <p>Lorem ipsum dolor sit amet</p>
</div>

CSS

div {
    padding: 10px;
    border: 1px solid #ccc
}
p {
    padding: inherit;
}

Certo, mas como faço para que uma declaração seja herdada sem ter que declarar explicitamente o valor inherit ?

Como tínhamos visto anteriormente, basta aplicar regras que não sejam referentes a posicionamento e tamanho, ou seja, se declararmos algo como o exemplo abaixo, todos os descendentes, neste caso da tag <body>, herdarão automaticamente as mesmas regras de estilo.

body {
    font-family: Arial, Sans-serif;
    font-size: 12px;
    color: #ccc
}

Efeito Cascata

Sabemos que podem existir duas, três ou até mais declarações direcionadas ao mesmo elemento. É aí onde atua o efeito cascata , que envolve tudo o que já vimos neste post e mais um conjunto de outros fatores que influenciam na hora de se definir qual regra de estilo será a exibida pelo browser.

Para entendermos quais seriam todos esses fatores e suas respectivas prioridades, em ordem crescente, observemos essa lista disponibilizada pelo site do :

  1. folha de estilo padrão do navegador do usuário;
  2. folha de estilo do usuário;
  3. folha de estilo do desenvolvedor;
    • estilo externo (importado ou linkado).
    • estilo incorporado (definido na seção head do documento);
    • estilo inline (dentro de um elemento HTML );
  4. declarações do desenvolvedor com !important;
  5. declarações do usuário com !important;

Pode parecer um pouco complicado, porém essa parte teórica é essencial para que tenhamos menos dificuldade na hora de resolver bugs que surgem durante o desenvolvimento dos projetos.

Aproveitando o assunto de efeito cascata, abrirei um parêntese para falar, resumidamente, sobre a ferramenta FireBug . Atualmente utilizada por muitos profissionais da área, este plugin do Firefox surgiu para, dentre outras centenas de funcionalidades,  facilitar a identificar qual regra de estilo está sendo aplicada a cada elemento. Não entrarei em maiores detalhes, mas fica a dica para aqueles que ainda não o conheciam.

Conclusão

O que ganho se começar a aplicar todos esses conceitos?

  • Escrever menos linhas de código;
  • Facilitar futuras manutenções;
  • Evitar hacks, que dificultam a correção de bugs;
  • Gerar melhoria de performance com soluções bem elaboradas (ex.: css sprites);

Referências

Dicas, sugestões, acréscimos, críticas (construtivas)? Comente!

Author: ramonvictor

Designer de Interação e Desenvolvedor Frontend. Especialista em Design da Informação pela UFPE e graduado em Sistemas para Internet pela Faculdade Marista.

16 Comments

  1. muito bom o post, inclusive explicando como funciona o danado do !important, que o nome já diz muita coisa, mas MUITAS pessoas não sabem usar! #recomendo

  2. o post é muito bom, mas tem um certo erro em relação ao !important, ele É mais forte até mesmo que uma declaração de estilo INLINE, ele só perde para outro !important mais específico que ele mesmo.
    no mais, parabéns, não acho esse tipo de post chato, acho essencial, até mesmo pra dar uma cutucada nos que já são experientes.

  3. Herança, especificidade e efeito cascata na CSS: Como funciona? | #css

  4. @André,

    Valeu pela observação! O @brunosouza também tinha me alertado para este ponto. O post já está atualizado.
    :)

    Grato pela particiapação de todos.

  5. Herança, especificidade e efeito cascata na CSS: Como funciona? (via @ramonvictor) #recomendo

  6. RT @ramonvictor: Herança, especificidade e efeito cascata na CSS: Como funciona? | #css

  7. RT @ramonvictor: Herança, especificidade e efeito cascata na CSS: Como funciona? | #css

  8. Interessante o post Ramon, muito útil para os iniciantes e uma boa relembrada para os mais experientes, eu uso muitos seletores avançados nos meus trabalhos, principalmente porque deixei de dar suporte ao IE6 e isso vem facilitando muito o desenvolvimento, principalmente pelo fato do html ficar muito mais limpo.

    Uma outra dica que também tem relacionamento com especificidade é o seguinte:

    <!DOCTYPE html>
    <html lang="pt-br">
    <body>
    <nav class="main horizontal">
    <ul>
    ...
    </ul>
    </nav>
    </body>
    </html>

    Nesse caso se a gente declarar a classe .main {width:300px} e a .horizontal {width:400px} qual estilo será aplicado? O da classe .main, pois no caso de múltiplas classes a ordem é seguida de acordo com o que vem primeiro no markup.

    Abraços Ramon.

  9. Cara! Ótimo post! Tu tá se garantindo muito!
    Parabéns pela didática! Tá tudo bem mastigadinho!
    Muito boa observação sobre o !important.

    Continua assim cara, colaborando com o crescimento da galera e crescendo junto! =)
    Abraço!

  10. Herança, especificidade e efeito cascata na CSS: Como funciona? | Ramon Victor

  11. RT @ramonvictor: Herança, especificidade e efeito cascata na CSS: Como funciona? | #css

  12. Pingback:

  13. Ramon vc tá ficando um danado!

  14. parabens ramon! o blog ta muito legal e bem explicativo.

    alem de vc ser o cara do front-end e saber de logica =P, to vendo que também sabe ensinar.

    parabens bro, continue assim!

    ps: to aprendendo front-end olhando seus posts… cuidado nao!
    kkkkkkkkkkkkkkkkk

  15. Agradecimentos a @brunosouza, @gersonthiago, @medeiros_rod, @andremendonca e @juarezpaf pelos comentários! #css #post |

  16. Herança, especificidade e efeito cascata no CSS: Como funciona? O que ganho se começar a aplicar todos esses conceitos?

Deixe uma resposta