Escrevendo CSS eficiente

by 3 colaboradores:

Este artigo necessita de uma revisão editorial.

Este documento fornece orientações para otimizar o código CSS, e mais especificamente sobre como escrever seletores eficientes.

A especificação CSS não especifica como os navegadores devem implementar o sistema de estilo, apenas o que ele deve fazer. Devido a isso, diferentes motores de sistema de estilo podem ter comportamentos de desempenho completamente diferentes e, especialmente, Gecko e WebKit, que são de código aberto, implementam algoritmos similares, com pontos fortes e fracos muito semelhantes. Portanto, as dicas apresentadas aqui devem ser úteis para documentos do mundo real web.

A primeira seção é uma discussão geral de como o sistema de estilo habitual categoriza as regras. As seções a seguir contêm as diretrizes para escrever regras que se aproveitam de tal implementação do sistema de estilo.

Como o sistema de estilo quebra regras

O sistema de estilo quebra as regras em quatro categorias principais:

  1. Regra de ID
  2. Regra de Classe
  3. Regra de Tag
  4. Regras Universais

É fundamental compreender estas categorias, como são os blocos de construção fundamentais da regra correspondente.

Eu uso o termo chave seletora nos parágrafos que se seguem. A chave seletora é a última parte do seletor (a parte que corresponde ao elemento a ser acompanhada, em vez de os seus antepassados).

Por exemplo, em regra...

a img, div > p, h1 + [title] {…}

... os seletores chave são img, p, e title.

Regra de ID

A primeira categoria é constituída por aqueles que possuem uma regra ID seletor como o seu selector de chave.

Exemplo
button#backButton {…} /* Esta é uma regra de ID Categorizada */
#urlBar[type="autocomplete"] {…} /* Esta é uma regra de ID Categorizada */
treeitem > treerow > treecell#myCell:active {…} /* Esta é uma regra de ID Categorizada */

Regra de Classe

Se uma regra tiver um class espeficicado como seu seletor chave, ele entrará nesta categoria.

Exemplo
button.toolbarButton {…} /* Uma regra baseada em classe */
.fancyText {…}	/* Uma regra baseada em classe */
menuitem > .menu-left[checked="true"] {…} /* Uma regra baseada em classe */

Regra de Tag

Caso nenhuma class ou ID for especificada como seletor chave, o próximo candidato é a categoria tag. Se a regra tiver uma tag especificada como seletor chave, ela entrará nesta categoria.

Exemplo
td {…} /* Uma regra baseada em Tag */
treeitem > treerow {…} /* Uma regra baseada em Tag */
input[type="checkbox"] {…} /* Uma regra baseada em Tag */

Regras Universais

Todas as outras regras entram nesta categoria.

Exemplo
[hidden="true"] {…} /* Uma regra universal */  
* {…}		/* Uma regra universal */
tree > [collapsed="true"] {…} /* Uma regra universal */

Como o sistema de estilo combina as regras

O sistema de estilo combina as regras começando pelo seletor chave, e então segue para direita (procurando por quaisquer ascendentes na regra do seletor). Enquanto a sub-árvore do seletor continua fazendo a verificação, o sistema de estiilo continua se movendo para esquerda até ele terminar de combinar a regra, ou para a verificação devido alguma imcompatibilidade.

O conceito mais fundamental para aprender é a regra de filtro. As categorias existem a fim de filtrar regras irrelevantes (logo o sistema de estilo não desperdiça tempo tentando combiná-las).

Este é o ponto onde há um aumento drástico de performance de memória. Quanto menos regras forem necessárias para verificar um elemento, mais rápida será a resolução.

Por exemplo, se um elemento tiver um ID, então apenas a regra de ID que combina com o ID do elemento será verificada. Apenas regra de Classe para uma classe encontrada no elemento será verificada. Apenas regras de Tag que combinam com a tag serão verificadas. Regras Universais serão sempre verificadas.

Diretrizes para um CSS eficiente

Evite regras universais

Tenha certeza de quem uma regra não termina em categoria universal!

Não qualifique regras de ID com classes ou nome de tags

Se uma regra tiver um seletor ID como seletor chave, não adicione o nome da tag á regra. Uma vez que IDs são únicos, adicionar o nome de uma tag tornaria mais lento o processo de verificação desnecessariamente.

RUIM
button#backButton {…}
RUIM
.menu-left#newMenuIcon {…}
BOM
#backButton {…}
BOM
#newMenuIcon {…}
Exceção: Quando é desejável mudar dinamicamente a class de um elemento a fim de aplicar diferentes estilos em diferentes situaçãoes, porém a mesma class será compartilhada com outros elementos.

