apostila_css_avancado.html · v1.0 · 2026
CSS do básico ao muito avançado
Animações, SVG, o que há de mais moderno na plataforma web — e como a inteligência artificial está mudando (e não mudando) esse trabalho.
Módulo 0
Como usar esta apostila para todos
Esta apostila foi desenhada para levar você do básico ao muito avançado em CSS, com um objetivo prático: tornar você contratável e produtivo em times reais de front-end. Ela segue três regras:
- Tudo tem demonstração ao vivo. As caixas marcadas com
▶ demo ao vivosão renderizadas pelo próprio CSS que você acabou de ler. Redimensione, passe o mouse, interaja. - O arquivo é o material. Abra o código-fonte desta página (
Ctrl+Uou botão direito → "Exibir código-fonte"). A apostila usa as técnicas que ensina:@layer,oklch(),light-dark(), container queries, scroll-driven animations, SVG animado… - Cada módulo termina em prática. Os desafios do Módulo 15 simulam tarefas reais de vaga júnior/pleno.
laboratorio.html e teste cada conceito nele.
Legenda de níveis
básico fundação obrigatória · intermediário o dia a dia do mercado · avançado diferencia candidatos · fronteira recém-chegado à plataforma web
Módulo 1
A base que sustenta tudo básico
CSS avançado quebra na mão de quem não domina três mecanismos: cascata, especificidade e herança. Praticamente todo bug de "meu estilo não aplica" nasce aqui — e é pergunta clássica de entrevista.
1.1 A cascata: quem ganha quando duas regras brigam?
Quando duas declarações miram o mesmo elemento e a mesma propriedade, o navegador decide nesta ordem (a primeira diferença resolve a disputa):
- Origem e importância — estilos do usuário/navegador vs. do autor;
!importantinverte a ordem das origens. - Camadas (
@layer) — camadas declaradas depois vencem as anteriores (veja o Módulo 5). - Especificidade — o "peso" do seletor.
- Ordem no código — em empate total, a última regra escrita vence.
1.2 Especificidade na prática
Conte como um placar de três colunas (ID, classe, elemento):
| Seletor | Placar | Observação |
|---|---|---|
p | 0-0-1 | elemento |
.card p | 0-1-1 | classe + elemento |
.card .titulo | 0-2-0 | duas classes |
#app .card | 1-1-0 | ID pesa mais que qualquer nº de classes |
:where(.card) | 0-0-0 | :where() zera a especificidade! |
style="…" (inline) | — | vence tudo, exceto !important |
!important em estilos, justamente para manter a especificidade baixa e previsível. Se você precisa de !important para "ganhar" de outra regra, o problema quase sempre é de arquitetura — e hoje se resolve com @layer.
1.3 Herança
Propriedades de texto (color, font-*, line-height, letter-spacing) descem para os filhos automaticamente. Propriedades de caixa (margin, padding, border, background) não. Você pode forçar comportamentos com as palavras-chave inherit, initial, unset e revert.
1.4 Box model e o reset essencial
/* Faz width/height incluírem padding e borda — indispensável */
*, *::before, *::after { box-sizing: border-box; }
/* Remove margens-padrão imprevisíveis do navegador */
* { margin: 0; }
/* Mídia nunca estoura o contêiner */
img, svg, video { display: block; max-width: 100%; }
/* Formulários herdam a tipografia da página */
input, button, textarea, select { font: inherit; }
1.5 Unidades: quando usar cada uma
| Unidade | Relativa a… | Use para… |
|---|---|---|
rem | fonte da raiz (html) | fontes, espaçamentos, quase tudo (respeita zoom/acessibilidade) |
em | fonte do próprio elemento | padding de botões, ícones que escalam com o texto |
% | o elemento pai | larguras fluidas |
vw / vh | viewport | seções de tela cheia (prefira dvh no mobile — Módulo 4) |
ch | largura do caractere "0" | limitar linhas de texto: max-width: 65ch |
px | fixa | bordas, sombras, detalhes que não devem escalar |
1.6 Propriedades lógicas intermediário
Em vez de margin-left, o CSS moderno usa margin-inline-start: os estilos se adaptam sozinhos a idiomas RTL (árabe, hebraico) e a modos de escrita verticais. Produtos internacionais exigem isso.
/* Antes (físico) → Agora (lógico) */
margin-left: auto; margin-inline-start: auto;
padding: 8px 16px; padding-block: 8px;
padding-inline: 16px;
width / height; inline-size / block-size;
border-bottom: …; border-block-end: …;
Módulo 2
Flexbox: layout em uma dimensão básico
Flexbox distribui itens ao longo de um eixo (linha ou coluna). É a ferramenta certa para barras de navegação, grupos de botões, alinhamento de qualquer coisa.
2.1 O modelo mental
Ao declarar display: flex, o contêiner ganha um eixo principal (controlado por flex-direction) e um eixo transversal. Memorize o mapa:
justify-content→ distribui no eixo principalalign-items→ alinha no eixo transversalgap→ espaço entre itens (esqueça margens entre irmãos)flex-wrap: wrap→ permite quebrar linha
2.2 flex-grow, flex-shrink, flex-basis
O atalho flex: 1 significa flex: 1 1 0 — o item pode crescer, encolher, e parte de uma base de tamanho zero. Três padrões cobrem 90% do uso real:
.item-fluido { flex: 1; } /* divide o espaço igualmente */
.item-fixo { flex: 0 0 240px; } /* trava em 240px, nunca cresce */
.item-conteudo { flex: 0 1 auto; } /* padrão: encolhe se preciso */
2.3 O truque do margin: auto
Dentro de um flex container, margin-inline-start: auto "empurra" o item para o outro lado — o segredo de toda navbar:
.navbar { display: flex; align-items: center; gap: 1rem; }
.navbar .links { margin-inline-start: auto; display: flex; gap: 1rem; }
2.4 Centralização perfeita (pergunta de entrevista!)
/* Resposta moderna nº 1 */
.pai { display: flex; justify-content: center; align-items: center; }
/* Resposta moderna nº 2 — ainda mais curta, com Grid */
.pai { display: grid; place-items: center; }
2.5 Playground: experimente Flexbox
Edite o CSS à esquerda e veja o resultado na hora. Teste trocar row por column, center por space-between, adicionar flex-wrap: wrap…
Módulo 3
Grid e Subgrid: layout em duas dimensões intermediário
Grid controla linhas e colunas ao mesmo tempo. Regra de bolso do mercado: Flexbox para componentes, Grid para páginas — mas não é dogma; use o que expressar melhor a intenção.
3.1 Vocabulário essencial
.pagina {
display: grid;
grid-template-columns: 280px 1fr; /* sidebar fixa + resto */
grid-template-rows: auto 1fr auto; /* header, main, footer */
gap: 1.5rem;
min-height: 100dvh;
}
A unidade fr ("fração") distribui o espaço restante. minmax(min, max) define limites, e auto dimensiona pelo conteúdo.
3.2 O padrão mais valioso do CSS: galeria sem media query
.galeria {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: .7rem;
}
Leia assim: "crie quantas colunas couberem (auto-fit), cada uma com no mínimo 120px, dividindo a sobra igualmente (1fr)". Redimensione a janela e observe:
auto-fit colapsa colunas vazias (itens esticam); auto-fill mantém as colunas fantasmas (itens não esticam). Teste os dois com poucos itens para ver a diferença.
3.3 Áreas nomeadas: layout que se lê
.app {
display: grid;
grid-template-areas:
"header header"
"nav main"
"footer footer";
grid-template-columns: 220px 1fr;
}
.app > header { grid-area: header; }
.app > nav { grid-area: nav; }
.app > main { grid-area: main; }
/* Reorganizar no mobile é reescrever o desenho: */
@media (max-width: 700px) {
.app { grid-template-areas: "header" "main" "nav" "footer";
grid-template-columns: 1fr; }
}
3.4 Subgrid avançado
Problema clássico: cards lado a lado com títulos de tamanhos diferentes — os botões desalinhados. subgrid deixa os filhos herdarem as trilhas do grid do avô, alinhando tudo entre cards:
.cards { display: grid;
grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.card { display: grid;
grid-row: span 3; /* ocupa 3 linhas do pai */
grid-template-rows: subgrid; } /* herda essas 3 linhas! */
/* Agora título, texto e botão de TODOS os cards
compartilham as mesmas linhas → alinhamento perfeito. */
Módulo 4
Responsividade moderna intermediário
A responsividade de 2015 era "media queries por largura de tela". A de hoje é design intrínseco: componentes que se adaptam ao espaço que recebem, tipografia fluida e novas unidades de viewport.
4.1 Mobile-first
/* Base = celular (sem media query) */
.card { padding: 1rem; }
/* Melhorias progressivas para telas maiores */
@media (min-width: 48rem) { .card { padding: 2rem; } }
@media (min-width: 64rem) { .card { padding: 3rem; } }
/* Sintaxe moderna de intervalo (range syntax): */
@media (48rem <= width < 64rem) { … }
4.2 Tipografia fluida com clamp()
clamp(mínimo, preferido, máximo) elimina dezenas de media queries:
h1 { font-size: clamp(2rem, 1.2rem + 3vw, 3.5rem); }
/* nunca menor que 2rem, nunca maior que 3.5rem,
escala fluida no meio (o termo com vw dá a inclinação) */
rem na parte preferida (1.2rem + 3vw, não só 3vw). Sem ele, o zoom por tamanho de fonte do usuário para de funcionar — reprovação certa em auditoria de acessibilidade.
4.3 Container Queries avançado
A maior mudança em responsividade da década: componentes que respondem ao tamanho do contêiner, não da tela. O mesmo card fica horizontal na área larga e empilhado na sidebar estreita — sem saber onde está.
.onde-o-card-mora { container-type: inline-size;
container-name: cartao; }
.card { display: grid; gap: .8rem; }
@container cartao (min-width: 420px) {
.card { grid-template-columns: 130px 1fr; align-items: center; }
}
Card camaleão
Eu mudo de layout quando meu contêiner passa de 420px — a janela não importa.
Container queries trazem também unidades próprias: cqw, cqh, cqi, cqb (porcentagem do contêiner). Ex.: font-size: clamp(1rem, 4cqi, 1.6rem) faz o texto escalar com o card.
4.4 Novas unidades de viewport: dvh, svh, lvh
No celular, a barra do navegador aparece e some — e o velho 100vh estoura a tela. As unidades dinâmicas resolvem:
svh— viewport pequeno (barra visível)lvh— viewport grande (barra recolhida)dvh— dinâmico, acompanha a barra em tempo real. Usemin-height: 100dvhpara seções de tela cheia.
4.5 Media queries de preferência do usuário
@media (prefers-color-scheme: dark) { … } /* tema escuro */
@media (prefers-reduced-motion: reduce) { … } /* menos animação */
@media (prefers-contrast: more) { … } /* alto contraste */
@media (hover: none) { … } /* telas de toque */
Respeitar essas preferências não é detalhe: é requisito de acessibilidade e aparece em checklist de code review de empresas sérias.
Módulo 5
Seletores modernos e arquitetura avançado
5.1 :is() e :where(): menos repetição
/* Antes */
header a:hover, nav a:hover, footer a:hover { color: red; }
/* Agora */
:is(header, nav, footer) a:hover { color: red; }
/* :where() é igual, mas com ESPECIFICIDADE ZERO —
perfeito para estilos-base fáceis de sobrescrever: */
:where(h1, h2, h3) { margin-block: 0; }
5.2 :has(): o "seletor de pai" fronteira
Por décadas foi impossível estilizar um elemento com base no que existe dentro dele. :has() mudou o jogo — e eliminou muito JavaScript de interface:
/* Card que CONTÉM imagem ganha outro layout */
.card:has(img) { grid-template-rows: 160px auto; }
/* Label acende quando o checkbox interno é marcado */
label:has(input:checked) { border-color: var(--brand); }
/* Formulário inteiro reage a um campo inválido */
form:has(input:invalid) .btn-enviar { opacity: .4; pointer-events: none; }
/* Irmão anterior (!): título que antecede uma lista */
h2:has(+ ul) { margin-bottom: .3rem; }
5.3 Nesting nativo: adeus, pré-processadores?
O aninhamento que popularizou o Sass agora é CSS puro:
.card {
padding: 1rem;
border: 1px solid var(--line);
& .titulo { font-weight: 600; } /* .card .titulo */
&:hover { box-shadow: var(--shadow); }
&.destaque { border-color: gold; } /* .card.destaque */
@media (min-width: 48rem) { padding: 2rem; } /* MQ aninhada! */
}
5.4 @layer: o fim da guerra de especificidade
Camadas de cascata deixam você declarar a ordem de prioridade da arquitetura inteira em uma linha. Regras de uma camada posterior vencem as anteriores independentemente de especificidade:
/* 1ª linha do projeto: a hierarquia oficial */
@layer reset, terceiros, base, componentes, utilitarios;
@layer reset { /* normalizações */ }
@layer terceiros { /* CSS de bibliotecas */ }
@layer base { /* tipografia, cores globais */ }
@layer componentes { /* .card, .btn, .modal */ }
@layer utilitarios { /* .mt-4, .hidden — vencem tudo */ }
Um #id.super.especifico na camada base perde para um simples .hidden em utilitarios. Isso resolve o problema que gerou décadas de !important. Esta apostila usa exatamente essa estrutura — confira no código-fonte.
5.5 @scope: estilos com fronteira fronteira
@scope (.comentarios) to (.editor) {
/* aplica dentro de .comentarios,
mas PARA ao encontrar .editor (buraco no escopo) */
p { margin-block: .5rem; }
}
5.6 Convenções de nomenclatura que o mercado usa
BEM (Block, Element, Modifier) continua sendo a convenção mais pedida em vagas que usam CSS "artesanal":
.card {} /* Bloco */
.card__titulo {} /* Elemento do bloco (__) */
.card--destaque {} /* Modificador do bloco (--) */
Em paralelo, o utility-first (Tailwind CSS) domina startups: classes utilitárias minúsculas compostas no HTML. Você não precisa escolher um lado — precisa entender os dois e o CSS que existe por baixo. Entrevistadores percebem rapidamente quem só sabe Tailwind sem saber CSS.
Módulo 6
Variáveis CSS e @property avançado
6.1 Custom properties: o sistema nervoso do design
:root {
--brand: oklch(48% .19 275);
--radius: 10px;
--espaco: 1rem;
}
.btn {
background: var(--brand);
border-radius: var(--radius);
padding: var(--espaco) calc(var(--espaco) * 2);
}
/* Fallback se a variável não existir: */
color: var(--texto, #333);
Diferente de variáveis de Sass, elas vivem no navegador: mudam em tempo real, respeitam a cascata (pode redefinir --brand só dentro de .tema-escuro) e são lidas/alteradas via JavaScript. São a base de design tokens, tema claro/escuro e white-label — vocabulário que impressiona em entrevista.
6.2 Escopo local = componentes configuráveis
.avatar { --tamanho: 40px;
width: var(--tamanho); height: var(--tamanho); }
.avatar--grande { --tamanho: 72px; } /* só muda o token! */
6.3 @property: variáveis com superpoderes fronteira
Por padrão o navegador trata variáveis como texto opaco — por isso não sabe animá-las. @property registra o tipo, e aí sim a variável vira animável. É assim que se anima um gradiente (que nativamente não é animável!):
@property --angulo {
syntax: "<angle>"; /* o tipo destrava a interpolação */
inherits: false;
initial-value: 20deg;
}
.btn-gradiente {
background: linear-gradient(var(--angulo), #4338ca, #0891b2);
transition: --angulo .6s ease; /* animando a VARIÁVEL */
}
.btn-gradiente:hover { --angulo: 200deg; }
Módulo 7
Cores de nova geração fronteira
7.1 Por que abandonar o HEX/HSL: oklch()
oklch(luminosidade croma matiz) é perceptualmente uniforme: dois azuis e dois amarelos com o mesmo valor de L parecem igualmente claros ao olho humano (em HSL, não parecem — um amarelo 50% "brilha" muito mais que um azul 50%). Consequências práticas:
- Paletas inteiras variando só um número, com contraste previsível;
- Acesso a cores mais vivas em telas P3 (fora do alcance do sRGB);
- Gradientes sem a "zona morta" acinzentada do RGB.
--brand: oklch(48% 0.19 275); /* L C H */ --brand-claro: oklch(85% 0.08 275); /* mesma matiz, + luz */ --brand-texto: oklch(30% 0.10 275); /* mesma matiz, − luz */
7.2 color-mix(): misture no navegador
/* 25% da marca sobre transparente = tinta de destaque */ background: color-mix(in oklch, var(--brand) 25%, transparent); /* hover 15% mais escuro, sem inventar outro hex: */ background: color-mix(in oklch, var(--brand), black 15%);
7.3 Relative Color Syntax: cores derivadas
/* "pegue --brand, desconte 0.25 de luminosidade" */ --brand-escuro: oklch(from var(--brand) calc(l - 0.25) c h); /* mesma cor, 50% de opacidade */ --brand-vidro: oklch(from var(--brand) l c h / 50%);
Um único token gera a família inteira de tons — o sonho dos design systems.
7.4 light-dark(): tema escuro em uma linha
:root { color-scheme: light dark; } /* obrigatório */
body {
color: light-dark(#1a2233, #e8ecf4);
background: light-dark(#fafbfd, #14181f);
}
O navegador escolhe o valor conforme o tema do sistema (ou o color-scheme forçado por você). O botão "Alternar tema" desta apostila funciona exatamente assim: o JavaScript só troca um atributo; quem faz todo o trabalho é light-dark(). Complete com accent-color: var(--brand) para tingir checkboxes, radios e ranges nativos.
Módulo 8
Transitions e Transforms intermediário
8.1 Transition: interpolando estados
.btn {
background: var(--brand);
transition: background .25s ease, transform .15s ease;
/* o quê tempo curva */
}
.btn:hover { background: var(--brand-2); }
.btn:active { transform: translateY(1px) scale(.98); }
transition: all
Ele anima propriedades que você não previu (inclusive quando o tema muda!) e força o navegador a observar tudo. Liste as propriedades explicitamente — isso aparece em code review.
8.2 Curvas de tempo: onde mora a "sensação" da interface
| Curva | Sensação | Uso típico |
|---|---|---|
ease-out | rápido → suave | elementos entrando (padrão de UI) |
ease-in | suave → rápido | elementos saindo |
cubic-bezier(.2,.8,.2,1) | "expressiva", desacelera longa | modais, painéis (padrão Material) |
linear(…) moderna | qualquer curva, até molas | bounce/spring sem JavaScript |
steps(n) | saltos discretos | sprites, relógios, "máquina de escrever" |
8.3 Transform: mover sem custo
transform: translate(-50%, -50%); /* mover */ transform: scale(1.05); /* escalar */ transform: rotate(45deg); /* girar */ transform: skewX(12deg); /* inclinar */ /* Sintaxe moderna: propriedades individuais, combináveis! */ translate: 0 -4px; scale: 1.05; rotate: 45deg;
Com as propriedades individuais (translate, scale, rotate), você anima cada uma em transições separadas sem sobrescrever as outras — antes era preciso repetir a lista inteira de transforms.
8.4 Performance: a regra de ouro da animação avançado
O navegador renderiza em etapas: Layout → Paint → Composite. Animar width, height, top, margin refaz o layout da página a cada frame (caro, trava em celulares). Animar transform e opacity acontece direto no compositor, geralmente na GPU — 60fps de graça.
/* ❌ dispara layout a cada frame */
.menu { left: -300px; transition: left .3s; }
/* ✅ só compositor, suave em qualquer aparelho */
.menu { translate: -300px 0; transition: translate .3s; }
will-change: transform avisa o navegador para preparar a otimização — use com moderação e só em elementos que realmente animam com frequência.
8.5 3D: perspective e o card flip
.palco { perspective: 900px; } /* no PAI */
.carta { transform-style: preserve-3d;
transition: transform .7s cubic-bezier(.2,.8,.2,1); }
.palco:hover .carta { transform: rotateY(180deg); }
.face { position: absolute; inset: 0;
backface-visibility: hidden; } /* esconde o verso */
.verso { transform: rotateY(180deg); }
🂡
rotateY(180deg)
Módulo 9
@keyframes e animação avançada avançado
9.1 Anatomia completa
@keyframes flutuar {
0% { translate: 0 0; }
50% { translate: 0 -12px; rotate: 2deg; }
100% { translate: 0 0; }
}
.balao {
animation: flutuar 3s ease-in-out infinite;
/* nome | duração | curva | delay | iterações |
direção (alternate/reverse) | fill-mode | play-state */
}
As duas propriedades que mais confundem iniciantes (e caem em entrevista):
animation-fill-mode: forwards— o elemento fica no estado final em vez de "pular de volta";animation-direction: alternate— vai e volta, ótimo cominfinite.
9.2 steps(): animação de sprite (jogos!)
.personagem {
width: 64px; height: 64px;
background: url(sprite-corrida.png) 0 0 / auto 64px;
animation: correr .8s steps(8) infinite; /* 8 quadros */
}
@keyframes correr { to { background-position: -512px 0; } }
9.3 O problema histórico: animar display: none fronteira
Durante 25 anos foi impossível fazer fade em elementos que entram/saem do DOM com display — todo mundo recorria a JavaScript e setTimeout. O CSS moderno resolveu com duas peças:
.toast {
transition: opacity .4s, translate .4s,
display .4s allow-discrete; /* 1) display anima "no fim" */
opacity: 1; translate: 0 0;
}
.toast[hidden] { display: none; opacity: 0; translate: 0 12px; }
@starting-style { /* 2) estado do PRIMEIRO frame ao entrar */
.toast { opacity: 0; translate: 0 12px; }
}
9.4 animation-composition: animações que se somam
.item {
animation: flutuar 3s infinite, balancar 2s infinite;
animation-composition: add; /* soma os transforms
em vez de a última vencer */
}
9.5 Acessibilidade de movimento — inegociável
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
transition-duration: .01ms !important;
}
}
Pessoas com distúrbios vestibulares passam mal com paralaxe e movimentos amplos. Todo projeto profissional embarca esse bloco (esta apostila embarca — teste ativando "reduzir movimento" no seu sistema).
Módulo 10
Scroll-driven animations e View Transitions fronteira
As duas APIs mais impactantes chegadas ao CSS recentemente. O que exigia bibliotecas JavaScript (GSAP ScrollTrigger, AOS) agora é declarativo — rodando fora da thread principal, sem travar.
10.1 animation-timeline: scroll() — progresso da rolagem
A linha do tempo da animação deixa de ser o relógio e passa a ser a barra de rolagem. A barra de progresso no topo desta página é isto:
.progresso {
position: fixed; inset: 0 0 auto 0; height: 4px;
background: linear-gradient(90deg, var(--brand), var(--brand-2));
transform-origin: 0 50%; transform: scaleX(0);
animation: crescer linear both;
animation-timeline: scroll(root); /* rolagem da página! */
}
@keyframes crescer { to { transform: scaleX(1); } }
10.2 animation-timeline: view() — revelar ao entrar na tela
A animação progride conforme o próprio elemento cruza a viewport. O clássico "fade-in ao rolar", 100% CSS:
.card {
animation: surgir both;
animation-timeline: view();
animation-range: entry 0% entry 80%; /* do início da entrada
até 80% dela */
}
@keyframes surgir {
from { opacity: 0; transform: translateY(28px) scale(.98); }
}
@supports (animation-timeline: view()) { … }: navegadores sem suporte simplesmente mostram o conteúdo estático. Site funciona para todos; a experiência melhora onde dá.
10.3 View Transitions API: transições entre estados e páginas
O efeito "app nativo" — um card que voa e vira a página de detalhes — chegou à web. Na mesma página:
/* JS: embrulhe a mudança de DOM */
document.startViewTransition(() => atualizarConteudo());
/* CSS: o navegador cria capturas ::view-transition-old/new
e você anima a troca: */
::view-transition-old(root) { animation: fade-out .25s ease both; }
::view-transition-new(root) { animation: fade-in .25s ease both; }
/* Elemento que "viaja" entre os estados: */
.card-destaque { view-transition-name: card-hero; }
E entre páginas diferentes (MPA), sem framework e sem JavaScript:
@view-transition { navigation: auto; }
/* pronto: navegação entre páginas do mesmo site com crossfade;
nomeie elementos com view-transition-name para animações "hero" */
Módulo 11
SVG do zero básico
SVG (Scalable Vector Graphics) é imagem descrita por código XML: vetorial (nítida em qualquer zoom), leve, acessível, estilizável com CSS e animável. Ícones, logos, ilustrações, gráficos de dashboards — tudo isso no mercado é SVG.
11.1 O sistema de coordenadas: viewBox
<svg viewBox="0 0 100 100" width="200">
<!-- "meu desenho vive num plano de 100×100 unidades,
começando em (0,0)" — o width só ESCALA esse plano -->
</svg>
viewBox="min-x min-y largura altura" é o conceito nº 1 de SVG: separa o sistema de desenho (interno) do tamanho exibido (externo). É por isso que SVG escala sem perder qualidade.
11.2 Formas básicas
<svg viewBox="0 0 220 120">
<rect x="10" y="10" width="60" height="60" rx="8" fill="#4338ca"/>
<circle cx="120" cy="40" r="30" fill="#0891b2"/>
<line x1="170" y1="10" x2="210" y2="70"
stroke="#d97706" stroke-width="4" stroke-linecap="round"/>
<polygon points="30,110 60,80 90,110" fill="#059669"/>
<text x="120" y="105" font-size="14">Olá, SVG!</text>
</svg>
11.3 <path>: a forma que desenha qualquer coisa
O atributo d é uma sequência de comandos de caneta. Os essenciais:
| Comando | Significado | Exemplo |
|---|---|---|
M x y | Mover a caneta (sem desenhar) | M 10 80 |
L x y | Linha reta até o ponto | L 90 20 |
H x / V y | linha Horizontal / Vertical | H 120 |
C x1 y1, x2 y2, x y | curva de Bézier Cúbica (2 controles) | curvas suaves |
Q x1 y1, x y | Bézier Quadrática (1 controle) | arcos simples |
A rx ry … | Arco elíptico | fatias de pizza, medidores |
Z | fecha o caminho | — |
Minúsculas (m, l, c…) usam coordenadas relativas ao ponto atual. Na prática você desenha no Figma/Illustrator e exporta — mas ler um d é o que permite editar, otimizar e animar.
11.4 fill, stroke e o truque do currentColor
/* SVG inline é estilizável por CSS normal: */
.icone { fill: currentColor; } /* herda a cor do TEXTO ao redor */
.icone path { stroke: var(--brand); stroke-width: 2;
stroke-linecap: round; stroke-linejoin: round; }
fill: currentColor é o padrão universal de bibliotecas de ícones: o ícone acompanha automaticamente a cor do texto do botão/link onde está — inclusive no hover e no tema escuro.
11.5 As três formas de usar SVG
| Forma | Como | Quando |
|---|---|---|
| Arquivo externo | <img src="logo.svg"> ou background-image | imagens estáticas; cacheável, mas não estilizável por CSS da página |
| Inline | <svg>…</svg> direto no HTML | ícones e ilustrações que você quer estilizar e animar — o caso principal desta apostila |
| Sprite | <symbol id="x"> + <use href="#x"> | sistemas de ícones: define uma vez, usa em todo lugar (Módulo 12) |
11.6 Acessibilidade de SVG — desde o primeiro dia
<!-- SVG informativo: --> <svg role="img" aria-label="Crescimento de 32% nas vendas">…</svg> <!-- SVG decorativo: esconda dos leitores de tela --> <svg aria-hidden="true" focusable="false">…</svg>
Módulo 12
SVG avançado e animado avançado
12.1 O efeito de "desenho à mão": stroke-dasharray
A técnica de animação de SVG mais pedida do mercado. A ideia: um tracejado (stroke-dasharray) cujo traço tem o comprimento total do caminho, deslocado para fora da vista (stroke-dashoffset) e animado de volta a zero — parecendo que a linha se desenha:
<!-- pathLength="1" normaliza o comprimento: chega de medir com JS -->
<path d="M10 50 C 40 10, 80 90, 120 50 …"
pathLength="1" fill="none" stroke="#4338ca" stroke-width="3"/>
path {
stroke-dasharray: 1; /* 1 traço do tamanho do caminho */
stroke-dashoffset: 1; /* começa 100% "escondido" */
animation: desenhar 3s ease forwards;
}
@keyframes desenhar { to { stroke-dashoffset: 0; } }
12.2 CSS anima SVG como anima HTML — com dois cuidados
.estrela {
transition: fill .3s, transform .3s;
transform-origin: center; /* 1) origem no centro da forma… */
transform-box: fill-box; /* 2) …RELATIVA à própria forma
(sem isso, gira em torno do
canto 0,0 do SVG inteiro!) */
}
.estrela:hover { fill: gold; transform: scale(1.25) rotate(15deg); }
12.3 Movimento ao longo de um caminho: offset-path
Qualquer elemento HTML ou SVG pode percorrer um trajeto — órbitas, foguetes seguindo curvas, timelines:
.planeta {
offset-path: ellipse(80px 50px at 50% 50%);
/* aceita também: path("M0 0 C…"), ray(45deg), url(#trilha) */
animation: orbitar 5s linear infinite;
}
@keyframes orbitar { to { offset-distance: 100%; } }
12.4 Gradientes e filtros dentro do SVG
<defs>
<linearGradient id="grad" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#4338ca"/>
<stop offset="100%" stop-color="#0891b2"/>
</linearGradient>
<filter id="brilho">
<feGaussianBlur stdDeviation="4" result="blur"/>
<feMerge>
<feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<circle r="40" fill="url(#grad)" filter="url(#brilho)"/>
Filtros SVG (feGaussianBlur, feDropShadow, feTurbulence para texturas e "gosma", feColorMatrix) são um mundo próprio — e podem ser aplicados a HTML comum via filter: url(#id) no CSS. Efeitos "impossíveis" de hover em sites premiados costumam ser isso.
12.5 Sistema de ícones profissional: <symbol> + <use>
<!-- Uma vez, no topo do HTML (ou arquivo sprite.svg): -->
<svg style="display:none">
<symbol id="i-check" viewBox="0 0 24 24">
<path d="M20 6 9 17l-5-5" fill="none"
stroke="currentColor" stroke-width="2.5"/>
</symbol>
</svg>
<!-- Em qualquer lugar, quantas vezes quiser: -->
<svg class="icone" width="20" height="20" aria-hidden="true">
<use href="#i-check"/>
</svg>
12.6 Playground: edite um SVG ao vivo
Mude coordenadas, cores, o d do path, o viewBox… e veja na hora. Sugestões: troque r="28", mude o stroke-width, arraste os pontos de controle da curva C.
Módulo 13
CSS de produção: o que os times esperam avançado
Saber propriedades não basta; o mercado paga por CSS manutenível, acessível e rápido. Este módulo é o seu checklist de profissional.
13.1 Arquitetura em camadas (o padrão emergente)
@layer reset, tokens, base, layout, componentes, utilitarios; /* + design tokens como custom properties em :root + componentes com escopo próprio (BEM, CSS Modules ou @scope) + utilitários por último, vencendo sem !important */
13.2 Checklist de acessibilidade (WCAG) que cai no dia a dia
- Contraste mínimo 4.5:1 para texto (ferramenta: qualquer contrast checker; em breve nativo com a função
contrast-color()); :focus-visiblesempre estilizado — nuncaoutline: nonesem substituto;prefers-reduced-motionrespeitado (Módulo 9.5);- Zoom de texto até 200% sem quebrar (use
rem, evite alturas fixas); - Alvos de toque com no mínimo ~44×44px em mobile;
- Nunca comunicar estado só por cor (some ícone/texto).
13.3 Performance de CSS
- Anime
transform/opacity, não layout (Módulo 8.4); content-visibility: autoem seções longas fora da tela — o navegador pula o render delas (ganhos enormes em páginas extensas);contain: layout paintisola componentes e reduz recálculos;- Carregue fontes com
font-display: swape pré-conecte ao host; - Evite seletores dependentes de estrutura profunda (
div > div > ul li span): frágeis e difíceis de manter.
13.4 Truques modernos que economizam JavaScript
| Antes (JS) | Agora (CSS/HTML) |
|---|---|
| Acordeão com cliques | <details>/<summary> (+ interpolate-size: allow-keywords para animar até height: auto) |
| Carrossel com biblioteca | scroll-snap-type + scroll-snap-align |
| Modal com foco preso na mão | <dialog> + ::backdrop |
| Tooltip/menu posicionado por JS | Popover API + Anchor Positioning (anchor-name/position-anchor) — a fronteira mais recente |
| Máscara de aspecto por cálculo | aspect-ratio: 16 / 9 |
| Truncar texto em N linhas | line-clamp: 3 |
13.5 Ferramentas que aparecem em vagas
Tailwind CSS (utility-first), CSS Modules e styled-components (em React), Sass (legado ainda enorme), PostCSS (transformações de build), Stylelint (lint), Lighthouse/DevTools (auditoria). Aprenda os fundamentos primeiro: quem domina CSS aprende qualquer uma dessas em dias.
Módulo 14
IA e o futuro do trabalho com CSS fronteira
Uma resposta honesta, sem hype nem pânico, sobre como a inteligência artificial está mudando este ofício — escrita, aliás, com a ajuda de uma IA, o que torna o exemplo concreto.
14.1 O que a IA já mudou
- Escrever CSS "commodity" ficou quase instantâneo. Assistentes (GitHub Copilot, Claude, ChatGPT, Cursor e afins) geram layouts, componentes e animações a partir de descrições em texto ou de screenshots. O trabalho de digitar um card responsivo do zero deixou de ser diferencial.
- Design-to-code encurtou. Ferramentas convertem telas do Figma em HTML/CSS razoável; a IA faz a primeira passada e o dev refina.
- Debug acelerou. Colar um trecho quebrado e perguntar "por que o z-index não funciona aqui?" resolve em segundos o que levava horas de tentativa e erro.
- A barreira de entrada caiu — o que também significa que só saber o básico vale menos do que valia.
14.2 O que a IA (ainda) não faz bem — e onde você vale ouro
- Julgamento visual e de produto. A IA gera um resultado plausível; decidir se ele serve à marca, ao usuário e ao contexto continua humano. Código gerado tende ao genérico — olho treinado percebe.
- Arquitetura e consistência de longo prazo. Manter um design system coerente por anos, decidir tokens, camadas e convenções de um produto real: a IA ajuda peça por peça, mas não carrega a visão do todo.
- Auditoria do que foi gerado. IA produz com confiança código sutilmente errado: acessibilidade ignorada, animação de
widthem vez detransform, especificidade bagunçada, APIs inventadas. Quem não sabe CSS não consegue revisar CSS. Este é o ponto central: os fundamentos desta apostila são o que transforma a IA de risco em alavanca. - Contexto de código legado — entender por que aquele hack de 2017 existe antes de removê-lo.
- Responsabilidade. Quando o site quebra em produção, quem responde é você, não o modelo.
14.3 Como o papel do dev front-end está se redesenhando
| Menos tempo em… | Mais tempo em… |
|---|---|
| Digitar CSS boilerplate | Especificar bem o problema (o "prompt" é uma spec) |
| Procurar sintaxe na documentação | Revisar, testar e endurecer código gerado |
| Reproduzir mockups pixel a pixel | Decisões de sistema: tokens, acessibilidade, performance |
| Tarefas isoladas | Orquestrar ferramentas (IA, build, CI, design) num fluxo |
14.4 Usando IA a seu favor no estudo e no trabalho
- Peça explicações, não só código. "Explique por que essa solução usa grid e não flex" ensina; "faça pra mim" só entrega.
- Dê contexto no prompt: navegadores-alvo, convenção do time (BEM? Tailwind?), requisitos de acessibilidade. Saída genérica vem de pedido genérico.
- Trate toda saída como código de estagiário talentoso: revise acessibilidade, performance e casos extremos antes de commitar.
- Use a IA para praticar entrevista: peça perguntas do Módulo 15 e defenda suas respostas.
- Continue lendo a plataforma (MDN, release notes dos navegadores): modelos têm data de corte e frequentemente desconhecem — ou alucinam — as APIs mais novas, justamente as que dão vantagem competitiva.
Módulo 15
Desafios de mercado, entrevistas e portfólio
15.1 Cinco desafios progressivos (faça na ordem)
Desafio 1 · Card de produto responsivo básico
Tarefa: um card com imagem, título, descrição, preço e botão. Empilhado em telas estreitas; imagem ao lado do texto quando o contêiner passa de 420px (container query, Módulo 4). Botão com estados :hover, :active e :focus-visible.
Critérios de aceite: zero media queries de tela; funciona com zoom de 200%; transições apenas em transform/cores.
Desafio 2 · Dashboard em Grid intermediário
Tarefa: layout de app com header, sidebar, área principal e footer usando grid-template-areas (Módulo 3). No mobile, a sidebar vai para baixo. Galeria interna de cards com auto-fit/minmax. Bônus: alinhe os botões dos cards com subgrid.
Desafio 3 · Tema claro/escuro com design tokens avançado
Tarefa: defina a paleta inteira em oklch() como custom properties; derive hovers e superfícies com color-mix()/relative colors (Módulo 7); implemente o tema com light-dark() + um botão que alterna color-scheme. Contraste mínimo 4.5:1 nos dois temas.
Desafio 4 · Loader e ilustração SVG animada avançado
Tarefa: desenhe um logo simples em <path> (pode exportar do Figma e otimizar no SVGO). Anime o traçado com stroke-dasharray + pathLength="1" (Módulo 12); adicione um elemento orbitando com offset-path; tudo pausado sob prefers-reduced-motion.
Desafio 5 · Landing page de fronteira fronteira
Tarefa: uma landing com: barra de progresso de leitura (scroll()), seções que surgem com view(), navegação entre duas páginas com @view-transition, toast animado com @starting-style (Módulos 9–10). Envolva tudo em @supports para degradar com elegância. Este projeto, bem documentado no README, é ouro no portfólio.
15.2 Perguntas reais de entrevista (com o caminho da resposta)
"Explique especificidade. O que vence: #a .b ou .a .b .c .d?"
#a .b (1-1-0) vence (0-4-0): nenhuma quantidade de classes supera um ID. Cite o placar de três colunas, mencione :where() zerando especificidade e @layer como solução arquitetural moderna (Módulos 1 e 5).
"Flexbox ou Grid — quando usar cada um?"
Flexbox: um eixo, tamanho ditado pelo conteúdo (navbars, grupos de controles). Grid: duas dimensões, o layout dita o conteúdo (páginas, dashboards, galerias). Mostre que conhece subgrid e o padrão auto-fit/minmax — sinaliza atualização (Módulos 2–3).
"Como você faria uma animação suave em um celular fraco?"
Animar só transform/opacity (compositor/GPU, sem layout nem paint), will-change pontual, respeitar prefers-reduced-motion, e citar scroll-driven animations rodando fora da main thread (Módulos 8–10).
"O que é reflow (layout) e repaint? Como evitar?"
Reflow: recálculo de geometria (mudou width, font-size…); repaint: redesenho de pixels (mudou color, box-shadow). Evita-se animando propriedades de compositor, agrupando leituras/escritas de DOM e isolando com contain/content-visibility (Módulos 8 e 13).
"Como você estilizaria um componente sem vazar estilos para o resto do app?"
Convenção de nomes (BEM), CSS Modules/escopo do framework, @scope nativo, ou Shadow DOM em web components; e @layer para controlar quem vence quem (Módulo 5).
"Você usa IA para escrever CSS? Como garante a qualidade?"
Pergunta cada vez mais comum. Resposta forte: "uso para acelerar boilerplate e explorar alternativas, mas reviso como revisaria código de terceiros — acessibilidade, performance de animação, especificidade e suporte de navegador — porque sei o que procurar" (Módulo 14). Demonstra maturidade, não dependência.
15.3 Portfólio que contrata
- 3 projetos profundos > 15 rasos. Os desafios 3, 4 e 5 acima são um portfólio completo.
- README explica decisões: "usei container queries porque o card aparece em três contextos" vale mais que o código em si.
- Publique (GitHub Pages, Netlify, Vercel) e teste no celular de verdade;
- Rode o Lighthouse e exiba as notas de Acessibilidade e Performance;
- Grave um GIF/vídeo curto das animações para o README — recrutador não roda projeto;
- Um clone caprichado de UI conhecida (player de música, feed) mostra olho para detalhe — deixe claro que é estudo.
Apêndice
Referências para continuar
- MDN Web Docs (developer.mozilla.org) — a documentação de referência; consulte para toda propriedade citada aqui.
- web.dev/learn/css — curso gratuito do time do Chrome; e o blog do Chrome para novidades da plataforma.
- CSS-Tricks — guias visuais clássicos de Flexbox e Grid.
- caniuse.com — suporte de navegadores; procure também pelo selo Baseline nas documentações.
- Kevin Powell (YouTube) — o professor de CSS mais didático da internet.
- Josh W. Comeau — artigos interativos profundos (especialmente sobre animação e Flexbox).
- State of CSS (stateofcss.com) — pesquisa anual: o que o mercado usa e o que vem aí.
- SVGOMG — otimizador de SVG online; svg-path-editor (yqnn.github.io) para entender o atributo
dvisualmente.