# Escrevendo CSS eficiente

> Escreva CSS eficiente para melhor performance web. Entenda seletores otimizados, especificidade e técnicas de otimização para sites rápidos. Otimize!

URL: https://dpw.dev/css/escrevendo-css-eficiente/  
Publicado em: 2012-05-28  
Categoria: css  
Tags: performance  
Autor: Tárcio Zemel

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](https://developer.yahoo.com/blogs/ydn/high-performance-sites-importance-front-end-performance-7160.html). 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.

> Artigo baseado em [Writing efficient CSS selectors](http://csswizardry.com/2011/09/writing-efficient-css-selectors).

## 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:

- ID, ex. `#header`
- Classe, ex. `.promo`
- Tipo, ex. `div`
- Irmão adjacente, ex. `h2 + p`
- Filho, ex. `li > ul`
- Descendente, ex. `ul a`
- Universal, ex. `*`
- Atributo, ex. `[type="text"]`
- Pseudo-classe/Pseudo-elemento, ex. `a:hover`

É 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](/css/nao-use-ids-como-seletores-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](/css/diferencas-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"](/images/blog/escrevendo-css-eficiente/encontre-o-caminho-css.gif)

É 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?](http://stackoverflow.com/questions/5797014/css-selectors-parsed-right-to-left-why)", no [Stack Overflow](http://stackoverflow.com/).

## 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:

```
#content .intro {}
```

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:

```
#content * {}
```

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:

```
#social a {}
```

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:

- [Twitter](#)
- [Facebook](#)
- [Google+](#)

Com esse CSS:

```
#social a {}
```

Agora, veja este outro HTML:

- [Twitter](#)
- [Facebook](#)
- [Google+](#)

Com esse CSS:

```
#social .social-link {}
```

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:

```
html body .wrapper #content a {}
```

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:

```
#content a {}
```

Um outro exemplo, infelizmente bastante comum, é:

```
ul#nav li a {}
```

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:

```
#nav a {}
```

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?

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:

```
div:nth-of-type(3) ul:last-child li:nth-of-type(odd) * { font-weight: bold }
```

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...

---

Fonte: [dpw - desenvolvimento para web](https://dpw.dev/) (pt-BR).
Guia para agentes: https://dpw.dev/llms.txt
Índice completo: https://dpw.dev/sitemap-index.xml
Feed: https://dpw.dev/rss.xml
