Skip to content

CSS Folha de referência

Linguagem de folha de estilo para descrever a apresentação de páginas web.

01

Seletores

Seletores Básicos

Seletores CSS visam elementos HTML para estilização. Seletores de tipo correspondem a nomes de elementos (p, div). Seletores de classe (.) correspondem a atributos de classe e podem ser reutilizados. Seletores de ID (#) correspondem a um único elemento e devem ser únicos. O seletor universal (*) corresponde a tudo. Agrupe seletores com vírgulas para compartilhar estilos.

css
/* Type selector - all <p> elements */
p { color: #333; }

/* Class selector - elements with class="btn" */
.btn { padding: 8px 16px; }

/* ID selector - element with id="header" */
#header { background: #fff; }

/* Universal selector - all elements */
* { box-sizing: border-box; }

/* Grouping selector */
h1, h2, h3 { font-family: Arial, sans-serif; }

Combinadores

Combinadores definem relacionamentos entre elementos. Descendente (espaço) corresponde a qualquer elemento aninhado. Filho (>) corresponde apenas a filhos diretos. Irmão adjacente (+) corresponde ao elemento imediatamente após. Irmão geral (~) corresponde a todos os irmãos após. Entender combinadores é essencial para estilização precisa sem classes extras.

css
/* Descendant - any <a> inside .nav */
.nav a { text-decoration: none; }

/* Child - direct <li> children of <ul> */
ul > li { list-style: none; }

/* Adjacent sibling - <p> right after <h1> */
h1 + p { font-size: 1.2em; }

/* General sibling - all <p> after <h1> */
h1 ~ p { color: gray; }

Seletores de Atributo

Seletores de atributo correspondem elementos com base em valores de atributo. [attr] corresponde à presença. [attr=val] corresponde ao valor exato. ^= corresponde ao prefixo, $= corresponde ao sufixo, *= corresponde à substring. São poderosos para estilizar inputs de formulário, links por tipo ou elementos com atributos data sem adicionar classes extras.

css
/* Elements with type attribute */
[type] { border: 1px solid #ccc; }

/* Exact match */
[type="text"] { padding: 4px; }

/* Starts with */
a[href^="https"] { color: green; }

/* Ends with */
a[href$=".pdf"] { color: red; }

/* Contains */
a[href*="example"] { font-weight: bold; }

Pseudo-classes

Pseudo-classes selecionam elementos com base em estado ou posição. Interativas: :hover, :focus, :active, :visited, :disabled. Estruturais: :first-child, :last-child, :nth-child(n), :nth-of-type(n). :not() nega um seletor. :nth-child(odd/even) cria listras de zebra. :nth-child(3n) seleciona cada 3º elemento. Estas reduzem a necessidade de classes extras.

css
/* Interactive states */
a:hover { color: red; }
a:visited { color: purple; }
input:focus { border-color: blue; }
input:disabled { background: #eee; }
button:active { transform: scale(0.98); }

/* Structural */
li:first-child { font-weight: bold; }
li:last-child { border: none; }
li:nth-child(odd) { background: #f9f9f9; }
li:nth-child(3n) { color: blue; }
p:not(.highlight) { color: #333; }

Pseudo-elementos

Pseudo-elementos (::dois-pontos) estilizam partes específicas de elementos. ::before e ::after inserem conteúdo gerado (requer propriedade content). ::first-letter e ::first-line estilizam porções de texto. ::selection estiliza texto destacado. ::placeholder estiliza placeholders de input. Nota: ::before/::after são inline por padrão — defina display:block para comportamento de bloco.

css
/* First line of a paragraph */
p::first-line { font-weight: bold; }

/* First letter (drop cap) */
p::first-letter { font-size: 3em; float: left; }

/* Insert content before/after */
.quote::before { content: "\201C"; }
.quote::after { content: "\201D"; }

/* Selection styling */
::selection { background: yellow; color: black; }

/* Placeholder styling */
input::placeholder { color: #999; }

Especificidade & !important

A especificidade determina qual regra se aplica quando seletores entram em conflito. Estilos inline > IDs > classes > tipos. Quando a especificidade empata, a última regra vence. !important sobrescreve tudo, mas quebra a cascata — evite-o. Use DevTools para inspecionar a especificidade. Prefira seletores baseados em classe para manutenibilidade. Aumentar a especificidade repetindo classes (.btn.btn) é um hack — evite-o.

css
/* Specificity hierarchy (low to high):
   1. Type selectors (p, div)         = 0,0,0,1
   2. Class selectors (.btn)          = 0,0,1,0
   3. ID selectors (#header)          = 0,1,0,0
   4. Inline styles (style="...")     = 1,0,0,0
   5. !important                      = overrides all
*/

/* ID beats class */
#nav .link { color: red; }   /* wins */
.nav .link { color: blue; }

/* Avoid !important unless necessary */
.critical { color: red !important; }
02

Box Model

Margin & Padding

Todo elemento é uma caixa com conteúdo, padding, border e margin. Padding fica dentro da border (afeta o background), margin fica fora (transparente). Shorthand: 1 valor = todos os lados, 2 valores = topo/baixo esquerda/direita, 3 = topo esquerda/direita baixo, 4 = topo direita baixo esquerda (sentido horário). margin: 0 auto centraliza elementos de bloco com uma largura definida.

css
.box {
  /* TRBL: top right bottom left */
  margin: 10px 20px 10px 20px;

  /* Shorthand: top/bottom  left/right */
  margin: 10px 20px;

  /* All sides */
  padding: 15px;

  /* Individual sides */
  margin-top: 0;
  padding-left: 24px;

  /* Center horizontally (block) */
  margin: 0 auto;
}

Border & Outline

border adiciona uma linha ao redor do padding, afetando o layout. outline desenha fora da border sem afetar o layout — útil para indicadores de foco. border-radius arredonda cantos (valor único ou por canto: top-left top-right bottom-right bottom-left). outline-offset adiciona espaço entre border e outline. Sempre forneça estilos de foco visíveis para acessibilidade.

css
.box {
  /* Shorthand: width style color */
  border: 2px solid #333;

  /* Individual sides */
  border-bottom: 3px dashed red;
  border-radius: 8px;

  /* Outline (doesn't affect layout) */
  outline: 2px solid blue;
  outline-offset: 4px;
}

/* Remove default focus, add custom */
button:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(0,123,255,0.5);
}

Box Sizing

box-sizing: content-box (padrão) significa que width/height se aplicam apenas ao conteúdo — padding e border são somados ao tamanho total. box-sizing: border-box inclui padding e border no width/height, tornando o dimensionamento previsível. Sempre defina border-box globalmente para layouts consistentes. Este é um dos resets CSS mais importantes.

css
/* Default: width = content only */
.content-box {
  box-sizing: content-box;
  width: 200px;
  padding: 20px;
  border: 5px solid;
  /* Total width: 200 + 40 + 10 = 250px */
}

/* Recommended: width includes padding+border */
.border-box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid;
  /* Total width: 200px */
}

/* Apply globally */
*, *::before, *::after {
  box-sizing: border-box;
}

Box Shadow

box-shadow adiciona efeitos de sombra: offset-x offset-y blur-radius spread-radius color. Offsets positivos movem a sombra para a direita/baixo. inset cria uma sombra interna. Múltiplas sombras são camadas (primeira = topo). Use rgba para sombras semitransparentes que se misturam naturalmente. Sombras são ótimas para profundidade, mas o uso excessivo prejudica a performance — prefira sombras sutis.

css
/* offset-x offset-y blur spread color */
.card {
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

/* Multiple shadows */
.button {
  box-shadow:
    0 1px 2px rgba(0,0,0,0.1),
    0 4px 8px rgba(0,0,0,0.05);
}

/* Inset shadow */
.input:focus {
  box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
}

/* No shadow */
.no-shadow { box-shadow: none; }

Display & Visibility

display: none remove o elemento do layout inteiramente (sem espaço). visibility: hidden o oculta, mas mantém seu espaço. opacity: 0 o torna transparente, mas ainda interativo. Elementos block ocupam toda a largura e quebram linhas. Elementos inline fluem com o texto. inline-block combina fluxo inline com dimensões de bloco (width, height). Use display: none para alternar conteúdo.

css
/* Display types */
div { display: block; }           /* full width, line break */
span { display: inline; }         /* content width, no break */
.inline-block { display: inline-block; } /* inline but block props */
.flex { display: flex; }          /* flex container */
.grid { display: grid; }          /* grid container */
.none { display: none; }          /* removed from layout */

/* Visibility (keeps space) */
.hidden { visibility: hidden; }

/* Opacity (keeps space, can interact) */
.fade { opacity: 0; }
03

Cores & Unidades

Formatos de Cor

O CSS suporta múltiplos formatos de cor. Hex (#rrggbb) é o mais comum. RGB/RGBA adiciona transparência alfa. HSL (Hue 0-360, Saturation%, Lightness%) é intuitivo — mude o hue para mudar a cor, lightness para tons. currentColor herda a propriedade color do elemento. O CSS moderno também suporta oklch() e color() para gamas mais amplas. Use rgba/hsla para transparência.

css
/* Named colors */
.color { color: red; background: tomato; }

/* Hexadecimal */
.hex { color: #ff6600; }        /* 6-digit */
.hex-short { color: #f60; }     /* 3-digit shorthand */

/* RGB / RGBA */
.rgb { color: rgb(255, 102, 0); }
.rgba { background: rgba(0, 0, 0, 0.5); }

/* HSL / HSLA (hue, saturation, lightness) */
.hsl { color: hsl(20, 100%, 50%); }
.hsla { background: hsla(120, 100%, 50%, 0.3); }

/* Current color keyword */
.box { color: blue; border: 2px solid currentColor; }

Unidades de Comprimento

px é absoluto e previsível. em é relativo ao font-size do pai (compõe quando aninhado). rem é relativo ao font-size da raiz (html) — consistente e preferido para acessibilidade. % é relativo ao pai. vh/vw são relativos ao viewport (100vh = altura total). Use rem para tamanhos de fonte, % para layouts e px para bordas/detalhes finos.

css
/* Absolute units */
.px { font-size: 16px; }     /* 1px = 1/96 inch */
.pt { font-size: 12pt; }     /* 1pt = 1/72 inch */

/* Relative to parent font-size */
.em { font-size: 1.5em; }    /* 1.5x parent */

/* Relative to root font-size (html) */
.rem { font-size: 1.2rem; }  /* 1.2x root (usually 16px) */

/* Relative to parent dimensions */
.pct { width: 50%; }         /* 50% of parent */

/* Viewport units */
.vh { height: 100vh; }       /* 100% of viewport height */
.vw { width: 50vw; }         /* 50% of viewport width */
.vmin { font-size: 2vmin; }  /* 2% of smaller dimension */

Funções CSS

calc() realiza matemática com unidades mistas (ex.: 100% - 250px). min() pega o menor valor (ótimo para max-widths responsivos). max() pega o maior. clamp(min, preferred, max) cria valores fluidos que escalam entre limites — perfeito para tipografia responsiva. var() referencia custom properties com um fallback opcional. Essas funções tornam o CSS dinâmico sem media queries.

css
/* calc() - mathematical calculations */
.sidebar { width: calc(100% - 250px); }
.gap { margin: calc(1rem + 10px); }

/* min() / max() - choose smaller/larger */
.responsive { width: min(90%, 1200px); }
.min-width { width: max(300px, 50%); }

/* clamp() - fluid sizing with bounds */
.title { font-size: clamp(1.5rem, 4vw, 3rem); }

/* var() - use custom properties */
.btn { color: var(--primary, #007bff); }

Gradientes

Gradientes criam transições suaves de cor. linear-gradient(direction, color1, color2) vai em uma direção (to right, 45deg). radial-gradient expande a partir de um ponto central. conic-gradient rotaciona ao redor de um centro. Você pode adicionar paradas de cor com posições: linear-gradient(to right, red 0%, blue 50%, green 100%). Gradientes são imagens, não cores, e podem ser usados em qualquer lugar onde background-image é aceito.

css
/* Linear gradient */
.bg1 {
  background: linear-gradient(to right, #ff0000, #0000ff);
}

/* Diagonal with angle */
.bg2 {
  background: linear-gradient(45deg, #ff0000, #00ff00, #0000ff);
}

/* Radial gradient */
.bg3 {
  background: radial-gradient(circle, #ff0000, #0000ff);
}

/* Conic gradient */
.bg4 {
  background: conic-gradient(red, yellow, green, blue, red);
}

Filtros & Blend Modes

filter aplica efeitos visuais: blur(), brightness(), contrast(), grayscale(), sepia(), hue-rotate(), invert(), opacity(), saturate(). Múltiplos filtros encadeiam. mix-blend-mode mistura um elemento com o que está atrás dele (multiply, screen, overlay, etc.). backdrop-filter aplica filtros à área atrás de um elemento (ótimo para glassmorphism). Filtros podem impactar a performance — use com moderação.

css
/* Filters */
img.bw { filter: grayscale(100%); }
img.blur { filter: blur(5px); }
img.bright { filter: brightness(1.5); }
img.sepia { filter: sepia(0.8); }

/* Multiple filters */
img.vintage {
  filter: sepia(0.5) contrast(1.2) brightness(0.9);
}

/* Blend mode */
.overlay {
  background: rgba(255,0,0,0.5);
  mix-blend-mode: multiply;
}
04

Tipografia

Propriedades de Fonte

font-family aceita uma lista de fallback — o navegador usa a primeira disponível. Sempre termine com uma família genérica (serif, sans-serif, monospace). font-weight varia de 100 (thin) a 900 (black). line-height: 1.5 significa 1.5x o tamanho da fonte — 1.4-1.6 é ideal para legibilidade do corpo do texto. O shorthand font deve incluir no mínimo size e family.

css
body {
  /* Font shorthand: style weight size/line-height family */
  font: italic bold 16px/1.5 Arial, sans-serif;

  /* Individual properties */
  font-family: "Helvetica Neue", Arial, sans-serif;
  font-size: 16px;
  font-weight: 400;  /* 100-900, normal=400, bold=700 */
  font-style: italic; /* normal, italic, oblique */
  line-height: 1.5;
}

Estilização de Texto

text-align controla o alinhamento horizontal. text-decoration adiciona linhas (underline, overline, line-through). text-transform muda a capitalização. letter-spacing (tracking) e word-spacing ajustam o espaçamento entre caracteres e palavras. white-space: nowrap impede a quebra de texto. Para alinhamento vertical, use vertical-align (inline) ou alinhamento flexbox/grid (block).

css
p {
  text-align: justify;        /* left, right, center, justify */
  text-decoration: underline; /* none, overline, line-through */
  text-transform: capitalize; /* uppercase, lowercase, capitalize */
  text-indent: 2em;           /* indent first line */
  letter-spacing: 0.05em;     /* tracking */
  word-spacing: 0.1em;
  white-space: nowrap;        /* prevent wrapping */
}

a {
  text-decoration: none;
  color: #0066cc;
}

Text Overflow & Quebra

Para truncar texto com reticências, você precisa de três propriedades: white-space: nowrap, overflow: hidden e text-overflow: ellipsis. overflow-wrap: break-word quebra palavras longas para evitar overflow. word-break: break-all quebra em qualquer caractere. text-wrap: balance (mais novo) equilibra comprimentos de linha para títulos. Sempre defina max-width ou width para que o truncamento funcione.

css
/* Truncate with ellipsis */
.truncate {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}

/* Break long words */
.break-word {
  overflow-wrap: break-word;
  word-break: break-all;
}

/* Balance text wrapping (newer) */
h1 {
  text-wrap: balance;
}

Web Fonts (@font-face)

@font-face carrega fontes personalizadas. woff2 é o formato moderno (melhor compressão). Forneça woff como fallback. font-display: swap mostra texto de fallback imediatamente, depois troca quando a fonte carrega (evita texto invisível). Sempre declare uma família de fonte de fallback. Google Fonts fornece fontes hospedadas via @import ou <link>. Preload fontes críticas para performance.

css
@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/custom.woff2') format('woff2'),
       url('fonts/custom.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: 'MyCustomFont', Arial, sans-serif;
}

/* Google Fonts import */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');

Estilização de Listas & Links

list-style: none remove os marcadores padrão para navegação personalizada ou listas estilizadas. list-style-type muda o marcador (disc, circle, square, decimal, none). list-style-position: inside coloca os marcadores dentro da área de conteúdo. Para links, a ordem LVHA importa: :link, :visited, :hover, :active. Isso garante a cascata adequada dos estados de link.

css
/* Reset list styles */
ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

/* Custom bullets */
ul.custom {
  list-style-type: square;
  list-style-position: inside;
}

/* Image bullets */
ul.image {
  list-style-image: url('bullet.png');
}

/* Link states (order matters!) */
a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; text-decoration: underline; }
a:active { color: orange; }
05

Layout Flexbox

Contêiner Flex

display: flex cria um contêiner flex. justify-content alinha itens ao longo do eixo principal (horizontal em row). align-items alinha ao longo do eixo cruzado (vertical). flex-direction muda o eixo principal. flex-wrap permite que itens quebrem para novas linhas. gap define o espaçamento entre itens (substitui hacks de margin). Flexbox é ideal para layouts 1D (linhas OU colunas).

css
.container {
  display: flex;

  /* Main axis alignment */
  justify-content: space-between;
  /* flex-start, center, flex-end, space-around, space-evenly */

  /* Cross axis alignment */
  align-items: center;
  /* flex-start, center, flex-end, stretch, baseline */

  /* Direction */
  flex-direction: row;
  /* row, row-reverse, column, column-reverse */

  /* Wrapping */
  flex-wrap: wrap;
  /* nowrap, wrap, wrap-reverse */

  /* Gap between items */
  gap: 16px;
}

Flex Items

flex-grow controla como os itens compartilham espaço extra (0 = não crescer, 1 = crescer igualmente). flex-shrink controla como os itens encolhem quando o espaço é limitado. flex-basis define o tamanho inicial. O shorthand flex: 1 significa flex-grow:1, flex-shrink:1, flex-basis:0%. align-self sobrescreve o align-items do contêiner para um item. order reordena itens visualmente sem mudar o DOM.

css
.item {
  /* Grow: how much space to take (0 = don't grow) */
  flex-grow: 1;

  /* Shrink: how much to shrink when space is tight */
  flex-shrink: 0;

  /* Basis: initial size before growing/shrinking */
  flex-basis: 200px;

  /* Shorthand: flex: grow shrink basis */
  flex: 1 0 200px;

  /* Override align-items for this item */
  align-self: flex-end;

  /* Order (default 0, lower = earlier) */
  order: -1;
}

Padrões Comuns de Flexbox

Flexbox torna o centralização trivial: justify-content: center + align-items: center. Para um footer fixo, faça do body uma coluna flex com min-height: 100vh e deixe o conteúdo principal com flex: 1. Para navbars, justify-content: space-between empurra o primeiro e o último item para extremidades opostas. Esses padrões resolvem problemas comuns de layout que eram difíceis antes do flexbox.

css
/* Center anything */
.center {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* Sticky footer */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.main { flex: 1; }

/* Navbar: logo left, links right */
.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

Flex Direction & Wrap

flex-direction: column cria layouts verticais (útil para empilhamento). flex-wrap: wrap permite que itens fluam para novas linhas quando ficam sem espaço. flex: 1 1 300px significa que itens começam em 300px, crescem para preencher espaço e encolhem conforme necessário. align-content controla o espaçamento entre linhas quebradas (só funciona com wrap). Este padrão cria grids de cards responsivos.

css
/* Horizontal (default) */
.row { display: flex; flex-direction: row; }

/* Vertical */
.column { display: flex; flex-direction: column; }

/* Reverse */
.row-rev { display: flex; flex-direction: row-reverse; }

/* Wrap to new lines */
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}
.card { flex: 1 1 300px; } /* grow, shrink, basis */

/* Align wrapped lines */
.cards { align-content: space-between; }

Aprofundamento em Alinhamento Flexbox

Em flex-direction: column, o eixo principal é vertical e o eixo cruzado é horizontal — justify-content e align-items trocam de papel. margin: auto em um flex item absorve todo o espaço disponível, centralizando-o perfeitamente. Isso é uma alternativa a justify-content/align-items. Entender qual eixo é 'principal' vs 'cruzado' é a chave para dominar o alinhamento flexbox.

css
.container {
  display: flex;
  flex-direction: column;

  /* Main axis = vertical (column) */
  justify-content: flex-start;
  /* push items to top, center, bottom, or spread */

  /* Cross axis = horizontal (column) */
  align-items: stretch;
  /* stretch items to full width */
}

/* Center a single item perfectly */
.wrapper {
  display: flex;
  min-height: 100vh;
}
.centered {
  margin: auto; /* centers in both axes */
}
06

Layout CSS Grid

Contêiner Grid

display: grid cria um layout 2D. grid-template-columns define tamanhos de coluna: unidades fr distribuem espaço livre proporcionalmente. repeat(3, 1fr) cria 3 colunas iguais. repeat(auto-fit, minmax(250px, 1fr)) cria um grid responsivo que autoajusta a contagem de colunas — este é o 'santo graal' dos grids responsivos. gap substitui margins para espaçamento.

css
.grid {
  display: grid;

  /* Define columns */
  grid-template-columns: 200px 1fr 200px;
  /* fixed, flexible, fixed */

  /* Or repeat */
  grid-template-columns: repeat(3, 1fr);
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

  /* Define rows */
  grid-template-rows: auto 1fr auto;

  /* Gap (formerly grid-gap) */
  gap: 20px;
  row-gap: 10px;
  column-gap: 20px;
}

Posicionamento de Grid Item

Grid items podem ocupar múltiplas células com grid-column: span N. Você também pode usar números de linha: grid-column: 1 / 3 significa começar na linha 1, terminar na linha 3. As linhas são numeradas de 1 (esquerda/topo) a N+1 (direita/baixo). grid-area atribui itens a áreas nomeadas. Grid permite posicionamento 2D preciso — itens podem ocupar tanto linhas quanto colunas simultaneamente.

css
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}

/* Span multiple columns */
.featured {
  grid-column: span 2;
}

/* Explicit placement */
.sidebar {
  grid-column: 1 / 3;  /* start at line 1, end at line 3 */
  grid-row: 1 / 4;
}

/* Named areas */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }

Áreas de Template Grid

grid-template-areas cria um mapa visual do layout usando strings nomeadas. Cada string representa uma linha; cada nome representa uma coluna. Itens são posicionados definindo grid-area para o nome correspondente. Esta é a maneira mais legível de criar layouts complexos. Use '.' para células vazias. O mesmo nome pode ocupar múltiplas células. Altere áreas em media queries para layouts responsivos.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  gap: 10px;
  min-height: 100vh;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

Alinhamento Grid

Grid tem 6 propriedades de alinhamento. align-items/justify-items alinham itens dentro de suas células grid. align-content/justify-content alinham toda a trilha grid dentro do contêiner (visível apenas se o grid for menor). align-self/justify-self sobrescrevem por item. place-items: center é shorthand para align-items + justify-items. place-content: center combina ambos os alinhamentos de conteúdo.

css
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);

  /* Align items within their cell (cross axis) */
  align-items: center;  /* start, center, end, stretch */

  /* Justify items within their cell (main axis) */
  justify-items: center;

  /* Align the entire grid (if smaller than container) */
  align-content: center;
  justify-content: center;
}

/* Override for individual item */
.item {
  align-self: end;
  justify-self: start;
}

Grid Responsivo (Auto-fit)

repeat(auto-fit, minmax(300px, 1fr)) cria um grid que ajusta automaticamente a contagem de colunas com base no espaço disponível — itens têm pelo menos 300px e crescem para preencher. Isso elimina media queries para layouts de cards. auto-fill mantém colunas vazias (itens ficam à esquerda), auto-fit as colapsa (itens se esticam). Use auto-fit para a maioria dos casos. Combine com max-width no contêiner para resultados ótimos.

css
/* Auto-responsive grid - no media queries needed! */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
}

/* Fixed number of columns per breakpoint */
@media (min-width: 768px) {
  .cards {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1024px) {
  .cards {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* Auto-fill vs auto-fit:
   auto-fit collapses empty tracks
   auto-fill keeps empty tracks */
07

Posicionamento

Tipos de Posição

static é o padrão (fluxo normal do documento). relative desloca de sua posição normal sem afetar outros elementos (cria contexto de posicionamento). absolute remove do fluxo e posiciona relativo ao ancestral posicionado mais próximo. fixed posiciona relativo ao viewport (permanece ao rolar). sticky alterna entre relative e fixed — rola normalmente e então gruda no limiar.

css
/* Static (default) - normal flow */
.static { position: static; }

/* Relative - offset from normal position */
.relative {
  position: relative;
  top: 10px;
  left: 20px;
}

/* Absolute - positioned relative to nearest positioned ancestor */
.absolute {
  position: absolute;
  top: 0;
  right: 0;
}

/* Fixed - positioned relative to viewport */
.fixed {
  position: fixed;
  bottom: 0;
  width: 100%;
}

/* Sticky - scrolls then sticks */
.sticky {
  position: sticky;
  top: 0;
}

Posicionamento Absoluto

posicionamento absoluto requer um ancestral posicionado (relative, absolute, fixed ou sticky). Sem um, posiciona relativo ao viewport. As propriedades top/right/bottom/left deslocam da borda correspondente. Para centralizar um elemento absolutamente posicionado, use top:50%, left:50% com transform: translate(-50%,-50%). Posicionamento absoluto remove elementos do fluxo normal.

css
/* Parent must be positioned */
.container {
  position: relative;
  width: 400px;
  height: 300px;
}

/* Position relative to container */
.badge {
  position: absolute;
  top: 10px;
  right: 10px;
}

/* Center absolutely positioned element */
.modal {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Posicionamento Sticky

position: sticky é um híbrido — elementos rolam normalmente até atingir um limiar (ex.: top: 0), então grudam. Ótimo para cabeçalhos sticky, sidebars e cabeçalhos de tabela. O elemento gruda dentro de seu contêiner pai (para de grudar quando o pai rola além). Sticky não funciona se algum ancestral tiver overflow: hidden/auto/scroll. Sempre defina um z-index para evitar problemas de sobreposição.

css
/* Sticky header */
.header {
  position: sticky;
  top: 0;
  background: white;
  z-index: 100;
  padding: 1rem;
}

/* Sticky sidebar */
.sidebar {
  position: sticky;
  top: 80px; /* offset for fixed header */
  height: calc(100vh - 80px);
  overflow-y: auto;
}

/* Note: sticky doesn't work if a parent has
   overflow: hidden or overflow: auto */

Z-index & Stacking Context

z-index controla a ordem de empilhamento de elementos posicionados (maior = no topo). Só funciona em elementos posicionados (não static). Um stacking context é criado por elementos posicionados com z-index, opacity < 1, transform ou filter. Dentro de um stacking context, valores de z-index filho são relativos àquele contexto — um filho nunca pode aparecer acima de um irmão de seu pai com z-index maior. Esta é uma fonte comum de confusão.

css
/* Higher z-index = closer to viewer */
.modal-overlay {
  position: fixed;
  z-index: 9999;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.5);
}

.modal {
  position: fixed;
  z-index: 10000; /* above overlay */
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}

/* Stacking context: z-index only works
   within the same stacking context */
.parent { position: relative; z-index: 1; }
.child { position: absolute; z-index: 9999; }
/* child can't exceed parent's stacking level */

Float & Clear (Legado)

float era o método principal de layout antes do flexbox/grid. Remove elementos do fluxo normal e os empurra para esquerda/direita, com texto envolvendo ao redor. clear impede que elementos apareçam ao lado de floats. O hack clearfix força um contêiner a envolver filhos flutuados. Hoje, use float apenas para seu propósito pretendido: envolver texto ao redor de imagens. Para layouts, use flexbox ou grid.

css
/* Float text around an image */
img.float-left {
  float: left;
  margin: 0 1rem 1rem 0;
}

/* Clear floats */
.clear { clear: both; }
.clear-left { clear: left; }
.clear-right { clear: right; }

/* Clearfix hack for containers */
.clearfix::after {
  content: "";
  display: table;
  clear: both;
}

/* Modern alternative: use flexbox or grid */
/* Float is mainly for text wrapping now */
08

Design Responsivo

Media Queries

Media queries aplicam estilos com base em condições. min-width (mobile-first) é preferido — estilos base visam mobile, depois aprimoram para telas maiores. max-width (desktop-first) é o inverso. Outras condições: prefers-color-scheme (dark/light), print, orientation (portrait/landscape), prefers-reduced-motion. Sempre defina uma meta tag viewport no HTML para que media queries funcionem em mobile.

css
/* Mobile-first: base styles first, then min-width */

/* Base (mobile) */
.container { flex-direction: column; }

/* Tablet and up */
@media (min-width: 768px) {
  .container { flex-direction: row; }
}

/* Desktop and up */
@media (min-width: 1024px) {
  .container { max-width: 1200px; margin: 0 auto; }
}

/* Print styles */
@media print {
  .no-print { display: none; }
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  body { background: #1a1a1a; color: #eee; }
}

Tipografia Fluida

clamp(min, preferred, max) cria tipografia fluida que escala suavemente com o tamanho do viewport — sem media queries necessárias. O valor preferred (frequentemente baseado em vw) escala entre limites min e max. min() pega o menor valor (ótimo para max-widths responsivos). Esta abordagem reduz o número de media queries necessárias e cria escala mais suave. Sempre defina min/max razoáveis para legibilidade.

css
/* clamp() for fluid font sizes */
h1 {
  font-size: clamp(1.5rem, 5vw, 3rem);
  /* min: 1.5rem, preferred: 5vw, max: 3rem */
}

/* Fluid spacing */
.container {
  padding: clamp(1rem, 3vw, 3rem);
}

/* Fluid width */
.content {
  width: min(90%, 1200px);
  margin: 0 auto;
}

/* Viewport-based sizing */
.hero {
  height: 100vh;
  font-size: clamp(2rem, 8vw, 5rem);
}

Container Queries

Container queries (CSS Containment Module Level 3) permitem estilizar elementos com base no tamanho do contêiner pai, não do viewport. container-type: inline-size declara um contêiner. @container aplica estilos quando o contêiner atende à condição. Isso é mais modular que media queries — componentes se adaptam ao seu contêiner, não à tela. Ótimo para componentes reutilizáveis em diferentes contextos de layout.

css
/* Define a container */
.card-container {
  container-type: inline-size;
  /* or: container: sidebar / inline-size; */
}

/* Query the container's size */
@container (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: row;
  }
}

@container (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

Imagens & Mídia Responsivas

max-width: 100% + height: auto torna as imagens responsivas (reduz mas nunca aumenta). O hack de padding-bottom cria embeds de vídeo 16:9 responsivos. A propriedade moderna aspect-ratio é mais limpa — defina a proporção e o navegador calcula a altura. Sempre defina atributos width e height em imagens para evitar layout shift (CLS). Use object-fit: cover para recortar imagens dentro de dimensões fixas.

css
/* Responsive image */
img {
  max-width: 100%;
  height: auto;
}

/* Responsive video (16:9 aspect ratio) */
.video-wrapper {
  position: relative;
  padding-bottom: 56.25%; /* 9/16 */
  height: 0;
}
.video-wrapper iframe {
  position: absolute;
  top: 0; left: 0;
  width: 100%;
  height: 100%;
}

/* Aspect ratio property */
.box {
  aspect-ratio: 16 / 9;
  width: 100%;
}

Estratégia Mobile-First

Mobile-first significa escrever estilos mobile como base, depois aprimorar progressivamente para telas maiores com media queries min-width. Isso garante que usuários mobile (frequentemente em conexões mais lentas) baixem menos CSS. Breakpoints comuns: 768px (tablet), 1024px (desktop), 1440px (large). Use unidades relativas (rem, %, vw) em vez de px fixo para melhor escalabilidade. Teste em dispositivos reais, não apenas no DevTools do navegador.

css
/* 1. Start with mobile base styles */
.nav { display: none; } /* hidden on mobile */
.menu-toggle { display: block; }

/* 2. Enhance for larger screens */
@media (min-width: 768px) {
  .nav { display: flex; }
  .menu-toggle { display: none; }
}

/* 3. Common breakpoints */
/* Mobile: < 768px */
/* Tablet: 768px - 1023px */
/* Desktop: 1024px - 1439px */
/* Large: >= 1440px */

/* 4. Use relative units */
body { font-size: 1rem; } /* not 16px */
09

Transições & Animações

Transições

transition cria mudanças suaves entre valores de propriedade. Sintaxe: transition: property duration timing-function delay. Funções de timing: ease (padrão), linear, ease-in, ease-out, ease-in-out, cubic-bezier(). Apenas propriedades animáveis fazem transição. Evite transition: all (performance). Transições disparam em mudanças de pseudo-classe (:hover, :focus) ou mudanças de classe via JavaScript.

css
.button {
  background: #007bff;
  transition: background 0.3s ease, transform 0.2s ease;
}

.button:hover {
  background: #0056b3;
  transform: translateY(-2px);
}

/* Transition all properties (use sparingly) */
.card {
  transition: all 0.3s ease;
}

/* Shorthand: property duration timing-function delay */
.box {
  transition: opacity 0.5s ease-in 0.2s;
}

Transform

transform modifica um elemento sem afetar o layout (diferente de margin/position). translate o move (translateX, translateY ou translate(x,y)). scale o redimensiona (1 = 100%). rotate o gira (deg, rad, turn). skew o distorce. Múltiplos transforms encadeiam em ordem. Transforms são acelerados por GPU — ótimos para performance. Sempre combine com transition para efeitos suaves. transform-origin muda o ponto de pivô.

css
.box {
  transition: transform 0.3s ease;
}

/* Translate (move) */
.box:hover { transform: translate(10px, 20px); }
.box:hover { transform: translateX(50%); }

/* Scale (resize) */
.box:hover { transform: scale(1.1); }

/* Rotate */
.box:hover { transform: rotate(45deg); }

/* Skew */
.box:hover { transform: skew(10deg, 5deg); }

/* Combine transforms */
.box:hover {
  transform: translate(10px, 0) scale(1.1) rotate(5deg);
}

Animações Keyframe

@keyframes define passos de animação. 0%/from é o início, 100%/to é o fim. Você pode adicionar passos intermediários (25%, 50%, 75%). O shorthand animation: name duration timing-function delay iteration-count direction fill-mode. infinite repete para sempre. direction: alternate inverte em iterações pares. fill-mode: forwards mantém o estado final. Animações executam automaticamente, diferentemente das transições.

css
@keyframes bounce {
  0%   { transform: translateY(0); }
  50%  { transform: translateY(-20px); }
  100% { transform: translateY(0); }
}

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.ball {
  animation: bounce 0.5s ease infinite;
}

.element {
  animation: fadeIn 1s ease forwards;
  /* name duration timing delay iteration direction fill-mode */
}

Propriedades de Animação

Propriedades individuais de animação dão controle fino. animation-iteration-count pode ser um número ou infinite. animation-direction: alternate reproduz para frente e depois para trás (ótimo para efeitos ping-pong). animation-fill-mode: forwards mantém o estado final após terminar. animation-play-state: paused congela a animação — útil para hover-to-pause. Múltiplas animações se separam por vírgula: animation: spin 1s, fade 2s;.

css
.spinner {
  animation-name: spin;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-delay: 0s;
  animation-iteration-count: infinite;
  animation-direction: normal; /* alternate, reverse */
  animation-fill-mode: none;   /* forwards, backwards, both */
  animation-play-state: running; /* paused */
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Pause on hover */
.spinner:hover {
  animation-play-state: paused;
}

Performance & Movimento Reduzido

Para animações suaves a 60fps, anime apenas transform e opacity — eles são acelerados por GPU e não disparam layout (reflow). Animar width, margin, top, etc. força o navegador a recalcular o layout a cada quadro, causando jank. Sempre respeite prefers-reduced-motion: reduce — alguns usuários sofrem de enjoo por movimento ou têm distúrbios vestibulares. Forneça transições instantâneas ou desabilite animações para esses usuários.

css
/* Only animate transform and opacity for performance */
.good {
  transition: transform 0.3s, opacity 0.3s;
}

/* Avoid animating these (cause reflow/repaint): */
/* margin, padding, width, height, top, left */

/* Respect user's motion preference */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
}
10

Variáveis & Funções Avançadas

Custom Properties (Variáveis)

Custom properties (variáveis CSS) armazenam valores reutilizáveis. Defina-as em :root para acesso global. Referencie com var(--name). Elas cascateiam e podem ser sobrescritas em qualquer escopo — perfeito para theming (modo dark/light). Diferente das variáveis de pré-processador, elas são dinâmicas (mudam em runtime) e podem ser manipuladas com JavaScript. Sempre forneça fallbacks: var(--primary, #007bff). Esta é a maneira moderna de gerenciar design tokens.

css
:root {
  /* Colors */
  --primary: #007bff;
  --primary-dark: #0056b3;
  --text: #333;
  --bg: #fff;

  /* Spacing scale */
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 2rem;

  /* Font sizes */
  --font-base: 16px;
  --font-lg: 1.5rem;
}

.button {
  background: var(--primary);
  padding: var(--space-sm) var(--space-md);
  font-size: var(--font-base);
  color: white;
}

/* Override in a scope */
.dark-theme {
  --bg: #1a1a1a;
  --text: #eee;
}

calc() & Funções Matemáticas

calc() realiza matemática com quaisquer unidades, incluindo mistura de px, %, em, rem, vw. É essencial para layouts responsivos. Você pode aninhar calc(), mas é desnecessário — calc(100% - 2rem) / 3 funciona sem calc interno. min() retorna o menor valor, max() o maior, clamp() limita um valor entre min e max. Essas funções tornam o CSS dinâmico sem JavaScript ou media queries.

css
/* Mixed unit calculations */
.sidebar {
  width: calc(100% - 250px);
}

/* With variables */
.box {
  padding: calc(var(--space-md) + 10px);
}

/* Nested calc */
.responsive {
  width: calc(calc(100% - 2rem) / 3);
}

/* min(), max(), clamp() */
.fluid {
  width: min(90%, 1200px);
  font-size: clamp(1rem, 2vw + 1rem, 2rem);
  height: max(200px, 50vh);
}

Object Fit & Position

object-fit controla como imagens/vídeo preenchem seu contêiner (como background-size para <img>). cover preenche o contêiner e recorta o overflow (ótimo para avatares/thumbnails). contain se encaixa inteiramente sem recortar (pode deixar espaço vazio). fill estica (distorce). object-position ajusta o alinhamento (como background-position). Isso substitui a necessidade de hacks de background-image para imagens responsivas.

css
/* Cover: fill container, crop overflow */
.avatar {
  width: 100px;
  height: 100px;
  object-fit: cover;
  border-radius: 50%;
}

/* Contain: fit entirely, may letterbox */
.preview {
  width: 200px;
  height: 200px;
  object-fit: contain;
  background: #eee;
}

/* Position the image within the frame */
.image {
  object-fit: cover;
  object-position: top center;
}

Propriedades de Background

background é um shorthand poderoso. background-size: cover preenche o contêiner (recortando); contain se encaixa sem recortar. background-attachment: fixed cria um efeito parallax (a imagem fica parada durante a rolagem). Múltiplos backgrounds são camadas com vírgulas (primeiro = camada superior). Use linear-gradient como background para sobreposições: background: linear-gradient(rgba(0,0,0,0.5), transparent), url('image.jpg').

css
.hero {
  /* Shorthand */
  background: url('hero.jpg') center/cover no-repeat fixed;

  /* Individual properties */
  background-image: url('hero.jpg');
  background-size: cover;     /* cover, contain, or px/% */
  background-position: center; /* top, bottom, left, right, or x y */
  background-repeat: no-repeat;
  background-attachment: fixed; /* scroll, fixed, local */

  /* Multiple backgrounds */
  background:
    url('overlay.png') no-repeat center,
    url('hero.jpg') center/cover;
}

CSS Nesting (Moderno)

O CSS moderno suporta nesting nativo (como Sass/Less). Use & para referenciar o seletor pai. Nesting melhora a legibilidade e reduz repetição. Media queries podem ser aninhadas diretamente dentro de regras. O suporte do navegador é bom em navegadores modernos (2023+). O & é necessário para pseudo-classes (&:hover) e combinadores (& > .child). Evite nesting profundo (3+ níveis) pois aumenta a especificidade e reduz a manutenibilidade.

css
/* Native CSS nesting (no preprocessor needed) */
.card {
  background: white;
  border-radius: 8px;

  & .title {
    font-size: 1.5rem;
    font-weight: bold;
  }

  & .body {
    padding: 1rem;

    & p {
      line-height: 1.6;
    }
  }

  &:hover {
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
  }

  @media (max-width: 768px) {
    padding: 0.5rem;
  }
}
11

Aprofundamento em CSS Custom Properties (Variáveis)

Definindo & Usando Variáveis

CSS custom properties (variáveis) são definidas com --name e usadas com var(). Defina variáveis globais em :root para valores de tema. Diferente das variáveis Sass, as variáveis CSS são live — alterá-las atualiza todos os usos instantaneamente. Elas têm escopo no elemento em que são definidas e são herdadas por descendentes. var() aceita um valor de fallback como segundo argumento, e fallbacks podem ser encadeados. Isso as torna muito mais poderosas que variáveis de pré-processador para theming dinâmico.

css
:root {
  --primary: #3498db;
  --spacing: 16px;
  --radius: 8px;
  --max-width: 1200px;
}

.button {
  background: var(--primary);
  padding: var(--spacing);
  border-radius: var(--radius);
  max-width: var(--max-width);
}

/* Fallback values */
color: var(--text-color, #333);
/* Chained fallbacks */
color: var(--text, var(--default, black));

Theming Dinâmico com JavaScript

Variáveis CSS habilitam theming em runtime que pré-processadores não conseguem fazer. Defina data-theme em <html> e sobrescreva variáveis por tema. JavaScript pode ler (getComputedStyle) e definir (style.setProperty) variáveis em runtime, permitindo seletores de cor dinâmicos, preferências do usuário e pré-visualizações live. Esta é a abordagem padrão para modo dark, personalização de marca e temas selecionáveis pelo usuário. Variáveis cascateiam e herdam, então sobrescrever em um elemento filho afeta apenas aquela subárvore.

css
/* Define theme variables */
:root {
  --bg: #ffffff;
  --text: #333333;
}

[data-theme="dark"] {
  --bg: #1a1a1a;
  --text: #e0e0e0;
}

body {
  background: var(--bg);
  color: var(--text);
}

/* Toggle theme with JS */
<script>
document.documentElement.setAttribute(
  "data-theme",
  isDark ? "dark" : "light"
);

/* Or set a single variable directly */
document.documentElement.style
  .setProperty("--primary", "#e74c3c");
</script>

Variáveis com Escopo & Herança

Variáveis CSS herdam como outras propriedades. Uma variável definida em :root está disponível em todo lugar; uma definida em .card afeta apenas .card e seus descendentes. Esse escopo permite personalização em nível de componente. Você pode sobrescrever variáveis em media queries para criar valores de variáveis responsivos — a variável em si não pode ser usada em condições @media, mas você pode mudar seu valor dentro de um bloco de media query. Esse padrão é poderoso para design responsivo sem repetir declarações de propriedade.

css
:root {
  --padding: 20px;
}

.card {
  --padding: 12px; /* overrides only for .card subtree */
  padding: var(--padding);
}

.card .inner {
  padding: var(--padding); /* inherits 12px from .card */
}

/* Variables in media queries don't work, but... */
.sidebar {
  --width: 250px;
  width: var(--width);
}
@media (max-width: 768px) {
  .sidebar { --width: 100%; }
}

Variáveis com calc()

Combinar variáveis CSS com calc() cria sistemas de design poderosos. Defina um tamanho base e fator de escala, depois calcule tamanhos derivados. Isso habilita escalas tipográficas e sistemas de espaçamento consistentes. calc() funciona com unidades mistas (px, %, em, vw) e variáveis. Você pode até usar variáveis sem fallbacks (var(--nav-h, 60px) fornece um padrão). Esta abordagem é a base dos sistemas de design modernos — mude uma variável e toda a escala se ajusta proporcionalmente.

css
:root {
  --base-size: 16px;
  --scale: 1.25;
}

h1 { font-size: calc(var(--base-size) * var(--scale) * 2); }
h2 { font-size: calc(var(--base-size) * var(--scale) * 1.5); }
p  { font-size: var(--base-size); }

/* Spacing scale */
:root {
  --space: 8px;
}
.margin { margin: calc(var(--space) * 2); }
.padding { padding: calc(var(--space) * 3); }

/* Mixed units */
.header { height: calc(var(--nav-h, 60px) + var(--content-h)); }

Registrando Custom Properties (@property)

@property registra custom properties com um tipo (syntax), valor inicial e flag de herança. Isso habilita variáveis CSS a serem animadas e transicionadas — sem @property, variáveis são tratadas como strings e não podem ser interpoladas. syntax aceita tipos como <angle>, <color>, <length>, <number>, <percentage> ou '*'. Isso desbloqueia animações suaves de gradientes, transforms e cores orientadas por variáveis. O suporte do navegador é bom no Chromium e Safari, com Firefox adicionando suporte. Um grande avanço para as capacidades de animação CSS.

css
/* Type-safe custom properties */
@property --angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}

@property --color {
  syntax: "<color>";
  initial-value: #3498db;
  inherits: false;
}

/* Now animatable! */
@keyframes spin {
  to { --angle: 360deg; }
}

.loader {
  --angle: 0deg;
  animation: spin 1s linear infinite;
  background: conic-gradient(
    from var(--angle),
    var(--color), transparent
  );
}
12

Transforms 3D

Funções de Transform 3D

Transforms 3D adicionam profundidade aos elementos. perspective() como função de transform se aplica a um único elemento; a propriedade perspective em um pai se aplica a todos os filhos uniformemente. rotateX/rotateY/rotateZ rotacionam ao redor de eixos; translateZ move ao longo do eixo Z (em direção/afastando do visualizador). Valores menores de perspective criam efeitos 3D mais dramáticos (ponto de vista mais próximo). Sempre defina perspective no contêiner pai para espaço 3D consistente em múltiplos filhos transformados. Combine múltiplos transforms para posicionamento 3D complexo.

css
.card {
  transform: perspective(1000px) rotateY(45deg) rotateX(15deg);
}

/* Using the perspective property instead */
.container {
  perspective: 1000px;
}
.container .card {
  transform: rotateY(45deg) rotateX(15deg);
}

/* translateZ moves toward/away from viewer */
.layer {
  transform: translateZ(100px);
}

/* scale3d for 3D scaling */
.box {
  transform: scale3d(1.5, 1.5, 1.5);
}

transform-style & backface-visibility

transform-style: preserve-3d mantém o espaço 3D para elementos filhos (flat é o padrão, que achata os filhos). backface-visibility: hidden oculta o lado de trás de um elemento quando rotacionado — essencial para efeitos de flip card. O flip card clássico usa duas faces posicionadas absolutamente: front voltada para frente, back pré-rotacionada 180deg. No hover, o pai rotaciona 180deg, trocando qual face é visível. Este é um dos padrões 3D CSS mais populares.

css
.container {
  perspective: 1000px;
}

.flip-card {
  transform-style: preserve-3d;
  transition: transform 0.6s;
  position: relative;
}

.flip-card:hover {
  transform: rotateY(180deg);
}

.flip-card .front,
.flip-card .back {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
}

.flip-card .back {
  transform: rotateY(180deg);
}

Cubo 3D

Um cubo 3D é construído com 6 faces, cada posicionada com rotate + translateZ. translateZ(100px) empurra a face para fora em metade da largura do cubo. Cada face é pré-rotacionada para direcionar-se à sua direção antes de ser empurrada para fora. transform-style: preserve-3d no contêiner do cubo é essencial — sem ele, as faces achatam. A animação rotaciona o cubo em ambos os eixos X e Y. Isso demonstra o poder completo dos transforms 3D CSS. Ajuste translateZ para corresponder a metade do tamanho do cubo para geometria adequada.

css
.scene {
  perspective: 800px;
  width: 200px; height: 200px;
}
.cube {
  position: relative;
  width: 100%; height: 100%;
  transform-style: preserve-3d;
  animation: rotate 8s infinite linear;
}
@keyframes rotate {
  from { transform: rotateX(0) rotateY(0); }
  to   { transform: rotateX(360deg) rotateY(360deg); }
}
.face {
  position: absolute;
  width: 200px; height: 200px;
  opacity: 0.85;
}
.front  { transform: translateZ(100px); background: red; }
.back   { transform: rotateY(180deg) translateZ(100px); background: blue; }
.right  { transform: rotateY(90deg) translateZ(100px); background: green; }
.left   { transform: rotateY(-90deg) translateZ(100px); background: yellow; }
.top    { transform: rotateX(90deg) translateZ(100px); background: purple; }
.bottom { transform: rotateX(-90deg) translateZ(100px); background: orange; }

Efeito de Inclinação de Card 3D

O efeito de inclinação do card rastreia a posição do mouse e rotaciona o card em 3D com base no deslocamento do cursor em relação ao centro. A matemática divide o deslocamento por um fator (10) para limitar o ângulo de rotação. No mouseleave, o card volta ao plano. A transition cria movimento suave. Adicionar uma sobreposição de brilho/brilho com um gradiente radial que segue o mouse aprimora o efeito. Este é um padrão de UI interativo popular para cards de produto e seções hero. A perspective na string de transform garante renderização 3D mesmo sem uma propriedade perspective pai.

css
.tilt-card {
  transition: transform 0.1s ease-out;
  transform-style: preserve-3d;
}

/* JavaScript-driven tilt */
<script>
const card = document.querySelector(".tilt-card");
card.addEventListener("mousemove", (e) => {
  const rect = card.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  const centerX = rect.width / 2;
  const centerY = rect.height / 2;
  const rotateX = (y - centerY) / 10;
  const rotateY = (centerX - x) / 10;
  card.style.transform =
    `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
});
card.addEventListener("mouseleave", () => {
  card.style.transform = "perspective(1000px) rotateX(0) rotateY(0)";
});
</script>

perspective-origin & Espaçamento 3D

perspective-origin define a posição do ponto de fuga (como mover a cabeça). O padrão é 50% 50% (centro). Movê-lo cria ângulos de visualização dinâmicos. Para efeitos parallax, elementos em diferentes valores translateZ movem-se em taxas diferentes quando o contêiner rola ou rotaciona. Elementos mais atrás (translateZ negativo) precisam de scale() para compensar a redução da perspective. Esta técnica cria profundidade na UI sem JavaScript — parallax CSS puro. Combinado com animações scroll-driven, cria experiências de rolagem imersivas.

css
.stage {
  perspective: 1200px;
  perspective-origin: 50% 30%; /* x y position of vanishing point */
  transform-style: preserve-3d;
}

.layer-1 { transform: translateZ(0); }
.layer-2 { transform: translateZ(50px); }
.layer-3 { transform: translateZ(100px); }

/* Parallax-like depth */
.depth-bg    { transform: translateZ(-200px) scale(1.2); }
.depth-mid   { transform: translateZ(-100px) scale(1.1); }
.depth-fg    { transform: translateZ(0); }
13

Filtros CSS & Backdrop Filters

Funções de Filter

Filtros CSS aplicam efeitos visuais a elementos. grayscale, sepia e invert mudam cores; blur suaviza; brightness/contrast/saturate ajustam intensidade; hue-rotate desloca cores. Múltiplos filtros encadeiam da esquerda para a direita. drop-shadow é superior a box-shadow para imagens PNG/SVG porque segue a forma alfa (áreas transparentes não recebem sombra). Filtros são acelerados por GPU e performam bem. Uso comum: grayscale no hover para galerias de imagens, efeitos de foto vintage e acessibilidade (modos de alto contraste).

css
img.grayscale { filter: grayscale(100%); }
img.blur { filter: blur(5px); }
img.bright { filter: brightness(1.5); }
img.contrast { filter: contrast(200%); }
img.sepia { filter: sepia(80%); }
img.saturate { filter: saturate(2); }
img.hue { filter: hue-rotate(90deg); }
img.invert { filter: invert(100%); }

/* Combine multiple filters */
img.vintage {
  filter: sepia(50%) contrast(110%) brightness(90%) saturate(120%);
}

/* Drop shadow (follows alpha shape) */
img.png-shadow {
  filter: drop-shadow(2px 4px 6px rgba(0,0,0,0.4));
}

backdrop-filter (Glassmorphism)

backdrop-filter aplica filtros à área atrás de um elemento (não ao elemento em si), criando o efeito glassmorphism. O elemento precisa de um background semitransparente para que o efeito seja visível. blur é o filtro de backdrop mais comum para vidro fosco. Sempre inclua o prefixo -webkit- para suporte no Safari. Combine com bordas semitransparentes e box-shadows sutis para um visual de vidro polido. A performance pode ser um problema com grandes áreas desfocadas — use com moderação. Esta é uma tendência definidora no design de UI moderno (iOS, macOS, Windows Acrylic).

css
.glass {
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px) saturate(180%);
  -webkit-backdrop-filter: blur(10px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  padding: 24px;
}

.glass-dark {
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

Filtros SVG (referência url)

CSS filter: url(#id) referencia filtros SVG para efeitos além das funções embutidas. O filtro 'gooey' cria fusão de elementos em formato de blob (popular para animações de carregamento e UI orgânica). feGaussianBlur + feColorMatrix com um multiplicador alfa alto cria o efeito gooey aguçando bordas desfocadas. feTurbulence + feDisplacementMap cria efeitos ondulados/distorcidos. Filtros SVG são poderosos, mas podem ser intensivos em performance. Eles habilitam efeitos impossíveis apenas com CSS: morphing líquido, deslocamento, iluminação e composição personalizada.

css
<!-- Define SVG filter -->
<svg style="display:none">
  <filter id="gooey">
    <feGaussianBlur in="SourceGraphic" stdDeviation="10" />
    <feColorMatrix values="
      1 0 0 0 0
      0 1 0 0 0
      0 0 1 0 0
      0 0 0 20 -10" />
  </filter>
</svg>

<!-- Apply via CSS -->
.gooey-container {
  filter: url(#gooey);
}

<!-- Displacement map for wavy text -->
<filter id="wavy">
  <feTurbulence baseFrequency="0.02" numOctaves="3" />
  <feDisplacementMap in="SourceGraphic" scale="10" />
</filter>

Animações de Filtro

Filtros podem ser animados e transicionados suavemente. O efeito pulse-glow combina brightness e drop-shadow para um brilho neon. Grayscale-to-color no hover é uma interação clássica de galeria. Transições de filtro são aceleradas por GPU e performam melhor que animar box-shadow ou background-color. No entanto, animar blur ou filtros complexos pode ser caro — teste em mobile. O hue-rotate scroll-driven é um efeito divertido, mas pode causar problemas de performance em páginas longas; use will-change: filter para dar uma dica ao navegador para otimização.

css
@keyframes pulse-glow {
  0%, 100% {
    filter: brightness(1) drop-shadow(0 0 5px #3498db);
  }
  50% {
    filter: brightness(1.3) drop-shadow(0 0 20px #3498db);
  }
}

.glow-button {
  animation: pulse-glow 2s ease-in-out infinite;
}

/* Hover filter transition */
.gallery img {
  filter: grayscale(100%);
  transition: filter 0.3s ease;
}
.gallery img:hover {
  filter: grayscale(0%);
}

/* Color shift on scroll (with JS) */
window.addEventListener("scroll", () => {
  const hue = window.scrollY * 0.5;
  document.body.style.filter = `hue-rotate(${hue}deg)`;
});

mix-blend-mode & background-blend-mode

mix-blend-mode determina como os pixels de um elemento se misturam com o conteúdo atrás dele. multiply escurece (bom para sombras e marcas d'água); screen clareia (bom para brilhos); difference cria efeitos psicodélicos; overlay combina multiply e screen para contraste. background-blend-mode mistura múltiplas camadas de background (imagens e gradientes) no mesmo elemento. Blend modes são essenciais para composição criativa, efeitos duotone e sobreposições de texto sobre imagem. isolation: isolate cria um novo contexto de blending para conter efeitos de blend.

css
/* mix-blend-mode: how element blends with backdrop */
.overlay {
  mix-blend-mode: multiply; /* darken */
}
.overlay-screen {
  mix-blend-mode: screen; /* lighten */
}
.overlay-difference {
  mix-blend-mode: difference; /* invert */
}

/* Common blend modes: multiply, screen, overlay,
   darken, lighten, color-dodge, color-burn,
   hard-light, soft-light, difference, exclusion,
   hue, saturation, color, luminosity */

/* background-blend-mode: blend background layers */
.gradient-texture {
  background-image: url(texture.png),
                    linear-gradient(45deg, red, blue);
  background-blend-mode: multiply;
}
14

Container Queries

Básico de Container Query

Container queries permitem que componentes respondam ao tamanho do seu contêiner em vez do viewport. container-type: inline-size torna o elemento um query container com base em sua dimensão inline (largura). A regra @container aplica estilos quando o contêiner corresponde à condição. Isso é revolucionário para design baseado em componentes — um componente de card se adapta esteja em uma sidebar ou área principal de largura total, independentemente do tamanho da tela. Isso resolve a limitação fundamental das media queries, que respondem apenas ao tamanho do viewport.

css
/* Define a container */
.card-container {
  container-type: inline-size;
  /* or: container-type: size; (both dimensions) */
}

/* Query the container's size */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 2fr;
  }
}

@container (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

Contêineres Nomeados

Contêineres nomeados permitem visar contêineres específicos quando múltiplos estão aninhados. container-name dá um rótulo ao contêiner; @container name (condition) consulta apenas aquele contêiner. Isso evita conflitos quando componentes são aninhados com diferentes contextos de contêiner. O shorthand container combina nome e tipo: container: panel / inline-size. Contêineres nomeados são essenciais para layouts complexos onde múltiplas container queries independentes coexistem. Sem nomes, @container consulta o contêiner ancestral mais próximo.

css
/* Name a container for specific queries */
.sidebar {
  container-type: inline-size;
  container-name: sidebar;
}

.main-content {
  container-type: inline-size;
  container-name: main;
}

/* Query specific container by name */
@container sidebar (min-width: 300px) {
  .widget { display: grid; grid-template-columns: 1fr 1fr; }
}

@container main (min-width: 600px) {
  .article { columns: 2; }
}

/* Shorthand: container: name / type */
.panel {
  container: panel / inline-size;
}

Unidades de Container Query

Unidades de container query (cqw, cqh, cqmin, cqmax) são como unidades de viewport (vw, vh), mas relativas ao query container em vez do viewport. 1cqw = 1% da largura do contêiner. Isso habilita tipografia e espaçamento verdadeiramente responsivos ao componente — o texto escala com a largura do componente, não da tela. Combinado com clamp(), você obtém tipografia fluida que se adapta ao tamanho do contêiner com limites min/max. Isso é ideal para sistemas de design onde componentes devem funcionar em vários contextos de layout. Nota: cqh/cqmin/cqmax requerem container-type: size (ambas as dimensões).

css
.card {
  container-type: inline-size;
}

.card-title {
  /* cqw: 1% of container width */
  font-size: 5cqw;

  /* cqh: 1% of container height (needs size type) */
  padding: 2cqh;

  /* cqmin: 1% of smaller container dimension */
  margin: 2cqmin;

  /* cqmax: 1% of larger container dimension */
  border-radius: 1cqmax;
}

/* Fluid typography that responds to container */
.headline {
  font-size: clamp(1rem, 8cqw, 3rem);
}

Container Style Queries

Container style queries (experimental, apenas Chromium em 2025) permitem consultar valores de custom property em um contêiner, não apenas dimensões. Isso habilita renderização condicional baseada em estilo: um componente pode mudar de aparência com base em uma variável --theme definida em seu contêiner. container-type: style (ou nenhum container-type necessário para style queries) habilita isso. Isso é poderoso para theming — defina uma variável em um pai e todos os filhos se adaptam. O suporte total do navegador ainda está pendente; use com aprimoramento progressivo ou verificações @supports.

css
/* Query custom property values on container */
.card-wrapper {
  container-type: style;
  container-name: card;
}

@container card style(--theme: dark) {
  .card {
    background: #1a1a1a;
    color: #fff;
  }
}

@container card style(--theme: light) {
  .card {
    background: #fff;
    color: #333;
  }
}

/* Set the theme variable */
<div class="card-wrapper" style="--theme: dark">
  <div class="card">...</div>
</div>

Padrão de Componente Responsivo

Este padrão cria um componente verdadeiramente reutilizável que se adapta à sua colocação. O card de produto mostra um layout vertical em contêineres estreitos, horizontal em médios e um grid de 3 colunas em contêineres largos. O mesmo componente funciona em uma sidebar (estreito), grid (médio) ou hero (largo) sem qualquer lógica condicional baseada em props. Este é o caso de uso matador para container queries — componentes genuinamente independentes de contexto. Combinado com unidades de container query para tipografia, você obtém componentes totalmente autoadaptáveis.

css
/* Component that adapts to any container */
.product-card {
  container-type: inline-size;
  container-name: product;
}

.product-card .layout {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Medium container: horizontal layout */
@container product (min-width: 350px) {
  .product-card .layout {
    flex-direction: row;
  }
  .product-card .image {
    width: 40%;
  }
}

/* Large container: full feature layout */
@container product (min-width: 600px) {
  .product-card .layout {
    display: grid;
    grid-template-columns: 1fr 2fr 1fr;
  }
  .product-card .actions {
    display: flex;
    flex-direction: column;
  }
}
15

Scroll Snap & Animações Scroll-Driven

Básico de Scroll Snap

Scroll snap cria rolagem magnética que alinha elementos a pontos de snap. scroll-snap-type: x/y define o eixo; mandatory força o snapping (sempre pousa em um ponto); proximity faz snap apenas quando próximo. scroll-snap-align: start/center/end define onde o filho faz snap dentro do contêiner. Seções de rolagem de página inteira (como slides de apresentação) usam y mandatory com seções de 100vh. Carrosséis horizontais usam x mandatory. Sempre teste em dispositivos touch — snapping obrigatório pode parecer restritivo se o conteúdo for mais alto que o viewport. Use proximity para comportamento mais tolerante.

css
/* Container with scroll snapping */
.gallery {
  scroll-snap-type: x mandatory;
  overflow-x: auto;
  display: flex;
  gap: 1rem;
}

/* Children snap to positions */
.gallery section {
  scroll-snap-align: start;
  flex: 0 0 100%;
  height: 300px;
}

/* Vertical snapping */
.full-page {
  scroll-snap-type: y mandatory;
  height: 100vh;
  overflow-y: scroll;
}
.full-page section {
  scroll-snap-align: start;
  height: 100vh;
}

Scroll Snap com Padding

scroll-padding desloca pontos de snap da borda do contêiner — útil quando você tem cabeçalhos fixos ou quer margem ao redor de itens com snap. scroll-snap-stop: always impede rolagem rápida de pular múltiplos itens (força snapping um de cada vez). scroll-snap-align: center faz snap de itens ao centro do contêiner, criando um efeito cover-flow. Essas propriedades dão controle fino sobre o comportamento de snapping. Para carrosséis de imagens, combine com scroll-behavior: smooth para transições animadas entre snaps.

css
.carousel {
  scroll-snap-type: x mandatory;
  scroll-padding: 0 20px; /* offset snap points */
  overflow-x: auto;
  display: flex;
  gap: 1rem;
  padding: 0 20px;
}

.carousel .item {
  scroll-snap-align: start;
  scroll-snap-stop: always; /* don't skip items */
  flex: 0 0 80%;
}

/* Center-aligned snapping */
.carousel-center .item {
  scroll-snap-align: center;
  flex: 0 0 60%;
}

Animações Scroll-Driven (animation-timeline)

Animações scroll-driven (apenas CSS, sem JS!) vinculam animações à posição de rolagem. animation-timeline: scroll() vincula a animação ao progresso de rolagem da página (0% no topo, 100% na base). animation-timeline: view() vincula à entrada/saída do elemento no viewport. animation-range define quando a animação começa/termina relativo à rolagem (entry, exit, cover, contain). Isso habilita barras de progresso de rolagem, reveal-on-scroll e efeitos parallax sem JavaScript ou listeners de evento de rolagem. Suportado no Chrome 115+, aprimoramento progressivo recomendado para outros navegadores.

css
/* Animate as user scrolls */
@keyframes fade-in {
  from { opacity: 0; transform: translateY(50px); }
  to   { opacity: 1; transform: translateY(0); }
}

.reveal {
  animation: fade-in linear;
  animation-timeline: view();
  animation-range: entry 0% cover 40%;
}

/* Progress bar based on scroll position */
.progress-bar {
  position: fixed;
  top: 0; left: 0;
  height: 4px;
  background: #3498db;
  width: 100%;
  transform-origin: left;
  animation: grow linear;
  animation-timeline: scroll();
}

@keyframes grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

Intervalos de View Timeline

Intervalos de view timeline controlam exatamente quando a animação ocorre. 'entry' é quando o elemento entra no viewport; 'exit' quando sai; 'cover' vai do início da entrada ao fim da saída; 'contain' é quando o elemento está totalmente visível. Porcentagens refinam dentro de cada intervalo. animation-range: entry 10% entry 90% significa que a animação executa de 10% na entrada a 90% na entrada. Para cabeçalhos sticky, scroll() com um intervalo de pixel (0 200px) anima com base na distância absoluta de rolagem. Isso substitui handlers de rolagem JavaScript complexos por CSS declarativo.

css
/* Element animates as it enters viewport */
@keyframes slide-up {
  from { opacity: 0; transform: translateY(100px); }
  to   { opacity: 1; transform: translateY(0); }
}

.section {
  animation: slide-up linear both;
  animation-timeline: view();
  /* Ranges: entry, exit, cover, contain */
  animation-range: entry 10% entry 90%;
}

/* Sticky header that shrinks on scroll */
.header {
  position: sticky;
  top: 0;
  animation: shrink linear both;
  animation-timeline: scroll();
  animation-range: 0 200px;
}
@keyframes shrink {
  to { padding: 0.5rem 1rem; font-size: 0.9em; }
}

scroll-behavior & smooth scroll

scroll-behavior: smooth em html (ou qualquer contêiner de rolagem) faz a navegação por link âncora e scrollIntoView() animar suavemente em vez de pular. Isso é uma substituição de uma linha para bibliotecas JavaScript de smooth-scroll. Sempre respeite prefers-reduced-motion — alguns usuários sofrem de enjoo por movimento, então desabilite a rolagem suave para eles. O scroll-snap-type: proximity (vs mandatory) combina bem com rolagem suave para uma sensação natural. scrollIntoView com block: 'start'/'center'/'end' controla o alinhamento vertical do alvo.

css
/* Smooth scrolling for anchor links */
html {
  scroll-behavior: smooth;
}

/* With scroll snap */
html {
  scroll-behavior: smooth;
  scroll-snap-type: y proximity;
}

/* Target specific elements */
.container {
  scroll-behavior: smooth;
  overflow-y: auto;
}

/* JavaScript: scroll to element */
<script>
document.querySelector(".section-3")
  .scrollIntoView({ behavior: "smooth", block: "start" });

/* Scroll to top */
window.scrollTo({ top: 0, behavior: "smooth" });
</script>

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}
16

Contadores CSS

Contador Básico

Contadores CSS numeram elementos automaticamente sem JavaScript. counter-reset inicializa um contador (no pai ou qualquer ancestral). counter-increment o incrementa (geralmente no elemento sendo numerado). counter(name) exibe o valor atual em content. O contador trata a numeração automaticamente ao longo do documento. Isso é ideal para numerar títulos, itens de lista, figuras ou qualquer conteúdo sequencial. Contadores têm escopo no elemento onde são resetados e seus descendentes.

css
/* Initialize counter on parent */
body {
  counter-reset: section;
}

/* Increment and display */
h2::before {
  counter-increment: section;
  content: "Section " counter(section) ": ";
  color: #3498db;
  font-weight: bold;
}

/* Result: Section 1: Introduction, Section 2: Methods... */

Contadores Aninhados

Contadores aninhados criam numeração hierárquica (1.1, 1.2, 2.1, etc.). Reset o subcontador no título pai (counter-reset: section em h2). Cada h2 inicia um novo capítulo e reseta o contador de seção. Cada h3 incrementa o contador de seção dentro do capítulo atual. A propriedade content combina múltiplas chamadas counter() com separadores. Isso espelha como livros e documentos técnicos são numerados. Os contadores cascateiam naturalmente com base na estrutura do DOM e pontos de reset.

css
body {
  counter-reset: chapter;
}

h2 {
  counter-reset: section;
  counter-increment: chapter;
}
h2::before {
  content: "Chapter " counter(chapter) ". ";
}

h3 {
  counter-increment: section;
}
h3::before {
  content: counter(chapter) "." counter(section) " ";
}

/* Result: Chapter 1.  / 1.1 / 1.2 / Chapter 2. / 2.1 ... */

Estilos de Contador

counter() aceita um argumento de estilo: decimal (padrão), decimal-leading-zero (01, 02), lower/upper-alpha (a/b ou A/B), lower/upper-roman (i/ii ou I/II). @counter-style define estilos de contador personalizados com símbolos cíclicos, sistemas aditivos ou notação simbólica. O system: cyclic repete símbolos; system: additive cria sistemas do tipo numerais romanos. Estilos de contador personalizados são poderosos para listas internacionalizadas, marcadores personalizados ou numeração decorativa. O suporte do navegador para @counter-style é bom em navegadores modernos.

css
/* Different number styles */
ol {
  counter-reset: item;
  list-style: none;
}
li::before {
  counter-increment: item;
  /* decimal, decimal-leading-zero, lower-alpha,
     upper-alpha, lower-roman, upper-roman */
  content: counter(item, upper-roman) ". ";
}

/* Leading zeros: 01, 02, 03... */
li::before {
  content: counter(item, decimal-leading-zero) ". ";
}

/* Custom @counter-style */
@counter-style thumbs {
  system: cyclic;
  symbols: "👍" "👎";
  suffix: " ";
}
.thumbs-list { list-style-type: thumbs; }

Função counters() (Aninhada)

A função counters() (plural) retorna o caminho completo do contador como uma string, com níveis separados pelo delimitador especificado. Isso trata automaticamente escopos de contador aninhados — cada ol aninhado cria um novo escopo de contador. counters(nested, '.') produz 1, 1.1, 1.1.1 para listas profundamente aninhadas. Isso é diferente de counter() que mostra apenas o nível atual. Use counters() para numeração estilo outline de listas aninhadas, sumários ou menus hierárquicos. A string separadora pode ser qualquer caractere (. , - > etc.).

css
/* counters() creates full path string */
ol {
  counter-reset: nested;
  list-style: none;
}
li::before {
  counter-increment: nested;
  /* counters() returns all levels separated by a string */
  content: counters(nested, ".") " - ";
  font-weight: bold;
}

/* For nested <ol> elements:
   1 - Top level
   1.1 - Nested
   1.1.1 - Deeper
   2 - Top level again
*/

Contador para Figuras & Tabelas

Contadores são perfeitos para autonumerar figuras, tabelas e equações em documentação. Reset por capítulo (counter-reset em h2) para que a numeração reinicie a cada capítulo. O pseudo-elemento ::before em figcaption/caption prefixa o número. Isso garante numeração consistente e automática que atualiza quando o conteúdo é reordenado. Para referências cruzadas ('veja Figura 3'), contadores CSS não ajudam diretamente — você precisaria de JS ou âncoras HTML. Mas para numeração de exibição, esta é uma solução limpa e sem manutenção.

css
body {
  counter-reset: figure table;
}

figure figcaption::before {
  counter-increment: figure;
  content: "Figure " counter(figure) ": ";
  font-weight: bold;
  color: #2c3e50;
}

table caption::before {
  counter-increment: table;
  content: "Table " counter(table) ": ";
  font-weight: bold;
  color: #2c3e50;
}

/* Reset figure counter per chapter */
h2 {
  counter-reset: figure;
}
18

Modo Dark & Esquemas de Cor

prefers-color-scheme

prefers-color-scheme: dark detecta a preferência de modo dark do SO/navegador do usuário. Defina variáveis de tema em :root para modo light, depois sobrescreva-as na media query dark. Usar variáveis CSS significa que você apenas muda os valores das variáveis — todos os componentes se atualizam automaticamente. Esta é a abordagem padrão para modo dark. A media query também suporta 'light' e 'no-preference'. Teste alternando o modo dark do SO ou usando a aba Rendering do Chrome DevTools (Emulate CSS prefers-color-scheme).

css
/* Light mode (default) */
:root {
  --bg: #ffffff;
  --text: #1a1a1a;
  --surface: #f5f5f5;
  --border: #e0e0e0;
  --accent: #3498db;
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1a1a1a;
    --text: #e0e0e0;
    --surface: #2a2a2a;
    --border: #404040;
    --accent: #5dade2;
  }
}

body {
  background: var(--bg);
  color: var(--text);
}

Toggle de Tema Manual

Para toggle de tema manual, use um atributo data-theme em <html> que sobrescreve a preferência do sistema. Armazene a escolha do usuário em localStorage para persistir. No carregamento da página, verifique localStorage antes de renderizar para evitar flash de tema errado (FOUC). color-scheme: light dark diz ao navegador para renderizar elementos de UI nativos (scrollbars, controles de formulário) no esquema apropriado. Para melhor UX, use como padrão a preferência do sistema quando não existe escolha salva: verifique matchMedia('(prefers-color-scheme: dark)') como fallback.

css
/* Default to system preference, allow override */
:root {
  color-scheme: light dark;
}

/* Manual dark mode via data attribute */
[data-theme="dark"] {
  --bg: #1a1a1a;
  --text: #e0e0e0;
}

[data-theme="light"] {
  --bg: #ffffff;
  --text: #1a1a1a;
}

/* Toggle button */
<button onclick="toggleTheme()">Toggle Theme</button>
<script>
function toggleTheme() {
  const current = document.documentElement.dataset.theme;
  const next = current === "dark" ? "light" : "dark";
  document.documentElement.dataset.theme = next;
  localStorage.setItem("theme", next);
}
// Load saved preference
const saved = localStorage.getItem("theme");
if (saved) document.documentElement.dataset.theme = saved;
</script>

Propriedade color-scheme

A propriedade color-scheme diz ao navegador quais esquemas de cor a página suporta, afetando elementos de UI nativos: scrollbars, controles de formulário (inputs, buttons, dropdowns), cor de fundo/canvas padrão e a cor ::placeholder. Sem ela, controles de formulário podem aparecer light mesmo em modo dark (incompatibilidade desconfortável). Defina color-scheme: light dark em :root para deixar elementos nativos se adaptarem automaticamente. Isso é uma correção de uma linha que melhora drasticamente o polimento do modo dark. É separada do seu theming de variáveis CSS — afeta apenas a renderização nativa do navegador.

css
:root {
  /* Tell browser this page supports both schemes */
  color-scheme: light dark;
}

/* Force light only */
.light-only {
  color-scheme: light;
}

/* Force dark only */
.dark-only {
  color-scheme: dark;
}

/* This affects native UI: scrollbars, form controls,
   default colors (canvas, text), and form elements */
input, textarea, select {
  /* Will use dark form controls in dark mode */
  color-scheme: dark;
}

Imagens & Mídia em Modo Dark

Imagens precisam de tratamento especial em modo dark. Diagramas com fundo branco podem ser invertidos com filter: invert(1) hue-rotate(180deg) — o hue-rotate evita distorção de cor. Fotos de pessoas nunca devem ser invertidas. Reduza o brilho ligeiramente para menos fadiga visual. Para logos e ícones, use <picture> com fontes media-query para servir versões otimizadas para dark. SVGs com currentColor se adaptam automaticamente. Para imagens de fundo, forneça alternativas de modo dark via media queries. Sempre teste imagens em ambos os modos para legibilidade.

css
@media (prefers-color-scheme: dark) {
  /* Invert images that are essentially white-background */
  img[src*="logo"],
  img[src*="diagram"] {
    filter: invert(1) hue-rotate(180deg);
  }

  /* Reduce brightness of photos */
  img.photo {
    filter: brightness(0.85);
  }

  /* Don't invert photos with people */
  img[src*="photo"]:not(.invertable) {
    filter: none;
  }
}

/* Use dark-mode-friendly SVG */
<picture>
  <source srcset="logo-dark.svg"
          media="(prefers-color-scheme: dark)">
  <img src="logo-light.svg" alt="Logo">
</picture>

Transição Suave de Tema

Adicionar transições de cor a todos os elementos cria uma animação suave de troca de tema. No entanto, isso pode causar um flash de cores animadas no carregamento inicial da página. A solução: adicione uma classe .no-transition ao <html> durante trocas de tema e no carregamento inicial, depois remova-a após um quadro. Sempre respeite prefers-reduced-motion para desabilitar transições para usuários que solicitam movimento reduzido. Seja seletivo — transitar todas as propriedades pode impactar a performance. Transite apenas propriedades relacionadas a cor (background-color, color, border-color, box-shadow).

css
/* Transition colors when theme changes */
* {
  transition: background-color 0.3s ease,
              color 0.3s ease,
              border-color 0.3s ease;
}

/* But not during initial load (prevent flash) */
.no-transition * {
  transition: none !important;
}

<script>
// Disable transitions during theme switch
function toggleTheme() {
  document.documentElement.classList.add("no-transition");
  document.documentElement.dataset.theme = newTheme;
  // Re-enable after switch
  requestAnimationFrame(() => {
    document.documentElement.classList.remove("no-transition");
  });
}
</script>

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
19

Aprofundamento em Funções CSS

clamp(), min(), max()

clamp(min, preferred, max) é o santo graal da tipografia e espaçamento fluidos — escala com o valor preferred, mas nunca excede os limites min/max. min() pega o menor valor (ótimo para max-width responsivo). max() pega o maior valor (ótimo para tamanhos mínimos). Estas eliminam muitas media queries fornecendo escala fluida contínua. O valor preferred em clamp normalmente usa unidades de viewport (vw, vh) ou unidades de contêiner (cqw). Esta é a abordagem moderna para design responsivo sem breakpoints.

css
/* clamp(min, preferred, max) */
h1 {
  font-size: clamp(1.5rem, 5vw, 3rem);
  /* Never smaller than 1.5rem, never larger than 3rem,
     preferred is 5vw */
}

/* min(): use the smaller value */
.container {
  width: min(100% - 2rem, 1200px);
  /* Full width minus padding, but max 1200px */
}

/* max(): use the larger value */
.hero {
  font-size: max(2rem, 4vw);
  /* At least 2rem, grows with viewport */
}

/* Combining for responsive padding */
.card {
  padding: clamp(1rem, 3vw, 2rem);
}

calc() Avançado

calc() realiza cálculos com unidades mistas (px, %, em, vw, etc.). Adição e subtração exigem espaços ao redor do operador (calc(100% - 20px), não calc(100%-20px)). Multiplicação e divisão funcionam apenas com números, não comprimentos (calc(10px * 2) é válido; calc(10px * 10px) não é). calc() pode ser aninhado, mas parênteses também funcionam. Combinado com variáveis CSS, calc() habilita sistemas de design dinâmicos e computados. É essencial para layouts responsivos que combinam dimensões fixas e fluidas.

css
/* Mixed units */
.sidebar {
  width: calc(100% - 250px); /* full width minus fixed sidebar */
  height: calc(100vh - 60px); /* viewport minus header */
}

/* Nested calc */
.element {
  margin: calc(calc(100% - 50px) / 2);
  /* Simplified: */
  margin: calc((100% - 50px) / 2);
}

/* With CSS variables */
:root { --gap: 20px; }
.grid {
  gap: calc(var(--gap) * 2);
}

/* Math operations: + - * / */
.padding {
  padding: calc(1rem + 2px);
  width: calc(50% - 10px);
}

Função attr()

attr() recupera valores de atributos HTML, mais comumente usado em content para pseudo-elementos. É a base de tooltips apenas com CSS (atributo data-tooltip → ::after content). attr() funciona de forma confiável apenas na propriedade content. Usar attr() para outras propriedades (width, color, etc.) com type casting (attr(data-size px)) faz parte do CSS Values Level 5, mas tem suporte mínimo de navegador. Por enquanto, use variáveis CSS para valores dinâmicos do HTML: defina style='--size: 100px' e use var(--size).

css
/* Display attribute values */
a[href]::after {
  content: attr(href);
}

/* data attributes for tooltips */
.tooltip::after {
  content: attr(data-tooltip);
  display: none;
  position: absolute;
}
.tooltip:hover::after {
  display: block;
}

/* HTML: <div class="tooltip" data-tooltip="Help text">?</div> */

/* Note: attr() for non-content properties is experimental */
/* This doesn't work widely yet: */
/* .box { width: attr(data-width px); } */

var() com Fallbacks

var() aceita um fallback como segundo argumento, usado quando a variável não está definida. Fallbacks podem encadear: var(--a, var(--b, var(--c, default))). Isso habilita aprimoramento progressivo e theming multinível. Um valor de variável vazio (--defined: ;) ainda é 'definido', então o fallback não dispara — isso habilita padrões CSS condicionais. Fallbacks podem incluir qualquer valor CSS válido, incluindo calc() e outras funções. Use fallbacks para variáveis de tema opcionais que podem não estar definidas em todos os contextos.

css
/* Single fallback */
color: var(--text-color, #333);

/* Chained fallbacks */
color: var(--text, var(--default-text, black));

/* Fallback in shorthand */
background: var(--bg, white) url(image.png);

/* Fallback with calc */
width: calc(100% - var(--sidebar, 250px));

/* Check if variable is set */
:root {
  --defined: ; /* empty space = valid value */
}
.conditional {
  --use-default: var(--defined, initial);
  /* If --defined is empty, --use-default = initial */
}

Funções gradient

Gradientes CSS criam transições suaves entre cores sem imagens. linear-gradient (direção + cores), radial-gradient (do centro para fora) e conic-gradient (rotacionando ao redor de um ponto) são os três tipos. Hard stops (mesma porcentagem para duas cores) criam faixas nítidas. repeating-linear-gradient cria padrões como listras. Gradientes podem ser camadas com múltiplos backgrounds (separados por vírgula, primeiro = camada superior). Gradientes cônico habilitam gráficos de pizza e rodas de cor em CSS puro. Gradientes são independentes de resolução e performam melhor que arquivos de imagem.

css
/* Linear gradient */
.bg { background: linear-gradient(45deg, #3498db, #e74c3c); }
.bg2 { background: linear-gradient(to right, red, orange, yellow); }

/* Radial gradient */
.radial { background: radial-gradient(circle, white, blue); }
.radial2 { background: radial-gradient(circle at top left, #fff, #000); }

/* Conic gradient */
.pie { background: conic-gradient(red 0% 30%, blue 30% 70%, green 70% 100%); }

/* Repeating gradients */
.stripes { background: repeating-linear-gradient(45deg, #ccc 0 10px, #fff 10px 20px); }

/* Hard color stops (sharp edges) */
.hard { background: linear-gradient(to right, #000 50%, #fff 50%); }

/* Multiple backgrounds */
.multi {
  background:
    linear-gradient(rgba(0,0,0,0.5), transparent),
    url(photo.jpg);
}
20

Variáveis CSS

Definindo & Usando Variáveis

CSS custom properties (variáveis) são definidas com --name e usadas com var(). Declare-as em :root para acesso global. Diferente das variáveis Sass, elas são live — alterar uma variável via JavaScript atualiza instantaneamente todo elemento que a usa.

css
:root {
  --primary: #3498db;
  --spacing: 16px;
  --radius: 8px;
}

.button {
  background: var(--primary);
  padding: var(--spacing);
  border-radius: var(--radius);
}

Valores de Fallback

var() aceita um segundo argumento como fallback quando a variável é indefinida. Fallbacks podem aninhar, permitindo encadear padrões. Para navegadores que não suportam custom properties, declare um valor normal primeiro, depois sobrescreva com var().

css
.box {
  color: var(--brand, #333);
  background: var(--bg, var(--default-bg, white));
}

/* Provide fallback for older browsers */
.element {
  color: #333;
  color: var(--text-color, #333);
}

Interação com JavaScript

JavaScript lê variáveis via getComputedStyle().getPropertyValue() e as define com setProperty(). Isso torna o theming em runtime trivial — alterne algumas variáveis para reestilizar todo o app.

css
// Read a variable
const color = getComputedStyle(document.documentElement)
  .getPropertyValue('--primary');

// Set a variable on an element
document.documentElement.style.setProperty('--primary', '#e74c3c');

// Toggle a theme
document.documentElement.setAttribute('data-theme', 'dark');

Escopo & Herança

Custom properties herdam, então uma variável definida em :root cascateia para todo elemento. Redefini-la em .card a sobrescreve apenas para aquela subárvore. Esse escopo habilita theming em nível de componente sem guerras de especificidade.

css
:root { --size: 16px; }

.card {
  --size: 20px; /* Overrides only within .card */
  font-size: var(--size);
}

.card .text { font-size: var(--size); } /* 20px */
.other { font-size: var(--size); }       /* 16px */

Variáveis Responsivas

Redefina variáveis dentro de media queries para fazer todo o layout responder a breakpoints sem reescrever regras. Altere uma variável e todo elemento que a usa se adapta — muito mais limpo que sobrescrever cada propriedade individualmente.

css
:root {
  --container-width: 1200px;
  --font-size: 18px;
}

@media (max-width: 768px) {
  :root {
    --container-width: 100%;
    --font-size: 16px;
  }
}

.container { max-width: var(--container-width); }
body { font-size: var(--font-size); }
21

Animações & Keyframes

@keyframes & Shorthand Animation

@keyframes define os estados de início (from/0%) e fim (to/100%) de uma animação. O shorthand animation combina name, duration, timing-function, delay, iteration-count, direction, fill-mode e play-state. forwards mantém o estado final.

css
@keyframes slide-in {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}

.element {
  animation: slide-in 0.5s ease-out forwards;
}

/* Shorthand: name duration timing delay count direction fill-mode */
.bounce {
  animation: bounce 1s cubic-bezier(0.68, -0.55, 0.27, 1.55) 0s infinite alternate;
}

Transições

Transições interpolam suavemente entre valores de propriedade quando eles mudam. Especifique quais propriedades transitam e sua duração/timing. transition: all é conveniente, mas pode prejudicar a performance — prefira listar propriedades específicas.

css
.button {
  background: blue;
  transition: background 0.3s ease, transform 0.2s ease-out;
}

.button:hover {
  background: darkblue;
  transform: scale(1.05);
}

/* Transition all changed properties */
.card { transition: all 0.3s ease; }

Funções de Timing

Funções de timing controlam a curva de aceleração. ease-out começa rápido e desacelera (bom para entradas); ease-in começa lento e acelera (bom para saídas). cubic-bezier permite criar curvas personalizadas. steps() cria um efeito discreto.

css
/* Built-in */
.ease-linear { transition: all 1s linear; }
.ease-out    { transition: all 1s ease-out; }

/* Custom cubic-bezier(x1, y1, x2, y2) */
.custom { transition: all 1s cubic-bezier(0.68, -0.55, 0.27, 1.55); }

/* Steps */
.steps { transition: all 1s steps(5, end); }

Eventos de Animação

JavaScript pode escutar animationstart, animationiteration (dispara a cada loop) e animationend. Controle a reprodução com a propriedade animation-play-state (paused/running). Combine com animationend para encadear animações.

css
const el = document.querySelector('.animate');
el.addEventListener('animationstart', () => console.log('Started'));
el.addEventListener('animationiteration', () => console.log('Looped'));
el.addEventListener('animationend', () => console.log('Finished'));

// Pause and resume
el.style.animationPlayState = 'paused';
el.style.animationPlayState = 'running';

Performance: transform & opacity

Anime apenas transform e opacity para performance de 60fps — eles executam na GPU sem disparar layout. Animar width, height, top ou margin força recálculo de layout a cada quadro. Use will-change com moderação para dar dicas ao navegador.

css
/* GOOD: GPU-accelerated, cheap */
.fade { transition: opacity 0.3s; }
.move { transition: transform 0.3s; }

/* BAD: triggers layout/paint, expensive */
.resize { transition: width 0.3s, height 0.3s; }

/* Hint the browser to optimize */
.card { will-change: transform; }
22

Transforms 3D

Transforms 2D

Transforms 2D movem, rotacionam, escalam e inclinam elementos sem afetar o layout ao redor. Transforms são compostos na GPU, tornando-os performáticos para animação. A ordem importa: rotate então translate move ao longo do eixo rotacionado.

css
.box { transform: translate(50px, 20px); }
.box { transform: rotate(45deg); }
.box { transform: scale(1.5); }
.box { transform: skew(20deg, 10deg); }

/* Combined — order matters */
.combo { transform: translate(100px, 0) rotate(90deg) scale(1.2); }

Transforms 3D & Perspective

Transforms 3D adicionam rotateX, rotateY, rotateZ, translateZ e scaleZ. perspective em um pai dá a todos os filhos um ponto de fuga compartilhado — valores menores exaggeram o efeito 3D. transform-style: preserve-3d mantém elementos aninhados em 3D.

css
.scene { perspective: 1000px; }

.card {
  transform: rotateY(45deg);
  transform-style: preserve-3d;
}

/* Perspective on the element itself */
.self { transform: perspective(800px) rotateX(30deg); }

/* Transform origin */
.pivot { transform-origin: top left; transform: rotate(45deg); }

Efeito Flip Card

O flip card clássico usa preserve-3d em um contêiner, com faces front e back posicionadas absolutamente. backface-visibility: hidden oculta o verso de cada face. A face back é pré-rotacionada 180deg para que apareça quando o contêiner vira.

css
.card { perspective: 1000px; }
.inner {
  position: relative;
  transform-style: preserve-3d;
  transition: transform 0.6s;
}
.card:hover .inner { transform: rotateY(180deg); }
.front, .back {
  position: absolute;
  backface-visibility: hidden;
}
.back { transform: rotateY(180deg); }

Cubo com 6 Faces

Um cubo 3D é construído a partir de seis faces, cada uma transladada 50px (metade da largura do cubo) para fora ao longo de seu eixo. preserve-3d mantém as faces posicionadas no espaço 3D. Anime o transform do cubo para girá-lo.

css
.cube {
  position: relative;
  width: 100px; height: 100px;
  transform-style: preserve-3d;
  transform: rotateX(-20deg) rotateY(30deg);
}
.face { position: absolute; width: 100px; height: 100px; }
.front  { transform: translateZ(50px); }
.back   { transform: rotateY(180deg) translateZ(50px); }
.right  { transform: rotateY(90deg) translateZ(50px); }
.left   { transform: rotateY(-90deg) translateZ(50px); }
.top    { transform: rotateX(90deg) translateZ(50px); }
.bottom { transform: rotateX(-90deg) translateZ(50px); }

Matrix & Performance

matrix() e matrix3d() expressam qualquer transform como uma única matriz — útil ao computar transforms em JavaScript. translateZ(0) ou will-change: transform forçam aceleração de GPU, melhorando a suavidade da animação. Evite uso excessivo de camadas.

css
/* matrix(a, b, c, d, e, f) encodes translate, rotate, scale, skew */
.transformed { transform: matrix(1, 0, 0, 1, 100, 50); }

/* 3D matrix */
.cube { transform: matrix3d(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1); }

/* Hardware acceleration hint */
.gpu { transform: translateZ(0); }
23

CSS Grid Avançado

Áreas de Template Grid

grid-template-areas nomeia células do grid visualmente, tornando a intenção do layout óbvia. Cada linha entre aspas representa uma linha do grid; nomes idênticos ocupam células. Células vazias usam um ponto (.). As áreas devem formar retângulos — formas em L são inválidas.

css
.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  gap: 16px;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main   { grid-area: main; }
.footer { grid-area: footer; }

minmax & auto-fit

repeat(auto-fit, minmax(200px, 1fr)) cria um grid responsivo sem media queries: colunas têm pelo menos 200px e se esticam para preencher a linha. auto-fit colapsa trilhas vazias; auto-fill as mantém reservadas.

css
.grid {
  display: grid;
  /* Columns auto-fit, each at least 200px, sharing leftover space */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
}

/* Fixed number that wraps */
.wrap {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

Alinhamento Grid

O alinhamento do grid funciona em dois níveis: o contêiner (justify/align-items e justify/align-content) e o item (justify/align-self). justify-* controla o eixo inline, align-* o eixo block. place-items: center é shorthand para ambos.

css
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  align-items: center;
  justify-content: space-between;
  align-content: center;
}

.item {
  justify-self: end;
  align-self: start;
}

Span & Posicionamento por Linha

Posicione itens por número de linha grid (1 / 3 significa da linha 1 à linha 3) ou por span (span 2). Linhas negativas contam a partir do fim (-1 é a última linha). grid-column: 1 / -1 faz um item ocupar toda a largura.

css
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.header { grid-column: 1 / -1; }       /* full width */
.sidebar { grid-column: 1 / 3; }       /* columns 1-2 */
.main { grid-column: span 2; }          /* span 2 columns */
.tall { grid-row: 1 / span 2; }         /* span 2 rows */

Subgrid

subgrid permite que um grid filho herde as definições de trilha do pai, então colunas ou linhas se alinham perfeitamente em grids aninhados. Sem subgrid, grids aninhados definem suas próprias trilhas e podem desalinhar. Suportado em todos os navegadores modernos desde 2023.

css
.card {
  display: grid;
  grid-template-rows: auto 1fr auto;
  /* Inherit column tracks from parent */
  grid-template-columns: subgrid;
  grid-column: span 3;
}

.parent {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}
24

Funções CSS

calc()

calc() realiza matemática em unidades mistas (px, %, vw, em, rem). Sempre cerque + e - com espaços (calc(100%-20px) falha; calc(100% - 20px) funciona). Multiplicação e divisão exigem que um lado seja um número sem unidade.

css
.sidebar {
  width: calc(100% - 250px);
  padding: calc(16px + 2vw);
  font-size: calc(14px + 0.5vw);
}

/* Nested calc */
.full { width: calc(calc(100% - 20px) / 2); }

/* With variables */
.box { margin: calc(var(--gap) * 2); }

clamp()

clamp() limita um valor entre um mínimo e um máximo, com um valor preferred no meio. É a maneira mais limpa de construir tipografia e espaçamento fluidos — o valor escala, mas nunca fica abaixo ou acima dos limites.

css
/* clamp(MIN, PREFERRED, MAX) */
h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}

.sidebar {
  width: clamp(200px, 25vw, 400px);
}

.padding {
  padding: clamp(1rem, 2vw + 1rem, 2rem);
}

min() & max()

min() retorna o menor argumento; max() retorna o maior. Diferente de clamp (que aceita exatamente três valores), min/max aceitam qualquer número de argumentos. Use min() para limitar um valor e max() para pisoar um valor.

css
/* Picks the smallest/largest of comma-separated values */
.box {
  width: min(100% - 32px, 800px);
  font-size: max(16px, 2vw);
}

/* With multiple units */
.responsive {
  padding: min(5vw, 2rem);
  margin: max(1rem, 3vw);
}

var() com Fallbacks

O segundo argumento de var() é usado apenas quando a custom property é indefinida. Para valores inválidos, a propriedade volta ao seu valor herdado ou inicial. Aninhe chamadas var() para encadear fallbacks.

css
.button {
  background: var(--btn-bg, #007bff);
  color: var(--text, var(--default-text, black));
  width: var(--width, 100%);
}

color-mix() & funções de cor

color-mix() mistura duas cores em um espaço de cor especificado (srgb, oklch, lab). É a maneira moderna de derivar tints e shades de uma cor de marca. A sintaxe de cor relativa (from keyword) permite ajustar canais individuais.

css
/* Mix two colors */
.muted { color: color-mix(in srgb, red 30%, blue); }

/* Adjust relative lightness */
.lighter { background: color-mix(in oklch, var(--brand) 70%, white); }
.darker  { background: color-mix(in oklch, var(--brand) 70%, black); }

/* Relative color syntax (newest) */
.tint { background: oklch(from var(--brand) calc(l + 0.1) c h); }
25

Animações Scroll-Driven

Básico de animation-timeline

animation-timeline: scroll(root) vincula uma animação à posição de rolagem da página — conforme o usuário rola, a animação progride. Sem JavaScript necessário. Isso é muito mais suave que listeners de evento de rolagem.

css
@keyframes grow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

.progress-bar {
  animation: grow linear;
  animation-timeline: scroll(root);
  transform-origin: left;
}

Timeline view()

view() cria uma timeline vinculada a um elemento entrando e saindo do viewport. animation-range controla qual parte da entrada dispara a animação. Perfeito para efeitos scroll-reveal sem IntersectionObserver.

css
@keyframes reveal {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0); }
}

.card {
  animation: reveal linear;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

Barra de Progresso Vinculada à Rolagem

Uma barra de progresso fixa que preenche conforme você rola a página. animation-timeline: scroll(root) mapeia a rolagem da página para o intervalo de animação 0-100%. transform-origin: 0 50% faz a barra crescer a partir da esquerda.

css
body { min-height: 200vh; }
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 4px;
  width: 100%;
  background: linear-gradient(to right, #6366f1, #ec4899);
  transform-origin: 0 50%;
  animation: scale-x linear;
  animation-timeline: scroll(root);
}
@keyframes scale-x {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

Scroll Timelines Nomeados

Quando você precisa vincular uma animação a um elemento rolável específico (não o root), defina scroll-timeline-name no contêiner e referencie-o em animation-timeline. scroll-timeline-axis escolhe qual eixo rastrear (block/inline/x/y).

css
.scroll-container {
  scroll-timeline-name: --cards;
  scroll-timeline-axis: block;
  overflow-y: scroll;
  height: 400px;
}

.card {
  animation: fade-in linear;
  animation-timeline: --cards;
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

Ajustes de Intervalo de View

animation-range refinamente quando a animação executa relativo à visibilidade do elemento. cover 0% a cover 100% vai de quando o elemento entra até sair totalmente. contain 0% a 100% vai apenas quando está totalmente dentro.

css
.image {
  animation: parallax linear;
  animation-timeline: view();
  animation-range: cover 0% cover 100%;
}

@keyframes parallax {
  from { transform: translateY(-20%); }
  to   { transform: translateY(20%); }
}

/* Only animate while in view */
.pulse {
  animation: pulse 1s infinite;
  animation-timeline: view();
  animation-range: contain 0% contain 100%;
}
26

CSS Layers

Definindo @layer

@layer agrupa estilos em camadas de cascata nomeadas. A ordem na linha de declaração define prioridade: camadas posteriores vencem as anteriores, independentemente da especificidade do seletor. Isso traz ordenação previsível para grandes stylesheets.

css
@layer reset, base, components, utilities;

@layer reset {
  * { margin: 0; padding: 0; box-sizing: border-box; }
}

@layer base {
  body { font-family: sans-serif; line-height: 1.6; }
}

@layer utilities {
  .hidden { display: none !important; }
}

Prioridade de Layer

Dentro de layers, aplicam-se regras normais de especificidade. Mas entre layers, as posteriores sempre vencem — uma única classe em components vence um ID em base. Estilos não layerizados têm prioridade sobre todos os estilos layerizados.

css
@layer base, components;

@layer base {
  /* Even though this is more specific, base loses */
  div.button { color: black; }
}

@layer components {
  .button { color: blue; } /* This wins */
}

/* Unlayered styles always beat layered styles */
.button { color: red; }

Importando para Layers

@import ... layer(name) coloca uma stylesheet inteira em uma layer nomeada. Isso é essencial para domar CSS de terceiros: coloque Bootstrap em uma layer vendor, e seus estilos personalizados (em uma layer posterior ou não layerizada) sempre vencerão.

css
@import url("reset.css") layer(reset);
@import url("bootstrap.css") layer(vendor);

@layer reset, vendor, custom;

@layer custom {
  .btn { background: hotpink; }
}

Layers Aninhadas

Layers podem aninhar, criando uma hierarquia. framework.theme refere-se à sublayer theme dentro de framework. Layers aninhadas seguem as mesmas regras de prioridade: dentro de framework, theme vence base.

css
@layer framework {
  @layer base, theme;

  @layer base {
    .btn { padding: 8px; }
  }
  @layer theme {
    .btn { color: navy; }
  }
}

/* Reference nested layer */
@layer framework.theme {
  .btn { color: hotpink; }
}

Lógica Condicional de Layer

Blocos @layer podem aninhar dentro de @media e @supports, então a associação de layer se adapta a condições. Isso mantém estilos específicos de recurso organizados dentro de sua layer em vez de vazar para espaço não layerizado.

css
@layer base, components;

@media (max-width: 600px) {
  @layer components {
    .nav { flex-direction: column; }
  }
}

@supports (display: grid) {
  @layer components {
    .layout { display: grid; }
  }
}
27

Backdrop Filters

Básico de backdrop-filter

backdrop-filter aplica um filtro ao conteúdo atrás de um elemento, criando efeitos de vidro fosco. Sempre inclua o prefixo -webkit- para Safari. Combine com um background semitransparente para que o blur seja visível.

css
.glass {
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 12px;
}

Múltiplos Filtros

Encadeie múltiplos filtros separados por espaço: blur, brightness, contrast, grayscale, hue-rotate, invert, opacity, saturate, sepia. Cada um se aplica ao backdrop. Combine com um background tingido para direcionar o clima.

css
.vibrant {
  backdrop-filter: blur(8px) saturate(180%) brightness(1.1);
}

.dark-glass {
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(12px) grayscale(50%);
}

Blend Modes

mix-blend-mode controla como um elemento se mistura com o conteúdo abaixo dele (separado do backdrop-filter). multiply escurece, screen clareia, difference inverte. Tenha cuidado com a legibilidade do texto.

css
.overlay {
  background: rgba(255, 0, 100, 0.3);
  backdrop-filter: blur(4px);
  mix-blend-mode: multiply;
}

.difference {
  background: white;
  mix-blend-mode: difference;
  backdrop-filter: invert(1);
}

Performance & Fallbacks

backdrop-filter é intensivo em GPU, especialmente com grandes raios de blur. Forneça um fallback de background sólido para navegadores sem suporte, depois aprimore com @supports. Evite animar backdrop-filter — pode causar jank severo.

css
/* Fallback for unsupported browsers */
.glass {
  background: rgba(255, 255, 255, 0.9);
}

/* Progressive enhancement */
@supports (backdrop-filter: blur(10px)) {
  .glass {
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(10px);
  }
}

Card Glassmorphism

Um card glassmorphism clássico combina um background translúcido, blur de backdrop, uma borda de luz sutil (simulando reflexo de borda) e uma sombra suave. O filtro saturate aumenta as cores vistas através do vidro.

css
.card {
  background: rgba(255, 255, 255, 0.15);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  padding: 24px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

Was this helpful?

Learning path

Learn from scratch

Learn this language from the ground up with structured lessons.