Não qualifique regras de classe com nomes de tag

O conceito anterior também se aplica aqui.  Apesar de que as classes podem ser utilizadas por diversas vezes na mesma página, elas ainda são mais exclusivas do que uma tag.

Uma convenção que você pode utilizar é incluir o nome da tag no nome da classe. Contudo, isto pode lhe custar alguma flexibilidade; caso mudanças de design forem aplicadas na tag, os nomes das classes devem mudar também.  (É melhor escolher nomes estritamente semânticos, enquanto tal flexibilidade é uma das finalidades de folhas de estilo separadas.)

RUIM
treecell.indented {…}
BOM
.treecell-indented {…}
MELHOR
.hierarchy-deep {…}

Utilize a categoria mais específica possível

A maior causa de performance lenta é o fato de ter muitas regras na categoria de tag. Ao adicionar classes para os nossos elementos, podemos subdividir essas regras em Categorias de Classe, da qual elemina o tempo gasto tentando combinar regras para uma determinada tag.

RUIM
treeitem[mailfolder="true"] > treerow > treecell {…}
BOM
.treecell-mailfolder {…}

Evite o seletor descendente

O seletor descendente é o seletor mais custoso no CSS. Ele é tremendamente caro — especialmente se o seletor estiver na Categoria Tag ou Universal.

Frequentemente, o que é realmente desejado é o seletor filho. Por exemplo, as performances são tão ruins, que os seletores descendentes são proibídos no Firefox' User Interface CSS, sem qualquer justificativa. É uma boa idéia fazer a mesma coisa nas suas páginas

RUIM
treehead treerow treecell {…}
MELHOR, MAS AINDA RUIM (veja a próxima diretriz)
treehead > treerow > treecell {…}

Regras de Categoria de Tag jamais devem conter um seletor filho

Evite usar o seletor filho com regras de categoria de tags. Isto irá alongar drasticamente o tempo para fazer a combinação (especialmente se a regra é susceptível de ser combinada) para todas as ocorrencias daquele elemento.

RUIM
treehead > treerow > treecell {…}
BOM
.treecell-header {…}

Questione todos os usos do seletor filho

Tenha cuidado ao usar o seletor filho. Evite-o se puder.

Particularmente, o seletor filho é frequentemente usado com árvores RDF e menus como:

RUIM
treeitem[IsImapServer="true"] > treerow > .tree-folderpane-icon {…}

Lembre-se que atributos REF podem ser duplicados em um template! Tire vantagem disso. Duplique as propriedades RDF em elementos XUL filhos a fim de muda-los baseado o atributo.

BOM
.tree-folderpane-icon[IsImapServer="true"] {…}

Conte com a herança

Descubra quais propriedades são herdadas, e permita que sejam utilizadas!  

Por exemplo, widgets XUL são explicitamente configurados de tal modo que o list-style-image do parente ou regras de fonte serão filtradas em conteúdo anônimo. Não é necessário desperdiçar tempo com regras que conversam diretamente com conteúdo anônimo.

RUIM
#bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
BOM
#bookmarkMenuItem { list-style-image: url(blah) }

No exemplo acima, o estilo desejado ao conteúdo anônimo (sem aproveitar a herança de list-style-image) resultado em uma regra que estava na Categoria de Classe, quando a regra deveria ter terminado na Categoria de ID — a categoria mais específica de todas!

Lembre-se: Os elementos tem a mesma classe — especialmente o conteúdo anônimo!

O exemplo de regra "ruim" acima força cada ícone do menu á ser testado para contenção dentro do #bookmarkMenuItem. Uma vez que existem muitos menus, isto se torna extraordinariamente caro. Ao invés disso, o exemplo de regra "bom" limita o teste para o #bookmarkMenuItem.

Utilize -moz-image-region!

Colocar um monte de imagens em um único arquivo de imagem e selecioná-los com -moz-image-region gera uma performance significativamente melhor do que colocar cada imagem em seu próprio arquivo.

Utilize folhas de estilo com escopo

Se você especificar uma folha de estilo como um recurso XBL, o estilos apenas se aplicam ao elementos amarrados e seu conteúdo anônimo. Isto reduz a ineficiência de regras universais e seletores filhos porque há menos elementos serão considerados.

Informação do Documento Original

Etiquetas do documento e colaboradores

Contributors to this page: AlanCezarAraujo, teoli, Danty
Última atualização por: AlanCezarAraujo,