DEV Community

Cover image for Os limites do Tailwind CSS
Camilo Micheletto
Camilo Micheletto

Posted on • Updated on

Os limites do Tailwind CSS

Taiwind como tudo nessa vida tem seus prós e contras. É importante que um ecossistema tenha um bom equilíbrio de críticas e elogios pra se manter num processo de melhoria contínua e também munir seus usuários com opiniões diversas que potencializem as suas tomadas de decisão sobre usar ou não.

Nesse artigo eu vou tratar o Tailwind como uma ferramenta, não como uma divindade, um problema grave ou solução definitiva. O que espero é que esse artigo ajude a tomada de decisão de aplicar Tailwind num projeto seja do ponto de vista de arquitetura de aplicação e levando em consideração seus prós e contras, e não por sentimentos puramente individuais e pessoais como "DX" ou "facilidade".

Esse artigo expressa somente a minha opinião sob meu critério técnico pessoal. Como eu me sinto sobre Tailwind ou sua comunidade foi algo secundário pra mim ao escrever esse artigo, espero o mesmo das pessoas que irão ler esse artigo.


O que é Tailwind CSS

Página inicial do site Tailwind. O slogan "Rapidly build modern websites without ever leaving your HTML" em caixa alta.

Tailwind é um framework de CSS utilitário. Um framework porque ele por si só não é uma utilidade, mas um pequeno ecossistema intricado ao redor de um design system. Utilitário pois ele fornece uma série de classes com responsabilidade única que trazem estilos com uma boa direção de arte, minimizando as decisões de design que uma pessoa desenvolvedora pode acabar tendo que tomar e que podem dificultar a chegada na etapa de desenvolvimento.


Pontos positivos

Mais do que um framework de CSS o Tailwind é um plugin de PostCSS. Isso porque seus maiores benefícios é a geração de classes JIT (Just-in-time) e a facilidade de purging, prefixing e outras ferramentas de otimização e compatibilidade que vem direto da caixa.

 

JIT
Just-in-time nasceu na v2.1 do Tailwind e é a capacidade de gerar estilos sob demanda. Ao passar os pontos de entrada de estilos no seu arquivo de configuração, Tailwind gera apenas os estilos que foram declarados nos seus arquivos de template (HTML, JSX, etc), fazendo com que classes não utilizadas não existam em produção.

Purging
Purge é a remoção de CSS não utilizado. O algoritmo de purge tem que levar em consideração uma série de fatores, o que pode dificultar o processo de remoção pra códigos de CSS mais denso ou com CSS condicional/ injetado via script. O Tailwind limita uma série de particularidades do CSS e fecha o usuário no seu ecossistema de tokens e classe, dando total previsibilidade pro PurgeCSS realizar uma remoção segura.

Otimização e compatibilidade
Tailwind usa minificação e compressão pra entregar bundles de CSS otimizados. Estratégias que inclusive podem e devem ser aplicadas à qualquer abordagem de CSS que não as tenha por padrão. Tailwind utiliza Gzip e Brotli pra compressão e CSSnano pra minificação.

DX
Developer experience é a qualidade de minimização de atritos no processo de desenvolvimento, tornando a experiência de programar fluída e quase "sem pensar". Por seu ecossistema de plugins, presets e extensões, é possível programar interfaces de forma rápida com código que se autocompleta com as classes disponíveis, quase que como tipado, com uma documentação bem visual e abundante, e muitas soluções e abstrações criadas pela comunidade.


Quando aplicar o Tailwind CSS no meu projeto?

Tailwind é extremamente útil pra projetos que possuem nenhum design system ou um que seja pouquíssimo opinionado. É perfeito pra projetos com necessidade de CSS de baixa complexidade e baixíssima manutenção, ideal pra times de front-end com pouca expertise em CSS ou com baixa capacidade de alocação de custos pra arquitetura de CSS.

 

Se você ficou na dúvida sobre os termos design system ou design tokens, escrevi um artigo bacana sobre isso.

 

Quando falo sobre a aplicabilidade, não estou dizendo que é impossível aplicar em uma aplicação de larga escala ou com design systems, mas ao fazê-lo, o time irá lidar muito mais com os pontos que o Tailwind não cobre, fazendo com que abstrações, patches e complexidade extra sejam criadas.

