Design Responsivo
Breakpoints, container queries e padrões mobile-first no Tailwind CSS v4.
Busque em todas as páginas da documentação
Breakpoints, container queries e padrões mobile-first no Tailwind CSS v4.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida - pronto para copiar e colar.
// Breakpoints mobile-first (min-width)
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
// Breakpoints padrão: sm(40rem) md(48rem) lg(64rem) xl(80rem) 2xl(96rem)
// Variante de largura máxima
<div className="max-lg:hidden"> {/* oculto abaixo de lg */}
// Intervalo
<div className="md:max-xl:flex"> {/* flex apenas entre md e xl */}
// Container queries
<div className="@container">
<div className="@sm:flex @lg:grid @lg:grid-cols-2">
{/* responde à largura do container, não à viewport */}
</div>
</div>
// Containers nomeados
<div className="@container/sidebar">
<div className="@md/sidebar:block">Quando usar isso: Quando seu layout ou componente precisa se adaptar a diferentes tamanhos de tela ou tamanhos de container.
export function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex min-h-screen flex-col lg:flex-row">
{/* Sidebar - largura total no mobile, largura fixa no desktop */}
<aside className="border-b bg-gray-50 p-4 lg:w-64 lg:shrink-0 lg:border-b-0 lg:border-r">
<nav className="flex gap-2 overflow-x-auto lg:flex-col lg:gap-1 lg:overflow-visible">
<a href="#" className="whitespace-nowrap rounded px-3 py-2 text-sm hover:bg-gray-200 lg:whitespace-normal">
Dashboard
</a>
<a href="#" className="whitespace-nowrap rounded px-3 py-2 text-sm hover:bg-gray-200 lg:whitespace-normal">
Analytics
</a>
<a href="#" className="whitespace-nowrap rounded px-3 py-2 text-sm hover:bg-gray-200 lg:whitespace-normal">
Settings
</a>
</nav>
</aside>
{/* Conteúdo principal */}
<main className="flex-1 p-4 md:p-6 lg:p-8">
{/* Grid de estatísticas - colunas responsivas */}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-4">
<StatCard label="Receita" value="$12,345" />
<StatCard label="Usuários" value="1,234" />
<StatCard label="Pedidos" value="567" />
<StatCard label="Conversão" value="3.2%" />
</div>
{/* Área de conteúdo com container queries */}
<div className="mt-6 grid gap-6 lg:grid-cols-[1fr_300px]">
<section className="@container">
<div className="@md:grid @md:grid-cols-2 @md:gap-4 space-y-4 @md:space-y-0">
{children}
</div>
</section>
<aside className="max-lg:hidden">
<div className="sticky top-4 rounded border p-4">
<h3 className="font-medium">Feed de Atividade</h3>
</div>
</aside>
</div>
</main>
</div>
);
}
function StatCard({ label, value }: { label: string; value: string }) {
return (
<div className="rounded-lg border bg-white p-4 shadow-sm">
<p className="text-sm text-gray-500">{label}</p>
<p className="mt-1 text-2xl font-bold">{value}</p>
</div>
);
}O que isso demonstra:
lggrid-cols-1 a grid-cols-4)max-lg:hidden para ocultar elementos abaixo de um breakpointsticky sidebar no desktop@media (min-width: ...) - md:flex significa @media (width >= 48rem) { display: flex }max-* compilam para @media (width < ...) - úteis para estilos apenas para mobile@container no pai e @sm:, @md:, etc. nos filhos@3xs(12rem) @2xs(16rem) @xs(20rem) @sm(24rem) @md(28rem) @lg(32rem) @xl(36rem) @2xl(42rem) etc.rem por padrão, não em pxBreakpoints customizados:
@theme {
--breakpoint-xs: 30rem; /* 480px */
--breakpoint-3xl: 120rem; /* 1920px */
}Container query com tamanhos customizados:
@theme {
--container-4xs: 8rem;
}Tipografia responsiva:
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl">
Título Responsivo
</h1>
{/* Ou use clamp para dimensionamento fluido */}
<h1 className="text-[clamp(1.5rem,4vw,3rem)]">
Título Fluido
</h1>Mostrar/Ocultar Responsivo:
{/* Mostrar apenas no mobile */}
<div className="md:hidden">Nav mobile</div>
{/* Mostrar apenas no desktop */}
<div className="hidden md:block">Nav desktop</div>
{/* Mostrar entre md e xl */}
<div className="hidden md:block xl:hidden">Apenas tablet</div>Cartão com container query:
function AdaptiveCard({ children }: { children: React.ReactNode }) {
return (
<div className="@container">
<div className="flex flex-col @sm:flex-row @sm:items-center gap-4 rounded border p-4">
<div className="size-16 shrink-0 rounded bg-gray-200 @sm:size-20" />
<div className="flex-1">{children}</div>
</div>
</div>
);
}// Variantes responsivas são nomes de classe - sem impacto no TS
// Mas você pode tipar props dependentes de breakpoint:
interface LayoutProps {
columns?: {
default: number;
sm?: number;
md?: number;
lg?: number;
};
}
function Grid({ columns }: LayoutProps) {
const colClasses = {
1: "grid-cols-1",
2: "grid-cols-2",
3: "grid-cols-3",
4: "grid-cols-4",
} as const;
return (
<div className={cn(
"grid gap-4",
colClasses[columns.default as keyof typeof colClasses],
columns.sm && `sm:${colClasses[columns.sm as keyof typeof colClasses]}`,
)}>
{/* Nota: construção dinâmica de classes não funciona com Tailwind - veja Armadilhas */}
</div>
);
}Nomes de classe dinâmicos não são detectados - sm:grid-cols-${n} nunca é encontrado pelo scanner do Tailwind. Correção: Use nomes de classe estáticos completos ou adicione-os à safelist.
max-* é <, não <= - max-md:hidden significa oculto quando a viewport é estritamente menor que md. Exatamente em 48rem, md: assume o controle.
Container queries precisam de um pai @container - Sem ele, @sm:flex não faz nada. Correção: Sempre adicione @container ao elemento cuja largura você deseja consultar.
hidden no mobile + mostrar em breakpoint - hidden md:flex funciona, mas hidden md:block mostra como block. Certifique-se de que o valor de exibição corresponda ao que você deseja.
Breakpoint de impressão - Use print: para estilos específicos de impressão: print:hidden, print:text-black. Frequentemente esquecido, mas importante para páginas imprimíveis.
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
@media CSS diretamente | Você precisa de media queries complexas (hover, prefers-reduced-motion) | Breakpoints padrão são suficientes |
@container CSS diretamente | Você precisa de recursos de container query além do suporte do Tailwind | As utilidades @container do Tailwind cobrem suas necessidades |
Hook useMediaQuery | Você precisa de lógica responsiva em nível de JS (componentes diferentes) | Mudanças de layout apenas com CSS são suficientes |
Imagens responsivas (srcset) | Você precisa de arquivos de imagem diferentes por breakpoint | Você só precisa de mudanças de layout |
Utilitários sem prefixo se aplicam a todos os tamanhos de tela. Prefixos de breakpoint como md: aplicam-se a partir desse tamanho e acima (min-width). Você estiliza o mobile primeiro, depois adiciona substituições para telas maiores.
sm = 40rem, md = 48rem, lg = 64rem, xl = 80rem, 2xl = 96remrem, não em px.<div className="hidden md:block xl:hidden">Apenas tablet</div>max-lg:hidden - oculto abaixo de lg (viewport < 64rem)lg:hidden - oculto em lg e acima (viewport >= 64rem)@container a um elemento pai@sm:, @md:, @lg: etc. nos filhos@theme {
--breakpoint-xs: 30rem;
--breakpoint-3xl: 120rem;
}<h1 className="text-[clamp(1.5rem,4vw,3rem)]">Título Fluido</h1>O tamanho da fonte escala suavemente entre 1.5rem e 3rem com base na largura da viewport.
O scanner do Tailwind não consegue detectar nomes de classe dinâmicos construídos com template literals. Use nomes de classe estáticos completos ou um mapa de consulta em vez disso.
O elemento pai precisa de className="@container". Sem ele, não há container para consultar.
interface LayoutProps {
columns?: {
default: number;
sm?: number;
md?: number;
lg?: number;
};
}Em seguida, use um mapa de consulta estático para converter números em strings de classe - nunca interpole dinamicamente.
Use a variante print:: print:hidden, print:text-black. Isso compila para @media print.
<div className="@container/sidebar">
<div className="@md/sidebar:block">Containers nomeados permitem consultar um ancestral específico quando múltiplos elementos @container são aninhados.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