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:
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>
);
} 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:
.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;
} import styles from "./ArticleCard.module.css";
export function ArticleCard({ artigo }: ArticleCardProps) {
return (
<article className={styles.card}>
<h2 className={styles.titulo}>{artigo.titulo}</h2>
</article>
);
} 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:
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>
);
} 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:
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' },
}); import { card, botaoVariantes } from './styles.css';
<article className={card}>...</article>
<button className={botaoVariantes[curtido ? 'curtido' : 'padrao']}>...</button> 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.
Qual é a principal vantagem do Tailwind CSS em relação ao CSS puro?
O que CSS Modules resolve que CSS global não resolve?
Qual é o problema de styled-components em comparação com soluções build-time?
Quando faz sentido usar CSS global em vez de qualquer solução de escopo?
Aula concluída
Quase lá.