Escrever CSS eficiente não é um assunto novo, mas algo que desenvolvedores front-end devem prestar bastante atenção, principalmente porque, como devem saber, pelo menos 80% das questões de performance de web sites se encontram no front-end. Portanto, é interessante e, em alguns casos, vital, para o sucesso de um site, que os seletores CSS sejam escritos e otimizados de modo a garantir a melhor performance possível!

As dicas e regras apresentadas neste artigo se aplicam, principalmente, a sites de alto desempenho, nos quais a velocidade é uma característica imprescindível e 1000 elementos podem estar presentes no DOM. Mas não importa se você está construindo o próximo Facebook ou um site para o decorador local: as melhores práticas são as melhores práticas.

Seletores CSS

Seletores CSS não são novidade para nós, desenvolvedores web. Os seletores mais básicos são de tipo (ex. div), ID (ex. #header) e classe (ex. .tweet), respectivamente. Os mais incomuns incluem pseudo-classes comuns (ex. :hover) e seletores CSS3 mais complexos, incluindo :first-child ou [class^="grid-"].

Seletores têm uma eficiência inerente que, partindo dos mais eficientes para os menos eficientes, são:

É importante notar que, apesar de, tecnicamente, um ID ser mais rápido e mais performático, essa diferença é mínima. Conforme já foi explicado no artigo “Não use IDs como seletores em CSS“, um seletor ID e um seletor de classe mostram muito pouca diferença no quesito performance.

Combinando seletores CSS

É possível ter seletores independentes, como #nav, que irão selecionar qualquer elemento com um ID “nav”, ou você pode combinar seletores, como #nav a, que vai corresponder a qualquer link/âncora dentro de qualquer elemento de ID de “nav” – que, no caso, seria somente 1 por página, conforme visto no artigo sobre diferenças entre IDs e classes.

Pode parecer estranho e um pouco difícil de entender rapidamete, mas, diferentemente do que a maioria dos ocidentais, que costumamos ler da esquerda para a direita, seletores CSS são lidos da direita para a esquerda pelos navegadores. Para tentar compreender o motivo pelo qual os browsers fazem isso, lembremo-nos daqueles jogos de “encontre o caminho” que brincávamos nas revistas da nossa infância. Todos nós iniciávamos a resolução pelo objetivo final do emaranhado de caminhos, retrocedendo até um dos pontos iniciais possíveis.

Escrevendo CSS eficiente: exemplo da brincadeira "encontre o caminho"

É mais eficiente para um navegador começar sua procura por combinações a partir do elemento mais à direita (o que ele sabe que irá receber o estilo) e trabalhar o seu caminho de volta através da árvore de DOM do que começar no alto da árvore de DOM e fazer o caminho para baixo, que poderia nem mesmo acabar no seletor que precisa receber a estilização – também conhecido como seletor-chave.

Já deu pra ter uma noção, mas, caso queira uma explicação mais detalhada, confira a discussão “CSS Selectors parsed right to left. Why?“, no Stack Overflow.

O seletor-chave

O seletor-chave, como discutido, é a parte mais à direita de um seletor CSS. Isto é o que o browser procura em primeiro lugar. Lembre-se da ordem dos seletores mais eficientes que abordamos anteriormente. Seja qual for o seletor chave da vez, ao escrever CSS eficiente é este seletor que contém o segredo do alto desempenho!

Um seletor como:

O navegador irá procurar todas as instâncias de .intro e, depois, começar a subir no DOM até encontar o elemento #content.

No entanto, o seguinte seletor não é muito performático:

O que isso faz é olhar para cada elemento da página (para cada um, mesmo!) e, em seguida, checar se qualquer um deles é descendente de #content. Este é um seletor de performance ruim e, como seletor-chave, é muito “expensivo”. Usando este conhecimento, é possível tomar melhores decisões quanto ao modo de classificar e selecionar elementos.

Vamos dizer que, numa página realmente grande, de um site realmente enorme, há centenas ou, mesmo, milhares de elementos a. Há, também, uma pequena seção de links de mídia social em um ul com um ID “social”; digamos que Twitter, Facebook e Google+. Temos 3 links de mídias sociais nesta página e, além destes, incontáveis outras âncoras.

Portanto, seria excessivamente custoso e nada performático um seletor como:

O que vai acontecer, aqui, é que o navegador irá avaliar todos os milhares de links na página antes de fazer o match com os links de #social. O seletor-chave corresponde a muitos outros elementos que nada têm a ver com a estilização pretendida.

Para remediar a situação, uma solução possível seria adicionar um seletor mais específico e explícito, .social-link, para cada um dos a da “área social”. Mas isso iria contra o fato de que não é aconselhado colocar classes desnecessárias na marcação quando é possível usar uma solução mais “enxuta”.

É por isso que o desenvolvimento web focado em desempenho é algo tão interessante, um estranho equilíbrio entre melhores práticas de padrões web e performance!

Considere o seguinte código:

Com esse CSS:

Agora, veja este outro HTML:

Com esse CSS:

Esse novo selector-chave vai corresponder a poucos elementos, o que significa que o navegador conseguirá realizar a estilização mais rapidamente e passar para a próxima coisa a ser feita.

Recapitulando, o seletor-chave é o que determina quanto trabalho o navegador terá de fazer; portanto, tenha bastante atenção nele(s)!

Superqualificando seletores

Já sabemos o que é um seletor-chave e que é nele que a maior parte do trabalho está. A boa notícia é que é possível trabalhar para o(s) otimizar ainda mais! A melhor coisa sobre ter bons seletores-chave explícitos e criar CSS eficiente e de qualidade é que é possível evitar a “superqualificação” de seletores. Um seletor superqualificado se parece com:

O navegador tem que olhar para todos os elementos a, então, verificar se, respectivamente, está em um elemento de ID “content” e assim por diante, num caminho até chegar em html. Isso está fazendo com que o navegador passe por caminhos que, realmente, ele não precisa e, pelo menos 3 desses elementos no seletor, são totalmente desnecessários. A regra poderia ser reescrita para:

Um outro exemplo, infelizmente bastante comum, é:

Sabemos que, se o a está dentro de li, que tem que estar dentro de #nav, então é possível, logo de cara, eliminar o li do seletor. Então, como o #nav é um ID (e já sabemos que só podem existir IDs únicos e exclusivamente nominados na página), o elemento ul também pode ser eliminado. O que reduz o seletor para:

Seletores superqualificados fazem com que o navegador trabalhe mais do que precisa e deveria. Construa seletores mais enxutos e de alto desempenho eliminando as partes desnecessárias.

Toda essa otimização CSS é necessária?

A resposta curta é: provavelmente não.

A resposta mais longa é que depende do site que está sendo desenvolvido. Se você está trabalhando no próximo projeto de seu portfolio pessoal, dê preferência a escrever um código limpo em detrimento à performance de CSS porque, neste caso, não vai fazer tanta diferença. Agora, se você está construindo a próxima Amazon, microssegundos de velocidades na página fazem a diferença!

Mas, independentemente do tamanho do seu projeto, os navegadores interpretação de forma igual e terão o mesmo trabalho de análise das regras CSS. Portanto, se estiver escrevendo algo como:

Você, muito provavelmente, está fazendo a coisa errada!

Mas, se seu humilde projeto web, de uma hora para a outra, começa a expandir e a ter, cada vez mais, acessos e mais acessos, crescendo exponencialmente e acima do esperado, tornando-se “o próximo hit da web”, os recursos despendidos para otimizar o CSS, depois disso, serão o melhor investimento a ser feito? Será que, à época, não haverá arrependimentos por não ter escrito um bom CSS desde o começo? Fica a questão…

Conheça o livro “CSS Eficiente“, dedicado inteiramente a este tema!