🧐 Se você tem bons exemplos de uma aplicação nesses parâmetros que deu certo com pouquíssima complexidade, comenta sobre, vou adorar conhecer!


Pontos negativos

Me incomoda muito quem critica qualquer coisa sem usar ou com base em critérios levianos. Pra escrever esse artigo eu testei Tailwind de duas formas - criei uma aplicação pra testar algoritmos complexos de UI e li o código fonte de dois frameworks populares que utilizam o Tailwind, o shadcnUI e o DaisyUI.

A escolha se deu pois um usa diretamente das classes do Tailwind, o outro as abstraí em classes únicas usando a diretiva @apply, se aproveitando apenas dos design tokens do mesmo.

Uma pessoa fumando cigarro, sendo comparada à fumar vape, paralelamente, código CSS inline sendo comparado à classes tailwind
Eu tava brincando, tá gente?


As críticas já existentes

Adam Wathan tratou sobre uma das críticas recorrentes ao Tailwind que é a separação de interesses (separation of concerns) que é manter uma separação em código das responsabilidades de cada parte da aplicação. Se essa trás benefícios como desacoplamento, manutenabilidade e modularização, ela ainda é uma opinião de alguns escritores dentro de contextos específicos e que deve ser levada em consideração, não uma lei ou axioma.

Há pouca evidência de benefícios mensuráveis da separação do HTML e do CSS pra além do arquivo. E ainda no campo do arquivo, é uma boa prática de performance que o CSS crítico seja colocado em uma tag style de forma inline.

O HTML ilegível é ilegível pra quem não gosta ou não trabalha com Tailwind. Em times que trabalham com esse framework, isso é uma das premissas basilares. Se você reparte o template em páginas e componentes, você precisa revisitar menos os templates e ler espaguetes menores. Eventualmente você acostuma ou instala um linter.

O problema raiz no meu ver antecede o template feio. O problema é a falha estrutural na reutilização de estilos.


Reuso de estilos

Esse trecho leva em consideração majoritariamente o capítulo Reusing Styles da documentação oficial

Tailwind é incapaz lidar com repetição de código por conta própria. Suas formas de lidar com isso são extremamente acopladas à IDE ou à bibliotecas e frameworks de templating ou componentes, como React, Vue ou vintage Nunchucks.

 

Editando via cursor múltiplo na IDE

Uma solução viável, mas que assume o uso de uma IDE e de uma feature específica que tem baixíssima acessibilidade e é pouco viável de se utilizar através de documentos (através do localizar e substituir global) pois este pode selecionar classes além do escopo pretendido. Isso, porém, pode ser solucionado localizando esses escopos com componentes.

Extraindo e componentizando

Componentes podem ser facilmente reutilizados, mas ainda são uma forma de acoplamento que assume pelo menos uma forma rudimentar de templating e pós processamento. Claro que é possível usar Tailwind em projetos vanilla, mas não sem perder os benefícios de JIT, compressão e as diretivas cujo suporte vem totalmente do PostCSS. Sem o PostCSS e o processamento, as maiores qualidades do Tailwind não sobreviveriam. Mesmo num contexto em que componentes são utilizados, o CSS fornece diversas ferramentas de reutilização, como a própria classe não-utilitária e seletores. Tailwind só é capaz de se apropriar através da diretiva @apply.

@apply

Essa diretiva existe pois é a forma mais fácil de cunhar classes que ainda usem do design system do Tailwind. É possível, por exemplo, usar dos design tokens do Tailwind, pois esse utiliza composição de variáveis CSS, mas não as expõe como API, não as documenta, não faz JIT delas standalone, nem possuí autocomplete, fazendo com que o uso das mesmas possa prejudicar a integridade do design system do Tailwind. Sem falar que o próprio Adam percebe o excesso de complexidade e a proeminência de bugs:

 

Novamente, você pode estar ok a respeito disso, principalmente se trabalha com um ecossistema que se encaixa com todos esses requisitos. Entender essa limitação é entender também quando aproveitar melhor quando elas se fazem necessárias.


