4 meses usando Tailwind
Tags: tailwindcss, css, frontend
Published: 2024-02-20 14:55:48



![Navio flutuando no céu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wmb4zsjg1xd8yup0ffs5.png)

[English version](https://dev.to/maiconsanson/4-months-using-tailwind-2ofn)

*Este post foi escrito em outubro de 2023, alguns dados fornecidos aqui podem ter sido alterados.*

Projeto pessoal é uma maravilha, você é livre para escolher toda a [stack da aplicação](https://pt.wikipedia.org/wiki/Conjunto_de_solu%C3%A7%C3%B5es_(computa%C3%A7%C3%A3o)): database, ambientes, deploy, testes, back end, front end, como organizar as tasks e etc. Nesses projetos você consegue ter um nível de aprendizado que dificilmente teria em uma empresa. Então aproveite, "brinque" de startup nas horas vagas e arque com suas decisões.

Meu foco é o front end mas navego um pouco no back end porque é uma sensação ótima conseguir, sozinho, tirar uma ideia maluca do papel e colocá-la em prática.

Sou um cara das antigas (+40) e que já trabalhava com desenvolvimento antes do início do [Jquery](https://coderwall.com/p/cekryw/history-of-jquery) e [Prototype](http://prototypejs.org/2007/01/18/prototype-documentation-is-here/). Nunca fiz faculdade na área, mas sou formado em faculdade pública de Música e Belas Artes... pois é.

Enfim, só pra dizer que já vi muita coisa por aí. Conceitos e ideias que vão em e vem, problemas antigos com novos nomes e soluções velhas com nova roupagem.

Mas o que quero focar aqui é sobre estilos numa aplicação WEB.

Nos últimos anos, trabalhando como desenvolvedor sênior em empresas de vários tamanhos, cada vez mais fui me afastando do CSS que, modéstias a parte, conheço muito bem e sempre achei divertido e terapêutico. Nunca reclamei disso, é mais que comum utilizar algum Design System já projetado e você "só" vai programando os blocos (às vezes aplicando Atomic Design, que já renderia outro artigo, quando faz sentido) e sem se preocupar muito com o estilo dos componentes.

Quando precisa ajustar algo, geralmente o projeto utiliza algum [CSS-in-JS](https://en.wikipedia.org/wiki/CSS-in-JS) como [Styled Components](https://styled-components.com/), [Emotion](https://emotion.sh/docs/introduction), [Stitches](https://stitches.dev/), [Linaria](https://linaria.dev/) e etc. Eles são ótimos, usei por muito tempo e adoro usá-los quando faz sentido.

Certa vez eu utilizei [Sass](https://sass-lang.com/) com [CSS Modules](https://github.com/css-modules/css-modules) para estilizar um teste prático de front end para uma vaga numa empresa de médio porte e um dos "programadores sêniors" me perguntou na entrevista:

> Qual o motivo de usar _Sass_? É algo incomum hoje em dia. Por que você não escolheu _CSS in JS_? Não acha uma má prática voltar a usar _CSS_ ou _Sass_?

Apenas sorri. Mas, ao longo do tempo, vi cada vez mais programadores front-end que não sabiam quase nada de _CSS_, _Modules_, _Custom Properties_, o poder do efeito em cascata e suas inúmeras possibilidades. Profissionais que já entram no mercado apenas utilizando _JS/TS_ como padrão para escrever os estilos e veem _CSS_ como algo obsoleto, fora de moda. Que loucura!

Voltando ao meu caso. Nesse projeto zero em folha, decidi usar [Server Components](https://react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) junto com o [NextJs](https://nextjs.org/) e dar uma chance ao tão comentado [TailWind Css](https://tailwindcss.com/). É um projeto relativamente complexo, com grande foco na experiência do usuário, com interface simples mas com detalhes de interações diferenciadas e múltiplos temas.

Posto isso, eis minhas conclusões após 4 meses de uso diário.

## O que é o Tailwind CSS?

Em resumo, para quem caiu aqui de paraquedas, o _Tailwind CSS_ é um framework de _CSS_ como o antigo [Bootstrap](https://getbootstrap.com/).

A diferença principal é que **cada classe no _Tailwind_ equivale a uma propriedade do _CSS_** (ou pseudo classe/elemento) mas com o nome ligeiramente diferente. O chamado [Utility-first](https://heydonworks.com/article/what-is-utility-first-css/).

Por exemplo:

- A classe `z-0` resulta na propriedade `z-index: 0;`.
- A classe `overflow-hidden` resulta na propriedade `overflow: hidden;`.
- A classe `hover:underline` resulta na pseudo classe `:hover { text-decoration: underline; }`

## Estética controversa

Nos exemplos que lemos por aí, inclusive na própria [documentação](https://tailwindcss.com/docs/installation), encontramos este tipo de estrutura de marcação:

`<div class="w-9 h-9 rounded-lg flex items-center justify-center text-slate-700 peer-checked:font-semibold peer-checked:bg-slate-900 peer-checked:text-white">`

Eu ligo muito para estética funcional do código (beleza + facilidade de ler), _clean code_ com bom senso e organização. 

Ao ler o código acima, isso me causa incômodo. Acho difícil compreender rapidamente o que está acontecendo e perco o foco com todas essas classes que estão poluindo minha marcação.

Na minha opinião, marcação e estilo devem ser isolados o máximo possível. Eu não preciso saber que um elemento tem posição `flex` se não quero saber disso naquele momento.

Meu pensamento foi: 

> Tudo bem, são apenas exemplos, dá pra contornar. Vou criar uma função para lidar com isso.

E resolvi assim:

Cada componente, que continha algo estilizado, eu criei um `styles.js`.

```js
import { cleanClasses } from '@helpers'

export default function classNames({ hasSomeProp }) {
  return {
    content: cleanClasses(`
      ${hasSomeProp ? 'border-green' : 'border-black'}
      border
      flex
      h-9
      items-center
      justify-center
      peer-checked:bg-slate-900
      peer-checked:font-semibold
      peer-checked:text-white
      rounded-lg
      text-slate-700
      w-9
    `),
  }
}
```

_obs.: Sempre ordeno minhas propriedades em ordem alfabética_.

E, dentro do meu componente, importei esse arquivo e apliquei ao elemento.

```js
import classNames from './styles'

export default function MyComponent({ children, hasSomeProp }) {
  const c = classNames({ hasSomeProp } )
  return <div className={c.content}>{children}</div>
}
```

Resolvido, pensei eu!
Isolo todas as classes e deixo meu componente limpo! 🤘

Mas repare que no `styles.js` tem uma função chamada `cleanClasses()`. Eu tive que criá-la por conta da identação usando o [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) que estava zoando a [minificação](https://en.wikipedia.org/wiki/Minification_(programming)) final do html.

Para resolver, **e manter minha identação do jeito que acho que faz sentido**, criei uma função para remover caracteres desnecessários que atrapalham a minificação no final do build.

```js
import { isString } from '@helpers'

export default function cleanClasses(value) {
  if (!isString(value)) return ''

  const removeFalsyValues = value.replace(
    /\b(?:undefined|null|false|NaN|'')\b/g,
    '',
  )
  const removeExtraSpaces = removeFalsyValues.replace(/\s+/g, ' ')
  const cleanedClasses = removeExtraSpaces.trim()

  return cleanedClasses
}
```

Gostei da solução e me atendeu bem, mas já comecei a ficar com uma pulga atrás da orelha...

Eu gosto de programar mas sou preguiçoso, quanto menos eu programo mais eu gosto de programar. 😂

## Abstrações desnecessárias

A documentação do _Tailwind_ começou a ser parte do meu dia a dia de trabalho. Sempre havia uma aba aberta para eu consultar e ter certeza de que tal classe era a propriedade que eu queria. 

E é normal, eu tenho que aprender o framework. Mas essa dependência em decorar classes, que são nomeações das propriedades (que eu já sabia _de cór_ no _CSS_), começou a me irritar e achar as abstrações desnecessárias.

De certa forma, me atrevo a dizer, estava "desdecorando" as propriedades de CSS puro.

Usei esse termo de propósito pois depois de poucos meses usando _TW_, e já migrado o projeto para CSS Modules, eu me vi adicionando classes do Tailwind ao invés das propriedades de CSS. Como são nomes parecidos, meu cérebro simplesmente acabou substituindo esses valores.

Por exemplo, você sabe a qual propriedade a classe do Tailwind `justify-center` se refere?

- :radio_button: `justify-content: center;`
- :radio_button: `justify-items: center;`
- :radio_button: `justify-self: center;`
- :radio_button: `justify-tracks: center;`

Dica, `justify-tracks` ainda é experimental e nem existe no Tailwind.

Se você ficou na dúvida, vai ter que ir na [documentação](https://tailwindcss.com/docs/justify-content). 🤡

## Lidando com seletores mais complexos

Um aspecto que não achei produtivo foi utilizar seletores mais complexos. Enquanto você estiliza apenas um único elemento é OK, mas quando precisa de algo mais complexo e que envolve outros elementos a coisa fica esquisita.

Por exemplo, digamos que eu precise modificar os itens, que não tenho acesso e não posso modificá-los, de uma lista.
_obs.: Isso está longe de ser complexo._

```jsx
<ul className={styles.ul}>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
```

Com Tailwind eu teria que adicionar algo como:
```jsx
import { cleanClasses } from '@helpers'

export default function classNames() {
  return {
    ul: cleanClasses(`
      [&_li]:rounded-full
      [&_li]:border
      [&_li]:border-black
      [&_li]:bg-white
      [&_li]:px-2
      [&_li]:py-0.5
    `),
  }
}
```

É muito verboso dizer que cada propriedade é um item da lista com `[&_li]` e ter que informar isso, repetidas vezes, em cada classe do _TW_. Sem falar que não consigo usar [shorthand properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties). Tem plugin pra isso, mas não quero entupir minha aplicação com pacotes.

Com CSS eu apenas declaro como:

```css
.ul li {
  background: var(--color__white);
  border-radius: var(--radius__full);
  border: 1px solid var(--color__black);
  padding: var(--size__0-5) var(--size__2);
}
```

E nem vou entrar em detalhe de [sibling selectors](https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-sibling-state) e outros seletores que são triviais com CSS nativo. Sinto-me reinventando a roda mas essa roda não é lá muito redonda. 😂

## Temas

Outra coisa que não gostei foi a forma de adicionar múltiplos temas e seus diversos [design tokens](https://thedesignsystem.guide/design-tokens) usando o _TW_. Pensei que ele lidaria com isso de forma nativa, mas não.

Uma possibilidade é instalar mais uma dependência como a [tw-colors](https://github.com/L-Blondy/tw-colors), já que não temos isso nativamente no framework (só podemos alterar os tokens do tema atual). Ela é muito boa e funciona bem.

Outra possibilidade é usar as variáveis de CSS nativas e informar ao Tailwind como usá-las... mas pera aí, eu não quero isso já que escolhi o framework para lidar com os estilos. Quero apenas usar o Tailwind e sua turminha.

## Cadê o efeito em cascata?

Rapidamente aprendi que o _TW_ remove uma das coisas mais importantes do CSS (que, inclusive, é o significado da primeira letra do seu acrônimo: **Cascade** Style Sheets.

_obs.: A versão usada foi a `3.3.3`, provavelmente vão resolver isso no futuro._

Por exemplo, há situações em que você precisa sobrescrever algum estilo para customizar componentes já existentes.
Vamos supor que você tenha um componente que é usado em vários lugares, mas, num único lugar específico, você precisa que ele tenha algo diferente e só precisa sobrescrever uma propriedade de CSS. Adicionar uma nova prop ao componente, que só vai ser usada ali, não seria uma boa ideia.

No código abaixo, em função do efeito em cascata, espera-se que o valor `white` seja substituído pelo `black` na propriedade `background` do `ChildComponent`. Porque quando chamamos esse componente adicionamos um outro background que deve sobrescrever o default.

Ou seja, tudo o que está declarado depois e com a mesma [especificidade](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity), tem uma ordem de importância maior que a propriedade anterior.

A renderização da `div` abaixo seria `<div class="bgWhite bgBlack" />`

```jsx
import { ChildComponent } from './components'
import styles from './styles.module.css'
// .bgBlack { background: black; }

export default function ParentComponent() {
  return (
    <ChildComponent className={styles.bgBlack} />
  )
}
```

```jsx
import styles from './styles.module.css'
// .bgWhite { background: white; }

export default function ChildComponent({ className }) {
  const bgStyles = [styles.white, className].join(' ')

  return (
    <div className={bgStyles}>
      Some Text
    </div>
  )
}
```

Já no Tailwind, se a renderização do seu componente for `<div class="bg-white bg-black" />` o `bg-black` não necessariamente sobrescreverá o `bg-white`, porque isso vai depender da ordem interna de classes do _TW_.

Ou seja, não há garantia que o efeito cascata seja aplicado! Poxa, mas é para isso que pago o CSS! 😅

Você consegue resolver isso, mas, adivinha, vai precisar acoplar mais uma dependência ao seu projeto usando o [tailwind-merge](https://github.com/dcastil/tailwind-merge) que irá remover as classes indesejadas já que o efeito em cascata não funciona. Ou usar o **!important**. 😒

## Decisão após análise

E, finalmente, como já foi dito, cheguei a conclusão que, para o meu caso, o ideal seria remover tudo relacionado ao _Tailwind_ (`tailwindcss`, `postcss`, `tw-colors` e `tailwind-merge`) e usar apenas _CSS Modules_ (já fornecido pelo _NextJs_ como padrão).

Achei interessante a experiência de usar o Tailwind mas não me convenceu 100%. Tive que criar muitas soluções extras e instalações de pacotes para deixar minha experiência do jeito que acho que funciona.

Para projetos de prototipação, MVPs, ou até mesmo se a equipe seja apenas de devs back-end (que não querem aprender CSS), pode ser. 

Mas se eu for criar um novo produto eu já descarto o uso do Tailwind. Ter um design tokens organizado com variáveis em CSS e usar CSS Modules é a escolha mais natural e eficiente pra mim. Nem de Sass eu iria. O básico bem feito é a tendência para os próximos anos, na verdade nunca deixou de ser.

Enfim, voltei a ter prazer em escrever e ler CSS.


![Print de um pull request do Github](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gnfafcguzge2pb759slo.png)