Media queries com Claude Code: guia CSS prático
Implemente CSS responsivo com Claude Code: media queries, container queries, preferências e testes Playwright.
Uma página pode parecer perfeita no notebook e falhar no ponto que gera resultado: leitura no celular, cartão de afiliado dentro de uma coluna estreita, modo escuro ou tela administrativa usada por horas. Pedir ao Claude Code “deixe responsivo” é amplo demais. O melhor é entregar regras de layout, preferências de usuário e uma forma de validar.
Media query aplica CSS quando o ambiente do navegador atende a uma condição. Container query aplica CSS conforme o tamanho do contêiner pai do componente. prefers-reduced-motion e prefers-color-scheme respeitam escolhas do sistema do leitor. Use as fontes oficiais: MDN CSS media queries, Using media queries, CSS container queries, CSSWG Media Queries Level 5, W3C CSS Containment Module Level 3 e Playwright emulation.
Para base, leia também CSS Grid com Claude Code, padrões Flexbox, acessibilidade e performance.
Regra principal
Comece mobile-first. O layout pequeno é o CSS padrão; telas maiores recebem ajustes com @media (width >= 48rem). Não escolha breakpoints por nomes de aparelhos. Escolha quando o conteúdo começa a sofrer: navegação quebra mal, cards ficam apertados, anúncios encostam no texto ou formulários ficam difíceis de ler.
| Decisão | Media queries | Container queries |
|---|---|---|
| Observa | Viewport, impressão, preferências | Tamanho ou estado do contêiner pai |
| Melhor uso | Layout da página, navegação, espaçamento global | Cards, CTA, preços, UI reutilizável |
| Erro comum | Breakpoints por aparelho demais | Esquecer container-type |
| Prompt | “Mude o layout pela largura do viewport” | “Mude o card pela largura disponível” |
Casos reais
Em um artigo de blog, empilhe texto, CTA e relacionados no celular. Adicione sidebar só quando houver largura suficiente. Cards de afiliado e produto devem usar container queries para funcionar no corpo, na sidebar e em blocos relacionados.
Em uma página de preços SaaS, o mesmo card aparece na home, landing page e checkout. Se o CSS olhar apenas para o viewport, o card pode assumir layout largo dentro de uma coluna estreita.
Em um painel administrativo, filtros, tabela, exportação e busca competem por espaço. Em telas pequenas, a tabela pode virar cards; em telas largas, mantém colunas. prefers-reduced-motion evita movimento cansativo em uso prolongado.
Em conteúdo monetizado, CTAs precisam aparecer sem esmagar a leitura. Use media queries para o ritmo da página e container queries para o interior do CTA.
HTML/CSS para copiar
Salve como responsive-demo.html e abra no navegador. O exemplo usa mobile-first, container queries, modo escuro, redução de movimento e tipografia com clamp(). Evite font-size: 4vw; o texto pode ficar gigante em telas largas e pequeno em telas estreitas.
<!doctype html>
<html lang="pt">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Responsive media query demo</title>
<style>
:root { color-scheme: light dark; --bg: #f7f8fb; --surface: #ffffff; --text: #1f2937; --line: #d8dee8; --accent: #0f766e; --accent-strong: #115e59; --shadow: 0 12px 30px rgb(15 23 42 / 0.12); }
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-size: clamp(1rem, 0.94rem + 0.25vw, 1.125rem); line-height: 1.7; color: var(--text); background: var(--bg); }
a { color: var(--accent-strong); }
.site-header { padding: 1rem; border-bottom: 1px solid var(--line); background: var(--surface); position: sticky; top: 0; z-index: 10; }
.nav { display: flex; flex-wrap: wrap; gap: 0.75rem 1rem; align-items: center; justify-content: space-between; max-width: 72rem; margin: 0 auto; }
.brand { font-weight: 800; }
.nav-links { display: flex; gap: 0.75rem; padding: 0; margin: 0; list-style: none; }
.page { width: min(100% - 2rem, 72rem); margin: 2rem auto; display: grid; gap: 1.5rem; }
.hero, .article, .sidebar-card, .offer { background: var(--surface); border: 1px solid var(--line); border-radius: 8px; box-shadow: var(--shadow); }
.hero { padding: clamp(1.25rem, 1rem + 1.5vw, 2.5rem); }
h1 { margin: 0 0 0.75rem; font-size: clamp(2rem, 1.65rem + 1.6vw, 3.2rem); line-height: 1.15; }
.layout { display: grid; gap: 1.5rem; }
.article, .sidebar-card { padding: 1rem; }
.sidebar { display: grid; gap: 1rem; align-content: start; }
.offer-wrap { container-type: inline-size; container-name: offer; }
.offer { display: grid; gap: 1rem; padding: 1rem; overflow: hidden; }
.offer-media { min-height: 10rem; border-radius: 6px; background: linear-gradient(135deg, rgb(15 118 110 / 0.85), rgb(37 99 235 / 0.75)), repeating-linear-gradient(45deg, rgb(255 255 255 / 0.18) 0 10px, transparent 10px 20px); }
.button { display: inline-flex; width: fit-content; min-height: 2.75rem; align-items: center; justify-content: center; padding: 0.7rem 1rem; border-radius: 6px; background: var(--accent); color: white; font-weight: 700; text-decoration: none; transition: transform 180ms ease, background-color 180ms ease; }
.button:hover { transform: translateY(-2px); background: var(--accent-strong); }
@media (width >= 48rem) { .article { padding: 1.5rem; } .layout { grid-template-columns: minmax(0, 1fr) 18rem; align-items: start; } }
@media (width >= 72rem) { .layout { grid-template-columns: minmax(0, 2fr) minmax(18rem, 0.8fr); } }
@container offer (width >= 34rem) { .offer { grid-template-columns: 14rem minmax(0, 1fr); align-items: center; padding: 1.25rem; } }
@media (prefers-color-scheme: dark) { :root { --bg: #10151f; --surface: #18202d; --text: #eef2f7; --line: #334155; --accent: #2dd4bf; --accent-strong: #5eead4; --shadow: none; } }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; scroll-behavior: auto !important; transition-duration: 0.01ms !important; } }
</style>
</head>
<body>
<header class="site-header"><nav class="nav" aria-label="Main navigation"><div class="brand">ClaudeCodeLab</div><ul class="nav-links"><li><a href="#guide">Guide</a></li><li><a href="#offer">Template</a></li></ul></nav></header>
<main class="page"><section class="hero"><h1>Media queries that survive real layouts</h1><p>Mobile-first CSS, cards com container queries, modo escuro e movimento reduzido.</p></section><div class="layout" id="guide"><article class="article"><h2>Readable article body</h2><p>The article stays readable on phones and gains a sidebar only when there is enough room.</p><div class="offer-wrap" id="offer"><section class="offer"><div class="offer-media" aria-hidden="true"></div><div><h2>Responsive review checklist</h2><p>Use this area for a download, newsletter or product CTA.</p><a class="button" href="#">Get the checklist</a></div></section></div></article><aside class="sidebar" aria-label="Related content"><section class="sidebar-card"><h2>Related</h2><p>Grid, Flexbox, accessibility and performance belong in the same review.</p></section></aside></div></main>
</body>
</html>
Prompts para Claude Code
Objetivo: CSS responsivo da página de artigo
Regras:
- Base mobile-first
- Media queries de viewport só para layout global
- Container queries para cards e CTAs reutilizáveis
- Não usar font-size apenas com vw; usar clamp()
- Respeitar prefers-color-scheme e prefers-reduced-motion
Verificação:
- Testar 375, 768, 1024 e 1440 px
- Testar dark mode e reduced motion no Playwright
- Apontar breakpoints duplicados ou desnecessários
Revise este diff como CSS responsivo.
Priorize overflow horizontal, texto ilegível, CTA/anúncio esmagado,
falta de container-type, violação de reduced-motion e excesso de breakpoints.
Retorne apenas linhas específicas e correções mínimas.
Teste com Playwright
import { test, expect } from "@playwright/test";
const fileUrl = "file:///absolute/path/to/responsive-demo.html";
for (const width of [375, 768, 1024, 1440]) {
test(`no horizontal overflow at ${width}px`, async ({ page }) => {
await page.setViewportSize({ width, height: 900 });
await page.goto(fileUrl);
const hasOverflow = await page.evaluate(() => document.documentElement.scrollWidth > document.documentElement.clientWidth);
await expect(hasOverflow).toBe(false);
await expect(page.locator(".offer")).toBeVisible();
});
}
test("dark mode keeps text readable", async ({ page }) => {
await page.emulateMedia({ colorScheme: "dark" });
await page.goto(fileUrl);
await expect(page.locator("body")).toHaveCSS("color", "rgb(238, 242, 247)");
});
test("reduced motion disables hover timing", async ({ page }) => {
await page.emulateMedia({ reducedMotion: "reduce" });
await page.goto(fileUrl);
const duration = await page.locator(".button").evaluate((el) => getComputedStyle(el).transitionDuration);
expect(duration).toBe("0.01ms");
});
flowchart TD
A["CSS mobile-first"] --> B["Media queries para layout"]
B --> C["Container queries para cards"]
C --> D["Preferências do usuário"]
D --> E["Screenshots e overflow no Playwright"]
E --> F["Prompt de revisão Claude Code"]
Erros e monetização
Evite empilhar max-width, usar viewport para componente reutilizável, definir fonte apenas com vw e ignorar reduced motion. Depois que Claude Code gerar CSS, valide textos traduzidos, CTAs reais, anúncios, modo escuro e larguras estreitas.
CSS responsivo protege receita: ofertas continuam visíveis sem prejudicar a leitura. Use um CTA discreto no meio do artigo para uma checklist gratuita e um CTA mais forte no final para templates ou consultoria. Veja o material gratuito, produtos ou treinamento.
No teste prático de Masa, a maior melhoria veio ao mover o card de CTA para container query. O mesmo card funcionou no corpo, na sidebar e nos relacionados sem novo breakpoint de viewport. Playwright confirmou ausência de overflow em 375px, texto legível no modo escuro e movimento reduzido aplicado.
PDF grátis: cheatsheet do Claude Code
Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.
Cuidamos dos seus dados e não enviamos spam.
Sobre o autor
Masa
Engenheiro focado em workflows práticos com Claude Code.
Artigos relacionados
Como pedir ao Claude Code para mexer em um único arquivo
Do desastre em que um 'deixa melhor' alterou 40 linhas nasceu um template de prompt que limita o escopo, valida e permite reverter.
Recuperar de negações de permissão no Claude Code sem enfraquecer guardrails
Transforme um comando negado em plano seguro com motivo, alternativa, provas e critérios de nova tentativa.
Claude Code Harness Smoke Test: prova de 15 minutos antes de confiar em um agente
Um smoke test para escopo, áreas bloqueadas, comandos de prova, URL pública e CTAs de receita no Claude Code.