CSS amordaçado

Muito da DX do Tailwind se deve à abstração de conceitos base do CSS como seletores compostos, unidades CSS, funções de CSS, herança e especificidade. Esses conceitos são sim complexos, mas também possibilitam a escrita de um CSS enxuto, robusto retrocompatível, mas com possibilidade de melhoria progressiva.

Criei 3 casos com diferentes complexidades pra demonstrar.

Layout Holy Grail na abordagem do Josh Comeau

Inspirado no artigo Full-Bleed Layout Using CSS Grid - An elegant solution to a tricky modern layout de Josh Comeau

Layout responsivo com header e footer e o conteúdo em uma coluna central

Esse layout aplicado de forma responsiva e sem media queries é possível com apenas 5 linhas de CSS, 8 se você não utilizar o nesting nativo:

.grail {
  display: grid;
  grid-template-columns: 1fr min(var(--width, 800px), 100%) 1fr;
  & > * { grid-column: 2; }
}
Enter fullscreen mode Exit fullscreen mode

 

Claro que há outras formas de executar esse layout, mas elas implicam em mais CSS - media queries pra controlar o tamanho das laterais de acordo com a largura do dispositivo, ou mais HTML, criando containeres e wrappers usando a mesma lógica do Bootstrap Grid.

Ou seja, pra produzir o mesmo layout você precisa introduzir complexidade que não é necessária, tendo como único benefício "experiência de desenvolvimento".

Você escreve "menos CSS" e não precisa saber algoritmos complicados de grid, mas você tem mais template pra processar, testar e debugar. Se classes utilitárias são simples de debugar por conter apenas uma propridade, páginas ou templates facilmente se tornam um wrapper hell quando o template assume a responsabilidade que os estilos deveriam suprir.

Arbitrary Values
Na versão mais recente, é possível criar uma classe com esses parâmetros sob demanda usando a API de arbitrary values.

<section className="grid w-full grid-cols-[1fr,min(var(--width),100%),1fr] place-items-center gap-y-4 [&>*]:col-start-2">
   <!-- ... -->
</section>
Enter fullscreen mode Exit fullscreen mode

Mas as limitações são claras:

  1. Só é possível se usar uma sintaxe bem específica. A sintaxe não é simples e não dá suporte pra espaçamentos, logo é muito fácil introduzir bugs nessa sintaxe e muito difícil identificá-los.

  2. É possível usar seletores [&>*], mas eles só recebem um parâmetro por vez e o código gerado é praticamente ilegível.

/* Output da classe [&>*] */
.\[\&\>\*\]\:col-start-2>* {
  grid-column-start: 2;
}
Enter fullscreen mode Exit fullscreen mode

 

"Ah, mas o output não importa"
Você não dá valor ao output, mas o navegador não se importa com qual ferramenta você tá utilizando. Se houver algum erro ou inconsistência, você vai enfrentar um devTools com dezenas de classes com seus contextos encapsulados e outras com declarações ilegíveis.


Fica, vai ter segunda parte

Há muita coisa a ser dita e exemplos a serem explorados, então farei uma segunda parte analisando mais uma aplicação de CSS avançado, se o Tailwind realmente produz menos CSS, a questão da herança e especificidade e a interação do Tailwind com outros frameworks e código estrangeiro.

Adoraria ler a opinião de vocês até aqui, os desafio a deixarem de lado questões pessoais e favoritismos, pois eu particularmente aprendi muito tecnicamente ao analisar essa ferramenta de forma fria, e gostaria que o mesmo acontecesse com vocês. Não sejam que nem o Adam:

Top comments (8)

Collapse
 
demenezes profile image
deMenezes

Nunca usei o Tailwind, e tento não formar uma opinião ruim só pelo argumento do "sujar o HTML"

Nessa linha, gostei desse trecho aqui, eu já tinha pensado sobre isso mas foi legal confirma-se hahahah

"O HTML ilegível é ilegível pra quem não gosta ou não trabalha com Tailwind. [...] Se você reparte o template em páginas e componentes, você precisa revisitar menos os templates e ler espaguetes menores."

