af aprenda frontend
módulo 08 horizonte

Estilização avançada — além do CSS puro.

Tailwind CSS, CSS Modules, styled-components, vanilla-extract, Panda. Tradeoffs entre runtime, build time e bundle.

O curso usou CSS puro com variáveis customizadas e Tailwind. No mercado, existem várias abordagens de estilização — cada uma com tradeoffs de ergonomia, performance e manutenção. Esta lição mapeia o panorama: o que existe, quando cada abordagem faz sentido, e como escolher.

Por que o CSS puro às vezes não basta

CSS puro tem um problema fundamental em aplicações grandes: escopo global. Um seletor .titulo em ArticleCard.css pode afetar qualquer elemento com classe titulo na página — incluindo os do Header, do Footer, ou de uma biblioteca de componentes.

Soluções de estilização avançada existem principalmente para resolver esse problema — além de adicionar tipagem, colocação de estilos junto ao componente, e melhor experiência de desenvolvimento.

Tailwind CSS — utility-first

Tailwind é um framework de utilitários — em vez de escrever .card { display: flex; gap: 16px; }, você escreve classes diretamente no JSX:

tsx
export function ArticleCard({ artigo }: ArticleCardProps) {
  return (
    <article className="flex flex-col gap-4 p-6 rounded-xl border border-gray-200 hover:shadow-md transition-shadow">
      <div className="flex gap-2 flex-wrap">
        {artigo.tags.map(tag => (
          <span key={tag} className="text-xs font-mono bg-gray-100 px-2 py-1 rounded">
            {tag}
          </span>
        ))}
      </div>
      <h2 className="text-xl font-semibold leading-tight">{artigo.titulo}</h2>
      <p className="text-gray-600 text-sm line-clamp-2">{artigo.descricao}</p>
    </article>
  );
}
ArticleCard com Tailwind — utilitários no JSX.

Vantagens: sem conflitos de nomes de classe, bundle de CSS mínimo em produção (Tailwind extrai apenas as classes usadas), e ergonomia alta uma vez que você aprende as classes. Em equipes, elimina discussões sobre nomeação e organização de CSS.

Desvantagens: a legibilidade do JSX diminui com muitas classes. className="flex flex-col gap-4 p-6 rounded-xl border border-gray-200 hover:shadow-md transition-shadow" é mais difícil de ler que .card. Customização (quebrar do design system) pode ser mais trabalhosa.

Quando usar: projetos com equipe, onde consistência e velocidade de desenvolvimento valem mais que legibilidade do markup. Este site usa Tailwind.

CSS Modules — escopo em build time

CSS Modules transformam nomes de classe em identificadores únicos durante o build:

css
.card {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.5rem;
  border-radius: 0.75rem;
  border: 1px solid var(--color-line);
}

.titulo {
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.3;
}
ArticleCard.module.css — CSS com escopo automático.
tsx
import styles from "./ArticleCard.module.css";

export function ArticleCard({ artigo }: ArticleCardProps) {
  return (
    <article className={styles.card}>
      <h2 className={styles.titulo}>{artigo.titulo}</h2>
    </article>
  );
}
ArticleCard.tsx — importar classes do módulo.

Em build, .titulo se torna algo como .ArticleCard_titulo_x7k2p — único, sem possibilidade de conflito. Você escreve CSS normal, com nomes semânticos, mas o escopo é garantido.

Vantagens: CSS familiar, escopo automático, sem runtime no browser, boa integração com Vite e Next.js.

Desvantagens: compartilhar estilos entre componentes exige um arquivo de estilos compartilhados. A colocação de estilos em arquivo separado divide a atenção entre dois arquivos por componente.

Quando usar: quando você prefere CSS tradicional mas quer garantia de escopo. Boa opção em projetos que migram de CSS global.

styled-components e CSS-in-JS em runtime

CSS-in-JS em runtime escreve CSS dentro do JavaScript — os estilos são gerados e injetados no browser:

tsx
import styled from 'styled-components';

const BotaoCurtir = styled.button<{ $curtido: boolean }>`
  border-radius: 9999px;
  padding: 0.5rem 1rem;
  background: ${({ $curtido }) => $curtido ? '#fee2e2' : '#f3f4f6'};
  color: ${({ $curtido }) => $curtido ? '#dc2626' : '#374151'};
  cursor: pointer;

  &:hover {
    opacity: 0.9;
  }
`;

export function LikeButton({ curtido, contagem, onCurtir }: LikeButtonProps) {
  return (
    <BotaoCurtir $curtido={curtido} onClick={onCurtir} aria-pressed={curtido}>
      {curtido ? '❤️' : '🤍'} {contagem}
    </BotaoCurtir>
  );
}
LikeButton com styled-components.

Vantagens: estilos colocalizados com o componente, props disponíveis para lógica de estilo, ThemeProvider para temas.

Desvantagens: runtime no browser — styled-components injeta <style> tags via JavaScript. Isso aumenta o bundle, pode causar flash de conteúdo não estilizado (FOUC) em SSR, e adiciona latência. Em React Server Components (Next.js App Router), styled-components não funciona sem configuração extra.

Quando usar: projetos React sem SSR, equipes já familiarizadas com a biblioteca, ou quando a prop-driven styling vale o custo de runtime.

vanilla-extract e Panda — CSS-in-JS em build time

Soluções modernas como vanilla-extract e Panda CSS oferecem ergonomia de CSS-in-JS mas geram CSS estático em build time — zero runtime:

ts
import { style, styleVariants } from '@vanilla-extract/css';

export const card = style({
  display: 'flex',
  flexDirection: 'column',
  gap: '1rem',
  padding: '1.5rem',
  borderRadius: '0.75rem',
});

// variantes tipadas — sem className condicional manual
export const botaoVariantes = styleVariants({
  padrao: { background: '#f3f4f6', color: '#374151' },
  curtido: { background: '#fee2e2', color: '#dc2626' },
});
styles.css.ts — vanilla-extract, tipado e em build time.
tsx
import { card, botaoVariantes } from './styles.css';

<article className={card}>...</article>
<button className={botaoVariantes[curtido ? 'curtido' : 'padrao']}>...</button>
Usar variantes no componente.

O CSS gerado é estático — sem injeção em runtime, sem problemas em SSR.

Quando usar: projetos Next.js com App Router (onde runtime CSS-in-JS é problemático), ou quando você quer a ergonomia de CSS-in-JS sem o custo de runtime.

O que o curso usa

Este site usa Tailwind CSS v4 para a maioria dos estilos. Essa escolha reflete os tradeoffs: velocidade de desenvolvimento, sem conflitos de nomes, bundle mínimo em produção. Para um projeto de documentação/curso como este, a legibilidade do markup é menos crítica do que a consistência e velocidade.

Resumo

  • CSS puro: simples, sem dependências. Problema de escopo global em projetos grandes.
  • Tailwind: utility-first, bundle mínimo, alta velocidade. Markup menos legível.
  • CSS Modules: CSS familiar com escopo automático, sem runtime. Dois arquivos por componente.
  • styled-components / Emotion: CSS-in-JS em runtime. Ergonomia alta, mas custo de bundle e problemas em SSR.
  • vanilla-extract / Panda: CSS-in-JS tipado em build time. Melhor opção para Next.js App Router.
  • CSS global ainda tem lugar: tokens de design, reset, fontes. Complementa qualquer solução de escopo.
/ checkpoint verifique seu entendimento
questão 1 de 4

Qual é a principal vantagem do Tailwind CSS em relação ao CSS puro?