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 :
- folha de estilo padrão do navegador do usuário;
- folha de estilo do usuário;
- 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 );
- declarações do desenvolvedor com !important;
- 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
- http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/
- http://imasters.uol.com.br/artigo/4699/css/compreendendo_a_heranca_nas_css/
- http://www.tableless.com.br/efeito-cascata-e-especificidade-do-css
- http://maujor.com/tutorial/intrtut.php
Dicas, sugestões, acréscimos, críticas (construtivas)? Comente!
26 de abril de 2010 at 10:53
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
26 de abril de 2010 at 13:21
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.
26 de abril de 2010 at 13:28
Herança, especificidade e efeito cascata na CSS: Como funciona? | #css
26 de abril de 2010 at 13:30
@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.
26 de abril de 2010 at 13:55
Herança, especificidade e efeito cascata na CSS: Como funciona? (via @ramonvictor) #recomendo
26 de abril de 2010 at 14:23
RT @ramonvictor: Herança, especificidade e efeito cascata na CSS: Como funciona? | #css
26 de abril de 2010 at 15:57
RT @ramonvictor: Herança, especificidade e efeito cascata na CSS: Como funciona? | #css
26 de abril de 2010 at 16:08
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.
26 de abril de 2010 at 17:42
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!
26 de abril de 2010 at 19:42
Herança, especificidade e efeito cascata na CSS: Como funciona? | Ramon Victor
26 de abril de 2010 at 21:26
RT @ramonvictor: Herança, especificidade e efeito cascata na CSS: Como funciona? | #css
Pingback:
27 de abril de 2010 at 14:14
Ramon vc tá ficando um danado!
27 de abril de 2010 at 14:55
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
27 de abril de 2010 at 17:10
Agradecimentos a @brunosouza, @gersonthiago, @medeiros_rod, @andremendonca e @juarezpaf pelos comentários! #css #post |
14 de outubro de 2010 at 20:20
Herança, especificidade e efeito cascata no CSS: Como funciona? O que ganho se começar a aplicar todos esses conceitos?