Parabéns pelo artigo, Camilo, continua assim que estou adorando ler.

Collapse
 
lixeletto profile image
Camilo Micheletto

Po que feedback fantástico, obrigado!

Collapse
 
dionarodrigues profile image
Diona Rodrigues

Ótimo artigo!

Assim como comentado aqui, eu também nunca fui muito a fundo no Tailwind, mas confesso que já o utilizei para projetos pequenos, onde eu não queria gastar muito tempo escrevendo CSS (e lidando com todas as suas complexidades). Eu realmente aprecio a inovação que esse framework trouxe possibilitando escrever estilos complexos apenas por meio de classes no HTML, mas tenho a impressão de que é muito mais díficil manter um projeto de larga escala com ele (sou defensora do separation of concerns).

Um ponto interessante que vc citou é que o Tailwind talvez seja interessante também para times com pouco conhecimento de CSS. Logo eu vejo sua grande popularidade no desenvolvimento de templates para baixar/comprar.

Eu acredito que ainda não chegamos a uma great tool para escrever CSS, mas definitivamente, para mim, Tailwind não é nem de longe a melhor solução para substituir preprocessors e CSS-in-JS. Talvez, eu limitaria o seu uso em cenários muito específicos onde baixo conhecimento de CSS e rapidez no desenvolvimento são os principais pontos (uma POC, prototype or aplicação simples por exemplo).

Collapse
 
lixeletto profile image
Camilo Micheletto

Olá! Obrigado pelo comentário!
Então, acho que ele nem se propõe a substituir essas ferramentas, a comunidade que o vê dessa forma. Outro cenário que eu devia ter incluido é que manter é um investimento, custa dinheiro e trás uma baixa percepção de retorno de investimento. Um código verboso e limitado e um código limpo e moderno podem produzir UI de qualidades muito parecidas. O Tailwind é feito pra que se o seu caso for o primeiro, você não precise olhar pra trás pra mantê-lo.
A maior qualidade do Tailwind é não se preocupar, e pelo fato que a gente é cada vez menos pago pra se preocupar com CSS, a tendência é que os tradeoffs de soluções como essa pareçam cada vez mais irrisórios.

Collapse
 
olivianes97 profile image
Olivianes97 • Edited

This post will definitely be useful to many people.

Collapse
 
lucasayabe profile image
lucas-ayabe

Finalmente alguém que partilha de opiniões similares sobre o Tailwind.

Eu nunca fui tão a fundo em testar o Tailwind, mas também nunca fui muito convencido pelos pontos de quem o defende.

Eu não sou lá o maior fã do Tailwind, e acho que sua análise foi bem justa, pegou nos pontos que vejo muitas pessoas ignorarem quando falam desse assunto, principalmente a parte dos templates onde a discussão geralmente termina em "você se acostuma".

Gostaria de acrescentar que acho que o sucesso do Tailwind se deve muito a popularidade do React também, afinal com Vue e Svelte, o modelo de SFC, e o projeto open props, eu não vejo muito sentido em largar a sintaxe bem mais expressiva do CSS em favor de um HTML todo ilegível.

Collapse
 
lixeletto profile image
Camilo Micheletto

Então, eu vejo sentido pois toda abstração acarreta em capacidade no sentido de negócio. Arquitetura CSS custa dinheiro pra manter, pra hospedar, pra contratar devs que vão escrever um bom CSS e seguir uma convenção de padrões que linters dificilmente vão prover.

Isso obriga a equipe a investir num Design System que vai criar uma biblioteca de componentes pra fazer com que o time de desenvolvimento tenha uma qualidade de trabalho horizontalizada.

Essa é a beleza da limitação - ela é uma produção custo-efetiva. Um CSS de baixa qualidade produz os mesmos layouts que um CSS de alta qualidade, com um custo de debugging e retrabalho alto mas pouco relevante perto de Javascript.

Entendo sabe? E vejo que devia ter exposto mais essa opinião nesse texto também.

Collapse
 
zackmas profile image
zack muas

Greetings from The Vapez, the UK's RandM Paradise 10000 Box of 10 premier source for high-quality vaping accessories.