CSS: Carregando CSS de forma assíncrona
Tags: ptbr, webdev, css, javascript
Published: 2019-08-19 01:38:28

## Uma maneira simples de melhorar performance

Uma das coisas mais impactantes que podemos fazer para melhorar o desempenho e a resiliência de uma página web é carregar o CSS de uma maneira que não atrase a renderização da página. Isso ocorre porque, por padrão, os navegadores carregam o CSS externo de maneira síncrona - parando toda a renderização da página enquanto o CSS é baixado e analisado - e ambos acarretam possíveis atrasos. Obviamente, pelo menos uma parte do CSS do site deve ser carregada antes que a página comece a ser renderizada e, para obter imediatamente esse CSS inicial para o navegador, recomendamos colocá-lo na página em si (_inline css_ ou HTTP2 server-pushing). Para sites com uma quantidade total pequena, isso por si só pode ser suficiente, mas se o CSS for grande (digamos, maior que 15 a 20kb), essa técnica pode ajudar o desempenho e dividí-lo por prioridade. Uma vez dividido, o CSS menos crítico deve ser carregado em segundo plano - a.k.a. de forma assíncrona . Neste artigo, pretendo descrever a maneira preferida de fazer isso nos dias de hoje, que já existe há anos!

Há várias maneiras de fazer com que o CSS seja carregado de forma assíncrona, mas nenhuma é tão intuitiva quanto você espera. Ao contrário dos elementos **script**, não há nenhum atributo **async** ou **defer** que podemos simplesmente aplicar a um elemento **link**, portanto, há anos mantemos o [projeto loadCSS](https://github.com/filamentgroup/loadCSS) para facilitar o processo de carregamento do CSS assíncrono. Recentemente, porém, os navegadores padronizaram seu comportamento de carregamento de CSS, de modo que um script dedicado, como o loadCSS, para lidar com suas pequenas diferenças provavelmente não será mais necessário.

# O Código

Hoje, armados com um pouco de conhecimento de como o navegador lida com vários atributos de elementos **link**, podemos obter o efeito de carregar CSS de forma assíncrona com uma pequena linha de HTML. Aqui está, a maneira mais simples de carregar uma folha de estilo de forma assíncrona:

```html
<link 
  rel="stylesheet" 
  href="/path/to/my.css"
  media="print"
  onload="this.media='all'"
/>
```

# Entendendo suas partes

Essa linha de HTML é concisa, mas não é muito intuitiva, então vamos detalhar o que está acontecendo aqui.

Para começar, o atributo **media** do elemento **link** está definido para **print**. "print" é uma tipo de mídia, (_media type_) que diz: "aplique as regras desta folha de estilo para mídias baseada em impressão" ou, em outras palavras, aplique-as quando o usuário tentar imprimir a página. Francamente, queremos que nossa folha de estilo seja aplicada a todas as mídias (especialmente telas, _screens_) e não apenas a impressão, mas ao declarar um tipo de mídia que não corresponde ao ambiente atual, podemos obter um efeito interessante e útil: o navegador carregará a folha de estilo sem atrasar a renderização da página, de forma assíncrona! Isso é útil, mas não é tudo que queremos. Também queremos que o CSS se aplique ao ambiente de tela quando ele for carregado. Para isso, podemos usar o atributo **onload** para definir o tipo de mídia para **all** quando terminar o carregamento.

# O "rel=preload" não pode fazer isso também?

Sim, da mesma forma! Nos últimos dois anos, usamos **link[rel=preload]** (ao invés de **rel=stylesheet**) para obter um padrão semelhante ao anterior (alternando o atributo **rel** uma vez carregado, ao invés do atributo **media**, respectivamente). Ainda funciona bem usar essa abordagem, no entanto, há algumas desvantagens a considerar ao usar **preload**. Primeiro, o [suporte de navegadores para **preload** ainda não é excelente](https://caniuse.com/#feat=link-rel-preload), portanto, um polyfill (como [o que o loadCSS oferece](https://github.com/filamentgroup/loadCSS/#how-to-use-loadcss-recommended-example)) é necessário se você quiser confiar nesse atributo para buscar e aplicar uma folha de estilo nos navegadores. Mais importante ainda, **preload** busca arquivos muito cedo, _early loading_, com a prioridade mais alta, _highest priority_, potencialmente desprivilegiando outros downloads importantes, e isso pode ser uma prioridade maior do que você realmente precisa para CSS não crítico.

Felizmente, se você deseja a busca de alta prioridade que **rel=preload** fornece (nos navegadores que a suportam), você pode combiná-la com o padrão acima, assim:

```html
<link 
  rel="preload" 
  href="/path/to/my.css" 
  as="style"
/>

<link 
  rel="stylesheet"
  href="/path/to/my.css"
  media="print"
  onload="this.media='all'"
/>
```

Dada a natureza simples e declarativa do código acima, nós escolheríamos isso ao invés de um polyfill, então a abordagem de alternância de mídia de impressão é nossa preferência novamente.

# Por que não utilizar um atributo de tipo de mídia falso?

Você que tem lido nossos artigos sobre isso nos últimos anos pode lembrar que usamos valores de atributo de mídia como **"only X"** para obter o mesmo efeito que **"print"**, fornecendo um valor que não corresponde a nenhum ambiente, como um tipo de mídia **"X"** sem sentido. Quando os navegadores se deparam com tipos de mídia que não correspondem a nenhum ambiente, eles atualmente os tratam da mesma forma - eles carregam o arquivo de qualquer maneira. Dito isso, algumas equipes de navegadores estão começando a considerar a diferenciação entre tipos de mídia não correspondentes e aqueles que não são válidos (ou que não são reconhecidos pelo navegador) e [que potencialmente, podem não solicitam os arquivos vinculados que usam tipos de mídia inválidos](https://bugs.chromium.org/p/chromium/issues/detail?id=977573). Isso quebraria muitas implementações de carregamento de CSS existentes, portanto, não é provável, mas, por questões de segurança, recomendamos o uso de um tipo válido e compatível que não corresponda ao ambiente atual, como **"print"**.

# Você pode não precisar de loadCSS

Continuamos a manter o loadCSS e achar que é útil em algumas situações, como quando você quiser programaticamente buscar um arquivo CSS em JavaScript, como: **loadCSS("/path/to/my.css")**. Se você já estiver usando loadCSS ou seu **rel=preload** padrão de polyfill, não precisará alterar nada. Internamente, usamos a mesma mecânica descrita neste artigo.

Porém, mais e mais estamos descobrindo que a abordagem simples em HTML pode ser tudo o que você precisa.

**E simples é geralmente melhor.**

# Obrigado pela leitura

Perguntas? [Nos adicione no Twitter!](https://twitter.com/filamentgroup)

---

# Créditos

- [The Simplest Way to Load CSS Asynchronously](https://www.filamentgroup.com/lab/load-css-simpler/?utm_source=oieduardorabelo), escrito originalmente por [filament group](https://twitter.com/filamentgroup)