CSS — Dando vida às páginas
Do cinza sem graça ao layout incrível: aprenda a estilizar, posicionar e animar qualquer coisa com CSS. Da especificidade até animações suaves, tem tudo aqui.
🎨 Introdução ao CSS
CSS (Cascading Style Sheets — Folhas de Estilo em Cascata) é a linguagem responsável por toda a parte visual de uma página web. O HTML estrutura o conteúdo; o CSS decide como ele vai aparecer: cores, fontes, espaçamentos, layouts e até animações.
Pense no HTML como a estrutura de uma casa e o CSS como a decoração, pintura e móveis. Sem CSS, a web seria uma lista enorme de texto sem formatação — tipo um documento do Bloco de Notas gigante.
Como funciona a Cascata
O "C" de CSS significa Cascata. Quando mais de uma regra CSS se aplica ao mesmo elemento, o navegador precisa decidir qual vence. Essa decisão envolve três fatores, nessa ordem de importância:
| Fator | O que é | Exemplo |
|---|---|---|
| Origem | De onde vem o estilo: browser padrão, autor ou usuário | Seus estilos vencem o padrão do navegador |
| Especificidade | Quão "específico" é o seletor | #id vence .classe |
| Ordem | A última regra igual declarada vence | CSS mais abaixo no arquivo sobrescreve |
Herança
Algumas propriedades CSS são herdadas pelos elementos filhos automaticamente.
color, font-family e font-size são exemplos típicos.
Outras como margin, padding e border não são
herdadas — cada elemento cuida das suas próprias.
Como linkar CSS ao HTML
Existem três formas de aplicar CSS. A preferida é sempre a externa:
<!-- No <head> do HTML -->
<link rel="stylesheet" href="./assets/css/style.css">
<style>
body {
background: #0f1117;
}
</style>
<p style="color: red; font-size: 18px;">Texto vermelho</p>
Inline CSS tem a maior especificidade (exceto !important), o que dificulta sobrescrever
depois. Prefira sempre o CSS externo — manutenção muito mais fácil.
Sintaxe básica
A estrutura de uma regra CSS é sempre a mesma:
/* seletor { propriedade: valor; } */
h1 {
color: #6c63ff;
font-size: 2rem;
font-weight: 800;
}
/* Múltiplos seletores na mesma regra */
h1, h2, h3 {
line-height: 1.3;
}
Especificidade — a tabela de pontos
Cada tipo de seletor tem um "peso". O navegador soma os pontos e a regra com maior pontuação vence.
| Seletor | Pontos | Exemplo |
|---|---|---|
* (universal) |
0 | * { } |
| Elemento / tag | 1 | p { }, div { } |
| Classe / pseudo-classe / atributo | 10 | .btn { }, :hover { } |
| ID | 100 | #header { } |
| Inline style | 1000 | style="..." |
!important |
∞ (evite!) | color: red !important |
p { color: gray; } /* pontos: 1 */
.destaque { color: blue; } /* pontos: 10 — vence! */
#titulo { color: red; } /* pontos: 100 — vence sobre os dois! */
/* Seletores combinados somam pontos */
div .btn:hover {
/* 1 (div) + 10 (.btn) + 10 (:hover) = 21 pontos */
}
🎯 Seletores
Seletores são a forma de você dizer ao CSS "quero aplicar esse estilo neste(s) elemento(s)". Quanto mais você domina seletores, menos classes desnecessárias você cria no HTML.
Seletores básicos
/* Elemento (tag) — aplica em todos os <p> */
p { color: #e2e8f0; }
/* Classe — aplica em qualquer elemento com class="card" */
.card { background: #1a1d27; }
/* ID — aplica apenas no elemento com id="header" */
#header { height: 60px; }
/* Universal — aplica em TUDO (use com cuidado) */
* { box-sizing: border-box; }
Combinadores
Combinam seletores para selecionar elementos baseados na sua relação no HTML:
/* Descendente (espaço) — qualquer <p> dentro de .artigo */
.artigo p { line-height: 1.8; }
/* Filho direto (>) — apenas <li> filho imediato de <ul> */
ul > li { list-style: none; }
/* Irmão adjacente (+) — <p> imediatamente após <h2> */
h2 + p { margin-top: 0; }
/* Irmão geral (~) — todos os <p> após <h2> no mesmo nível */
h2 ~ p { color: var(--text-muted); }
Pseudo-classes
Selecionam elementos num estado especial ou numa posição específica na estrutura:
/* Estados de interação */
a:hover { color: #6c63ff; } /* mouse em cima */
input:focus { outline: 2px solid #6c63ff; } /* campo focado */
button:active { transform: scale(0.97); } /* clicando */
/* Posição na estrutura */
li:first-child { font-weight: bold; } /* primeiro filho */
li:last-child { border-bottom: none; } /* último filho */
li:nth-child(2) { color: #43d9ad; } /* exatamente o 2º */
li:nth-child(odd) { background: rgba(255,255,255,.03); } /* ímpares */
li:nth-child(3n) { color: #ffd166; } /* a cada 3 */
/* Negação */
input:not([type="submit"]) {
border: 1px solid #2a2d3e;
}
Pseudo-elementos
Permitem estilizar partes específicas de um elemento ou inserir conteúdo
via CSS sem mexer no HTML. Usam dois pontos duplos :::
/* Inserir conteúdo antes/depois do elemento */
.card::before {
content: '🃏 ';
display: inline-block;
}
.card::after {
content: '';
display: block;
height: 2px;
background: var(--accent);
}
/* Placeholder dos inputs */
input::placeholder {
color: #8892a4;
font-style: italic;
}
/* Texto selecionado pelo usuário */
::selection {
background: rgba(108,99,255,.35);
color: #fff;
}
Seletores de atributo
Selecionam elementos baseado nos seus atributos HTML — muito útil para formulários:
/* Tem o atributo href (qualquer valor) */
a[href] { text-decoration: underline; }
/* Valor exato */
input[type="text"] { border-radius: 8px; }
input[type="checkbox"] { accent-color: #6c63ff; }
/* Começa com... */
[class^="btn"] { cursor: pointer; }
/* Termina com... */
a[href$=".pdf"]::after { content: ' 📄'; }
/* Contém... */
a[href*="external"] { color: var(--yellow); }
📦 Box Model
Todo elemento HTML é uma caixa retangular. O Box Model define como o tamanho dessa caixa é calculado. Entender isso evita aquele frustrantemente famoso "por que está estourando o layout?!".
As quatro camadas
De dentro para fora, cada caixa tem:
box-sizing: o herói silencioso
Por padrão (content-box), o width que você define se aplica apenas ao
conteúdo — padding e border são somados por fora. Isso quebra layouts o tempo todo.
Com border-box, o width inclui padding e border. Muito mais intuitivo.
content-box (padrão ruim)
.caixa {
width: 200px;
padding: 20px;
border: 2px solid;
}
/* Tamanho real: 244px
(200 + 20*2 + 2*2) */
border-box (use sempre!)
.caixa {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 2px solid;
}
/* Tamanho real: 200px. Sempre. */
Adicione isso no começo de todo projeto CSS e durma tranquilo:
*, *::before, *::after {
box-sizing: border-box;
}
Propriedades do Box Model
.caixa {
/* Dimensões */
width: 300px;
height: 150px;
max-width: 100%; /* não ultrapassa o pai */
min-height: 50px; /* altura mínima */
/* Padding — shorthand: top right bottom left */
padding: 1rem; /* todos os lados */
padding: 1rem 2rem; /* vertical | horizontal */
padding: 10px 20px 10px 20px; /* t r b l */
/* Margin */
margin: 0 auto; /* centraliza horizontalmente */
/* Border */
border: 1px solid #2a2d3e;
border-radius: 8px;
}
Margin collapse: margens verticais entre elementos irmãos se "colapsam" (a maior vence, não somam). Isso não acontece com padding. Fique esperto!
🔲 Display
A propriedade display define como um elemento se comporta no fluxo da página e
como seus filhos são organizados. É uma das propriedades mais importantes do CSS.
| Valor | Comportamento | Exemplos nativos |
|---|---|---|
block |
Ocupa linha inteira, aceita width/height/margin vertical | div, p, h1–h6 |
inline |
Flui com o texto, ignora width/height, margens só horizontais | span, a, strong |
inline-block |
Flui com o texto MAS aceita width/height/margens verticais | img, button |
none |
Remove completamente do layout (não ocupa espaço) | Qualquer elemento escondido |
flex |
Ativa Flexbox no container; filhos viram flex items | Navbars, cards em linha |
grid |
Ativa CSS Grid no container; filhos viram grid items | Layouts de página inteira |
inline-flex |
Flex mas o container em si é inline | Badges, botões com ícone |
contents |
O container some, filhos sobem um nível no layout | Trick para grupos de flex items |
/* Esconder elemento sem tirar do DOM */
.escondido { display: none; }
.invisivel { visibility: hidden; } /* esconde mas ocupa espaço */
/* Botão com ícone alinhado */
.btn {
display: inline-flex;
align-items: center;
gap: .5rem;
padding: .6rem 1.2rem;
}
/* Trocar inline por block para estilizar */
span.destaque {
display: block;
width: 100%;
}
🔷 Flexbox
Flexbox é o sistema de layout unidimensional do CSS. Pense nele como uma prateleira: você define se os itens ficam em linha ou coluna, como se distribuem, como se alinham — e o navegador faz o trabalho pesado.
Flexbox trabalha em um eixo por vez: main axis (principal) e cross axis (cruzado).
O eixo principal é definido por flex-direction. Tudo gira em torno disso.
Propriedades do Container (pai)
.container {
display: flex;
/* Direção do eixo principal */
flex-direction: row; /* → padrão */
flex-direction: row-reverse; /* ← */
flex-direction: column; /* ↓ */
flex-direction: column-reverse; /* ↑ */
/* Quebra de linha */
flex-wrap: nowrap; /* padrão — tudo em uma linha */
flex-wrap: wrap; /* quebra pra próxima linha */
/* Alinhamento no eixo principal (horizontal se row) */
justify-content: flex-start; /* ◀◀◀ padrão */
justify-content: center; /* ▶◀ centro */
justify-content: flex-end; /* ▶▶▶ */
justify-content: space-between; /* ◀ · ▶ espaço entre */
justify-content: space-around; /* · ◀ · ▶ · espaço ao redor */
justify-content: space-evenly; /* espaço igual em tudo */
/* Alinhamento no eixo cruzado (vertical se row) */
align-items: stretch; /* padrão — estica para preencher */
align-items: center; /* centraliza verticalmente */
align-items: flex-start; /* alinha no topo */
align-items: flex-end; /* alinha embaixo */
align-items: baseline; /* alinha pela linha de base do texto */
/* Alinhamento de múltiplas linhas (quando wrap ativo) */
align-content: center;
/* Espaçamento entre itens */
gap: 1rem; /* linha e coluna */
gap: 1rem 2rem; /* linha | coluna */
}
Propriedades dos Items (filhos)
.item {
/* flex-grow: quanto crescer para preencher espaço livre */
flex-grow: 0; /* padrão — não cresce */
flex-grow: 1; /* cresce para preencher */
/* flex-shrink: quanto encolher quando faltar espaço */
flex-shrink: 1; /* padrão — pode encolher */
flex-shrink: 0; /* nunca encolhe */
/* flex-basis: tamanho "ideal" antes de crescer/encolher */
flex-basis: auto; /* usa width/height */
flex-basis: 200px; /* tamanho base fixo */
/* Shorthand flex: grow shrink basis */
flex: 1; /* flex: 1 1 0 */
flex: 1 1 200px;
/* Sobrescreve align-items só para este item */
align-self: center;
/* Ordem visual (não altera o DOM) */
order: 2; /* padrão é 0 */
}
Exemplos práticos
.navbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
height: 60px;
}
.nav-logo { font-weight: bold; }
.nav-links {
display: flex;
gap: 1rem;
list-style: none;
}
.tela-login {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1; /* cresce para empurrar o footer */
}
footer {
margin-top: auto;
}
⬛ CSS Grid
CSS Grid é o sistema de layout bidimensional do CSS — linhas E colunas ao mesmo tempo. Enquanto Flexbox é a prateleira, Grid é a planta baixa do apartamento inteiro. Perfeito para layouts de página e componentes complexos.
Propriedades do Container
.grid {
display: grid;
/* Colunas: 3 colunas de tamanhos diferentes */
grid-template-columns: 200px 1fr 1fr;
/* repeat() — repete o padrão N vezes */
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(4, minmax(200px, 1fr));
/* auto-fill: preenche com o máximo de colunas que couber */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
/* Linhas */
grid-template-rows: 60px 1fr 50px;
/* Espaçamentos */
gap: 1rem;
gap: 1.5rem 1rem; /* linha | coluna */
}
A unidade fr
fr significa fraction (fração). É a unidade do Grid que distribui
o espaço disponível de forma proporcional. 1fr 2fr = a segunda coluna tem o dobro
do tamanho da primeira. Super útil para layouts fluidos.
grid-template-areas — o superpoder
.layout {
display: grid;
grid-template-columns: 220px 1fr;
grid-template-rows: 60px 1fr 50px;
min-height: 100vh;
grid-template-areas:
"header header"
"sidebar main "
"footer footer";
}
header { grid-area: header; }
.sidebar{ grid-area: sidebar; }
main { grid-area: main; }
footer { grid-area: footer; }
Posicionamento manual de itens
.destaque {
/* Ocupa da coluna 1 até a 3 (2 colunas) */
grid-column: 1 / 3;
/* Atalho para "ocupa 2 colunas a partir da atual" */
grid-column: span 2;
/* Da linha 1 até a linha 2 */
grid-row: 1 / 2;
/* -1 significa "até o final" */
grid-column: 1 / -1; /* ocupa a linha toda */
}
/* Cards responsivos sem media query — mágica! */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1.2rem;
}
Regra geral: use Flexbox quando você pensa em uma dimensão (linha OU coluna). Use Grid quando você pensa em duas dimensões (linha E coluna ao mesmo tempo).
📱 Responsividade
Responsividade é fazer seu layout funcionar bem em qualquer tamanho de tela — do celular de 320px ao monitor 4K. Em 2024, mais de 60% do tráfego web vem de mobile. Ignorar isso é um erro caro.
Mobile-first: comece pelo menor
A abordagem mobile-first é simples: escreva o CSS base para celular e use
min-width para adicionar estilos progressivamente em telas maiores.
É mais fácil expandir do que comprimir.
Desktop-first (evite)
/* Base para desktop */
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
}
/* Quebra pra mobile */
@media (max-width: 768px) {
.grid {
grid-template-columns: 1fr;
}
}
Mobile-first (prefira)
/* Base para mobile */
.grid {
display: grid;
grid-template-columns: 1fr;
}
/* Expande para desktop */
@media (min-width: 768px) {
.grid {
grid-template-columns: 1fr 1fr;
}
}
Media Queries
/* Breakpoints comuns */
@media (min-width: 640px) { /* sm — celular grande */ }
@media (min-width: 768px) { /* md — tablet */ }
@media (min-width: 1024px) { /* lg — laptop */ }
@media (min-width: 1280px) { /* xl — desktop */ }
/* Orientação */
@media (orientation: landscape) { /* paisagem */ }
@media (orientation: portrait) { /* retrato */ }
/* Combinando condições */
@media (min-width: 768px) and (max-width: 1024px) {
/* só tablets */
}
/* Preferência de tema do sistema */
@media (prefers-color-scheme: dark) { /* modo escuro */ }
@media (prefers-reduced-motion: reduce) { /* desativa animações */ }
Unidades relativas
| Unidade | Relativa a | Uso típico |
|---|---|---|
% |
Elemento pai | Larguras fluidas: width: 100% |
vw |
Largura da viewport | Seções full-width: width: 100vw |
vh |
Altura da viewport | Hero sections: min-height: 100vh |
em |
Font-size do elemento atual | Padding/margin em escala com o texto |
rem |
Font-size do elemento raiz (html) |
Tipografia consistente no projeto |
ch |
Largura do caractere "0" | Largura de colunas de texto: max-width: 65ch |
svh |
Small Viewport Height (sem barras do browser) | Mobile: evita barras cobrindo conteúdo |
clamp() — tipografia fluida
A função clamp(min, preferred, max) define um valor que cresce com a tela mas
nunca sai de um intervalo. Perfeito para tamanhos de fonte responsivos sem media queries:
h1 {
/* Mínimo 1.8rem, ideal 5vw, máximo 3.5rem */
font-size: clamp(1.8rem, 5vw, 3.5rem);
}
p {
font-size: clamp(.9rem, 2.5vw, 1.1rem);
}
.hero {
/* Padding que cresce com a tela */
padding: clamp(2rem, 8vw, 6rem);
}
/* max-width com fluid — conteúdo não fica largo demais */
.container {
width: min(90%, 1200px);
margin: 0 auto;
}
🎨 Variáveis CSS
Variáveis CSS (tecnicamente chamadas de Custom Properties) permitem definir valores reutilizáveis diretamente no CSS — sem precisar de pré-processadores como Sass. Elas são dinâmicas (podem ser alteradas via JavaScript) e funcionam em cascata.
Sintaxe básica
/* Declarar no :root = disponível em todo o documento */
:root {
--cor-primaria: #6c63ff;
--cor-fundo: #0f1117;
--espaco-base: 1rem;
--fonte-titulo: 'Segoe UI', system-ui, sans-serif;
--raio-borda: 8px;
}
/* Usar com var() */
.botao {
background: var(--cor-primaria);
padding: var(--espaco-base);
border-radius: var(--raio-borda);
}
/* var() aceita fallback como segundo argumento */
.card {
color: var(--cor-texto, #e2e8f0); /* usa #e2e8f0 se --cor-texto não existir */
}
Escopo local
Variáveis não precisam ser globais. Você pode declarar uma variável em qualquer seletor e ela só existe naquele contexto e nos filhos:
.card-verde {
--destaque: #43d9ad;
}
.card-roxo {
--destaque: #6c63ff;
}
/* Ambas as classes usam a mesma propriedade */
.card .titulo {
color: var(--destaque);
border-bottom: 2px solid var(--destaque);
}
Tema dark/light com variáveis
A forma mais elegante de implementar dark mode. Você troca apenas as variáveis no :root
e todo o site muda instantaneamente:
/* Tema claro (padrão) */
:root {
--bg: #ffffff;
--texto: #1a1a2e;
--card-bg: #f5f5f5;
--borda: #e0e0e0;
}
/* Tema escuro — via preferência do sistema */
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f1117;
--texto: #e2e8f0;
--card-bg: #1a1d27;
--borda: #2a2d3e;
}
}
/* Alternativa: classe no elemento raiz (toggle via JS) */
[data-theme="dark"] {
--bg: #0f1117;
--texto: #e2e8f0;
}
/* Todo o CSS usa as variáveis — nada muda aqui */
body { background: var(--bg); color: var(--texto); }
.card { background: var(--card-bg); border-color: var(--borda); }
const btn = document.querySelector('#toggle-tema');
btn.addEventListener('click', () => {
const atual = document.documentElement.getAttribute('data-theme');
document.documentElement.setAttribute(
'data-theme',
atual === 'dark' ? 'light' : 'dark'
);
});
✨ Animações
Animações bem feitas comunicam estado, guiam o olhar e tornam a experiência mais prazerosa. Animações mal feitas deixam o site lento e irritam o usuário. A diferença está em usar as ferramentas certas.
transition — para estados
transition é usado para animar a mudança de um estado para outro (hover, focus, etc.).
É a animação mais simples e eficiente:
.botao {
background: #6c63ff;
transform: scale(1);
/* transition: propriedade duração timing delay */
transition: background .2s ease, transform .15s ease;
/* Ou anima todas as propriedades (menos eficiente) */
transition: all .2s ease;
}
.botao:hover {
background: #5a52d5;
transform: translateY(-2px);
}
.botao:active {
transform: scale(.97);
}
/* Timing functions mais usadas */
transition-timing-function: ease; /* suave no início e fim */
transition-timing-function: ease-in; /* começa devagar */
transition-timing-function: ease-out; /* termina devagar */
transition-timing-function: ease-in-out; /* devagar nos dois */
transition-timing-function: linear; /* velocidade constante */
transition-timing-function: cubic-bezier(.4,0,.2,1); /* customizado */
@keyframes + animation — para sequências
Para animações mais complexas que não são simples transições de estado, use
@keyframes para definir a sequência e animation para aplicá-la:
/* Definindo a animação */
@keyframes pular {
0% { transform: translateY(0); }
50% { transform: translateY(-20px); }
100% { transform: translateY(0); }
}
@keyframes girar {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes aparecer {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
/* Aplicando com animation */
.botao-pulante {
/* animation: nome duração timing delay iteracao direction fill-mode */
animation: pular .6s ease infinite;
}
.spinner {
animation: girar 1s linear infinite;
}
.card {
animation: aparecer .4s ease-out both;
}
/* Propriedades individuais */
.animado {
animation-name: pular;
animation-duration: .6s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite; /* ou um número */
animation-fill-mode: both; /* mantém estado final */
animation-play-state: running; /* paused para pausar */
}
transform — a propriedade para animar
.elemento {
/* Mover */
transform: translate(20px, -10px); /* x, y */
transform: translateX(50%);
transform: translateY(-100%);
/* Escalar */
transform: scale(1.1); /* 10% maior */
transform: scale(.95); /* 5% menor (clique) */
transform: scaleX(1.2); /* só horizontal */
/* Rotacionar */
transform: rotate(45deg);
transform: rotate(-180deg);
/* Torcer */
transform: skew(10deg, 5deg);
/* Combinar (ordem importa!) */
transform: translateY(-4px) scale(1.02);
}
Exemplos divertidos
@keyframes bounce {
0%, 100% {
transform: translateY(0);
animation-timing-function: cubic-bezier(.8,0,1,1);
}
50% {
transform: translateY(-16px);
animation-timing-function: cubic-bezier(0,0,.2,1);
}
}
.btn-bounce:hover {
animation: bounce .6s infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.spinner {
width: 32px;
height: 32px;
border: 3px solid rgba(108,99,255,.2);
border-top-color: #6c63ff;
border-radius: 50%;
animation: spin .8s linear infinite;
}
@keyframes fade-up {
from {
opacity: 0;
transform: translateY(24px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
animation: fade-up .5s ease-out both;
}
/* Delay escalonado para lista de cards */
.card:nth-child(1) { animation-delay: 0s; }
.card:nth-child(2) { animation-delay: .1s; }
.card:nth-child(3) { animation-delay: .2s; }
Performance tip: anime apenas opacity e transform.
Essas duas propriedades são processadas pelo compositor do browser (GPU) sem causar
layout recalculation ou repaint. Evite animar width,
height, top, left, margin —
elas causam reflow e podem deixar a animação travada.
Respeite usuários com sensibilidade a movimento. Desabilite animações desnecessárias para quem configurou o sistema para reduzir movimento:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: .01ms !important;
transition-duration: .01ms !important;
}
}
Resumo do módulo CSS
- CSS controla toda a apresentação visual — cores, layout, tipografia e animações
- A cascata resolve conflitos por origem, especificidade e ordem de declaração
- Prefira CSS externo; use
box-sizing: border-boxem todo projeto - Seletores combinados, pseudo-classes e pseudo-elementos eliminam classes desnecessárias
- O Box Model define Content → Padding → Border → Margin — sempre use border-box
- Flexbox para layouts unidimensionais; Grid para layouts bidimensionais
- Mobile-first com
min-widthe unidades relativas para responsividade - Variáveis CSS (
--custom-props) são essenciais para temas e manutenção - Anime apenas
opacityetransformpara performance máxima - Respeite
prefers-reduced-motionpara acessibilidade