Mobile-first UI com React: Guia de CSS Responsivo
Implementação prática do zero com HTML mínimo, CSS mínimo e raciocínio técnico por exercício
Estas questões não são apenas uma revisão de CSS. Elas treinam uma mudança de postura: sair do “ajustei até ficar bonito” e entrar no “consigo prever o comportamento do layout em condições diferentes e justificar tecnicamente cada decisão”. O foco é menos decorar propriedade e mais raciocinar como quem projeta interface para contexto real.
No primeiro bloco, o núcleo é engenharia de viewport. Você precisa distinguir 100% do container e 100vw do viewport, aplicar vh com critério e controlar efeitos colaterais de mobile. O objetivo é fazer imagem e texto obedecerem regra mensurável: ocupar largura visível, usar altura relativa e reagir a rotação sem quebrar.
No segundo bloco, responsividade vira sistema de condições, não chute de breakpoint. Você vai combinar media queries por orientação, mídia de saída, capacidade de entrada e tema do sistema. Isso evita erros comuns: interface dependente de hover em touch, estilo de tela vazando para impressão e dark mode inconsistente.
No terceiro bloco, entram páginas completas com conteúdo real: perfil, produto e plataforma de vídeos. A exigência passa por composição de seções, hierarquia visual, componentes reutilizáveis e reorganização de layout conforme a tela cresce. Também entra disciplina de engenharia: CSS externo, separação correta de arquivos e comportamento previsível em cada estado.
Se você percorrer o conjunto completo com método, as competências finais ficam objetivas:
- Domínio de viewport engineering: quando usar
100vw,80vh,100%,object-fiteaspect-ratiocom estabilidade visual. - Tipografia responsiva com
clamp(), calibrando limites mínimos e máximos com legibilidade em diferentes telas. - Layout mobile-first com evolução por necessidade de conteúdo, usando progressive enhancement em vez de ajustes aleatórios.
- Leitura de contexto de execução: orientação, pointer/hover, impressão e tema do sistema para definir regras certas no lugar certo.
Trate cada exercício como um pequeno experimento técnico: implemente, valide no DevTools e explique a cadeia regra → condição → comportamento observado. Esse ciclo é o que transforma CSS em método de construção, depuração e comunicação técnica.
Sequência padrão
<!-- index.html -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
/* styles.css */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
img { display: block; max-width: 100%; }img + classe e controlar largura com vw.<img class="hero-full" src="img.jpg" alt="Imagem principal">
.hero-full {
width: 100vw;
height: auto;
}Como explicar em 3 frases
100vw significa largura total do viewport.height: auto para preservar proporção.Erros comuns
width: 100% sem entender o container.vh com controle de recorte.<img class="hero-tall" src="img.jpg" alt="Imagem principal">
.hero-tall {
width: 100vw;
height: 80vh;
object-fit: cover;
}Como explicar em 3 frases
80vh fixa a altura em 80% da área visível.object-fit: cover evita deformação.100vw.Erros comuns
object-fit e distorcer a imagem.font-size: 100% em texto real.<p class="texto-base">Pensar mobile-first é começar pelo cenário mais restrito.</p>
.texto-base { font-size: 100%; }Como explicar em 3 frases
100% mantém o tamanho padrão do documento.Erros comuns
html { font-size } e afirmar que continua padrão.clamp com limite inferior e superior.<p class="texto-fluido">Mobile-first reduz retrabalho e melhora estabilidade visual.</p>
.texto-fluido {
font-size: clamp(10px, 2.2vw, 30px);
}Como explicar em 3 frases
clamp controla mínimo, valor fluido e máximo.vw reage à largura.Erros comuns
@media (orientation: portrait|landscape).<img class="hero" src="img.jpg" alt="Imagem orientada">
@media (orientation: portrait) {
.hero { width: 100vw; height: auto; }
}
@media (orientation: landscape) {
.hero { width: 100vw; height: 80vh; object-fit: cover; }
}Como explicar em 3 frases
Erros comuns
object-fit no modo landscape.<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="portrait-screen.css" media="(orientation: portrait)">
<link rel="stylesheet" href="landscape-screen.css" media="(orientation: landscape)">
/* portrait-screen.css */
.hero { width: 100vw; height: auto; }
/* landscape-screen.css */
.hero { width: 100vw; height: 80vh; object-fit: cover; }Como explicar em 3 frases
link com media escolhe automaticamente a regra.Erros comuns
<div class="wrap">
<img class="hero" src="img.jpg" alt="Imagem">
<p class="txt">Pense mobile-first.</p>
</div>
.wrap { display: flex; flex-direction: column; gap: 12px; }
.hero { width: 100vw; margin-left: calc(50% - 50vw); }
@media (min-width: 768px) {
.wrap { flex-direction: row; align-items: center; }
.hero, .txt { width: 50%; margin-left: 0; }
}Como explicar em 3 frases
Erros comuns
prefers-color-scheme.<article class="card">
<h2>Resumo da aula</h2>
<p>Mobile-first começa no menor contexto e escala para telas maiores.</p>
</article>
:root { --bg:#fff; --fg:#111; --card:#f3f3f3; }
@media (prefers-color-scheme: dark) {
:root { --bg:#0b0b0b; --fg:#eaeaea; --card:#1a1a1a; }
}
body { background: var(--bg); color: var(--fg); }
.card { background: var(--card); }Como explicar em 3 frases
Erros comuns
<section class="quiz">
<p class="question">Qual regra deixa a resposta oculta apenas na impressão?</p>
<ol class="options">
<li>.answer { visibility: hidden; }</li>
<li>@media print { .answer { display: none; } }</li>
<li>@media screen { .answer { display: none; } }</li>
<li>.quiz { display: none; }</li>
<li>.options { opacity: 0; }</li>
</ol>
<p class="answer">Alternativa correta: 2, porque a regra atua somente na mídia print.</p>
</section>
@media print {
.answer { display: none; }
}Como explicar em 3 frases
Erros comuns
@media print.<div class="options">
<label><input type="radio" name="q"> Opção A</label>
<label><input type="radio" name="q"> Opção B</label>
</div>
@media (pointer: fine) {
.options label { cursor: pointer; }
}Como explicar em 3 frases
Erros comuns
<nav class="menu">
<a class="item" href="#"><span class="icon">🏠</span><span class="label">Home</span></a>
<a class="item" href="#"><span class="icon">📚</span><span class="label">Cursos</span></a>
<a class="item" href="#"><span class="icon">🧰</span><span class="label">Ferramentas</span></a>
<a class="item" href="#"><span class="icon">☎️</span><span class="label">Contato</span></a>
</nav>
.label { display: inline; }
@media (hover: hover) and (pointer: fine) {
.label { display: none; }
.item:hover .label { display: inline; }
}Como explicar em 3 frases
Erros comuns
<nav class="menu">
<a class="item" href="#" data-label="Home" aria-label="Home"><span class="icon">🏠</span></a>
<a class="item" href="#" data-label="Cursos" aria-label="Cursos"><span class="icon">📚</span></a>
</nav>
.item { position: relative; }
@media (hover: hover) and (pointer: fine) {
.item::after {
content: attr(data-label);
position: absolute;
top: 110%;
left: 50%;
transform: translateX(-50%);
opacity: 0;
background: #111;
color: #fff;
padding: 6px 10px;
border-radius: 8px;
white-space: nowrap;
}
.item:hover::after { opacity: 1; }
}Como explicar em 3 frases
data-label.position: relative ancora o tooltip no item correto.Erros comuns
position: relative no item.aria-label e perder acessibilidade.<!-- index.html -->
<section class="quiz-grid">
<!-- Repita este article .q 5 vezes (mínimo) -->
<article class="q">
<h3 class="q__question">Qual media query limita 3 colunas para tela?</h3>
<ul class="q__options">
<li>@media print</li>
<li>@media (min-width: 768px)</li>
<li>@media screen and (min-width: 1024px)</li>
<li>@media (hover: hover)</li>
</ul>
<p class="q__answer">Resposta: usar @media screen and (min-width: 1024px).</p>
</article>
</section>
/* styles.css */
body { font-size: clamp(10px, 2.2vw, 30px); }
.quiz-grid { display: grid; gap: 12px; }
.q { display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 768px) {
.q { grid-template-columns: 1fr 1fr; }
.q__answer { grid-column: 1 / -1; }
}
@media screen and (min-width: 1024px) {
.q { grid-template-columns: 1fr 1fr 1fr; }
.q__answer { grid-column: auto; }
}Pontos essenciais de estudo
.q.@media screen ....Como explicar em 3 frases
Erros comuns
screen e aplicar 3 colunas na impressão.grid-column: 1 / -1 no estado intermediário.<!-- index.html -->
<header class="top">
<h1>Meu Perfil</h1>
<details class="nav">
<summary>Menu</summary>
<nav class="nav__list">
<a href="#bio">Bio</a>
<a href="#hobbies">Hobbies</a>
<a href="#amigos">Amigos</a>
<a href="#contato">Contato</a>
</nav>
</details>
</header>
<main class="layout">
<section id="bio" class="card profile"><img src="avatar.jpg" alt="Foto de perfil"><p>Apresentação curta.</p></section>
<section id="hobbies" class="card hobbies"><img src="h1.jpg" alt="Hobby 1"><img src="h2.jpg" alt="Hobby 2"><img src="h3.jpg" alt="Hobby 3"></section>
<section id="amigos" class="card friends"><img src="a1.jpg" alt="Amigo 1"><img src="a2.jpg" alt="Amigo 2"><img src="a3.jpg" alt="Amigo 3"></section>
<section id="contato" class="card contact"><p>contato@exemplo.com</p></section>
</main>
/* styles.css */
:root { --bg:#fff; --fg:#111; --card:#f3f3f3; --bd:#ccc; }
@media (prefers-color-scheme: dark) {
:root { --bg:#0b0b0b; --fg:#eaeaea; --card:#1a1a1a; --bd:#333; }
}
body { background: var(--bg); color: var(--fg); }
.top { display:flex; justify-content:space-between; align-items:center; gap:12px; }
.nav__list { display:flex; flex-direction:column; gap:8px; }
.layout { display: grid; gap: 12px; }
.card { padding: 12px; border: 1px solid var(--bd); border-radius: 10px; background: var(--card); }
.profile img { width: 96px; height: 96px; border-radius: 50%; object-fit: cover; }
.hobbies, .friends { display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); gap: 8px; }
.hobbies img, .friends img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 8px; }
@media (min-width: 900px) {
.layout { grid-template-columns: 1.2fr 1fr; }
.friends, .contact { grid-column: 1 / -1; }
}Pontos essenciais de estudo
Como explicar em 3 frases
Erros comuns
<!-- index.html -->
<header class="top">
<h1>Produto</h1>
<details class="nav"><summary>Menu</summary><nav class="nav__list"><a href="#produto">Produto</a><a href="#especificacoes">Specs</a><a href="#relacionados">Relacionados</a><a href="#comentarios">Comentários</a></nav></details>
</header>
<section id="produto" class="card product">
<div class="gallery">
<input id="p1" type="radio" name="gal" checked><input id="p2" type="radio" name="gal"><input id="p3" type="radio" name="gal">
<div class="thumbs"><label for="p1">Frente</label><label for="p2">Lado</label><label for="p3">Detalhe</label></div>
<div class="main"><img class="p1" src="produto-1.jpg" alt="Frente"><img class="p2" src="produto-2.jpg" alt="Lado"><img class="p3" src="produto-3.jpg" alt="Detalhe"></div>
</div>
<div class="info" id="especificacoes"><h2>Notebook X</h2><p class="price">R$ 4.999</p><ul class="specs"><li>16GB RAM</li><li>512GB SSD</li><li>Tela 14"</li></ul></div>
</section>
<section id="relacionados" class="card related">
<article class="item"><img src="r1.jpg" alt="Mouse sem fio"><h3>Mouse sem fio</h3><p>R$ 149</p></article>
<article class="item"><img src="r2.jpg" alt="Mochila"><h3>Mochila</h3><p>R$ 199</p></article>
</section>
<section id="comentarios" class="card comments">
<article class="comment"><strong>Ana</strong> <time datetime="2026-03-10">10/03/2026</time><p>Ótimo desempenho no dia a dia.</p></article>
<article class="comment"><strong>Bruno</strong> <time datetime="2026-03-11">11/03/2026</time><p>Bateria estável para trabalho remoto.</p></article>
</section>
/* styles.css */
:root { --bg:#fff; --fg:#111; --card:#f3f3f3; --bd:#ccc; }
@media (prefers-color-scheme: dark) { :root { --bg:#0b0b0b; --fg:#eaeaea; --card:#1a1a1a; --bd:#333; } }
body { background: var(--bg); color: var(--fg); }
.gallery input { display: none; }
.main img { display: none; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
#p1:checked ~ .main .p1, #p2:checked ~ .main .p2, #p3:checked ~ .main .p3 { display: block; }
.thumbs { display: flex; gap: 8px; flex-wrap: wrap; }
.product, .related, .comments { display: grid; gap: 12px; }
.related .item img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 8px; }
@media (min-width: 900px) { .product { grid-template-columns: 1fr 1fr; } .related { grid-template-columns: 1fr 1fr; } }Pontos essenciais de estudo
Como explicar em 3 frases
Erros comuns
<!-- index.html -->
<header class="top">
<h1>Plataforma de Vídeos</h1>
<details class="nav"><summary>Menu</summary><nav class="nav__list"><a href="#video">Vídeo</a><a href="#acoes">Ações</a><a href="#relacionados">Relacionados</a><a href="#comentarios">Comentários</a></nav></details>
</header>
<main class="video-layout">
<section id="video" class="card main">
<iframe class="player" src="https://www.youtube.com/embed/dQw4w9WgXcQ" title="Vídeo principal" allowfullscreen></iframe>
<h2>Título do vídeo</h2>
<p class="author">Autor: Canal Exemplo</p>
<div id="acoes" class="actions"><button>Curtir</button><button>Compartilhar</button><button>Salvar</button><button>Denunciar</button></div>
<p>Descrição curta do conteúdo.</p>
</section>
<aside class="card sidebar">
<section class="ad">Espaço de propaganda</section>
<section id="relacionados" class="related">
<article class="video-item"><img src="capa-1.jpg" alt="Capa 1"><h3>Vídeo relacionado 1</h3><p>Autor A</p></article>
<article class="video-item"><img src="capa-2.jpg" alt="Capa 2"><h3>Vídeo relacionado 2</h3><p>Autor B</p></article>
</section>
<section id="comentarios" class="comments">
<article class="comment"><strong>Ana</strong> <time datetime="2026-03-12">12/03/2026</time><p>Explicação clara e direta.</p></article>
<article class="comment"><strong>Bruno</strong> <time datetime="2026-03-13">13/03/2026</time><p>Gostei do exemplo de layout responsivo.</p></article>
</section>
</aside>
</main>
/* styles.css */
:root { --bg:#fff; --fg:#111; --card:#f3f3f3; --bd:#ccc; }
@media (prefers-color-scheme: dark) { :root { --bg:#0b0b0b; --fg:#eaeaea; --card:#1a1a1a; --bd:#333; } }
body { background: var(--bg); color: var(--fg); }
.player { width: 100%; aspect-ratio: 16 / 9; border: 0; }
.actions { display: flex; flex-wrap: wrap; gap: 8px; }
.video-item img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 8px; }
.video-layout { display: grid; gap: 12px; }
@media (min-width: 1000px) { .video-layout { grid-template-columns: 2fr 1fr; align-items: start; } }Pontos essenciais de estudo
Como explicar em 3 frases
aspect-ratio.flex-wrap em telas menores.