Herança no CSS: o que o filho recebe do pai sem pedir
Quais propriedades atravessam a árvore sozinhas, quais não, e o que inherit, initial e unset fazem quando você precisa forçar a mão.
Herança no CSS é o mecanismo que faz um elemento usar o valor do pai quando
ninguém declarou nada para ele. Ela não vale para todas as propriedades: color
desce, border não. E ela é a última coisa que o navegador consulta — se
existir qualquer declaração para aquele elemento, a herança nem entra na
conversa.
Os exemplos deste artigo são o site de uma clínica veterinária, a Pet Girassol: ficha do paciente, agenda do dia, cartão de atendimento. Todas as saídas coladas aqui saíram de um Chrome for Testing 151.0.7922.34 dirigido por Playwright, num MacBook com M4 Pro.
Herança é o plano B, não uma regra fraca
O erro de modelo mental mais comum é imaginar a herança como uma regra de peso zero, que entra na disputa e perde para qualquer seletor. Não é isso. A especificidade só compara declarações que existem. A herança acontece depois que essa comparação terminou, e só quando ela terminou de mãos vazias.
A sequência, para uma propriedade e um elemento:
- o navegador junta todas as declarações daquela propriedade que casam com o elemento — as suas, as da folha do próprio navegador, as do usuário;
- a cascata escolhe uma vencedora;
- se não houver nenhuma, e só nesse caso, o navegador pergunta se a propriedade é herdada. Se for, copia o valor do pai. Se não for, usa o valor inicial da propriedade.
Guardar essa ordem resolve sozinha metade dos “por que isso não pegou” do dia a dia. Vamos ver os dois lados na ficha do paciente.
A ficha da clínica: o que desceu e o que ficou para trás
Um único bloco de CSS, aplicado só no container:
<style>
.ficha {
color: #14532d;
font-family: Georgia, serif;
font-size: 18px;
line-height: 1.6;
border: 2px solid #14532d;
}
</style>
<section class="ficha">
<h2 id="h2">Mel — Golden Retriever</h2>
<p id="p">Retorno da vacina antirrábica em 12/09.</p>
<a id="a" href="/prontuario">Ver prontuário</a>
<button id="button">Confirmar consulta</button>
<input id="input" value="Tutor: Ana Souza">
</section>Nenhum dos cinco filhos tem uma linha de CSS própria. Lendo o estilo calculado de cada um:
const props = ['color', 'font-family', 'font-size', 'line-height', 'border-top-width'];
const ids = ['h2', 'p', 'a', 'button', 'input'];
const linha = (el) => {
const cs = getComputedStyle(el);
return props.map((p) => cs.getPropertyValue(p));
};
const tabela = [
['elemento', ...props],
['.ficha (pai)', ...linha(document.querySelector('.ficha'))],
...ids.map((id) => [' ' + id, ...linha(document.getElementById(id))]),
];
const larguras = tabela[0].map((_, i) => Math.max(...tabela.map((l) => l[i].length)) + 2);
for (const l of tabela) console.log(l.map((c, i) => c.padEnd(larguras[i])).join('').trimEnd());Cinco leituras dessa tabela:
bordernão desceu para ninguém. O pai tem2px, os filhos têm0px. Borda não é propriedade herdada — se fosse, cada parágrafo dentro de um cartão com borda ganharia a própria moldura.font-familyeline-heightdesceram para os três primeiros filhos. Oh2, ope oaestão todos em Georgia, sem que ninguém tenha escrito isso para eles.- A
colordesceu para dois deles, e o link ficou azul. Guarde isso, é a próxima seção. buttoneinputignoraram tudo. Não é que controles de formulário sejam imunes à herança: é que a folha do navegador declarafontecolorneles. Havendo declaração, não há herança.- O
h2ficou com27pxsem ninguém pedir. A folha do navegador dizh2 { font-size: 1.5em }, e dentro defont-sizeoemse resolve contra ofont-sizedo pai, nunca contra o do próprio elemento. O pai aqui é o.ficha, com18px. Herança e unidade relativa trabalham juntas: 18 × 1.5 = 27.
Contei quantas propriedades herdam de verdade
Toda lista de “propriedades herdadas” que circula por aí é copiada de outra
lista. Preferi medir. O script abaixo pega o catálogo de propriedades do
mdn-data, e para cada uma tenta um valor no pai e verifica se o filho passou a
computar o mesmo valor:
import { chromium } from 'playwright-core';
import props from 'mdn-data/css/properties.json' with { type: 'json' };
const CHROME = process.env.HOME + '/Library/Caches/ms-playwright/chromium-1234/' +
'chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing';
const lista = Object.entries(props)
.filter(([nome, d]) => d.status === 'standard' && !nome.startsWith('-'))
.map(([nome, d]) => ({ nome, mdn: d.inherited === true }));
const browser = await chromium.launch({ executablePath: CHROME });
const page = await browser.newPage();
await page.setContent(`
<div id="pai"><div id="filho">texto</div></div>
<div><div id="controle">texto</div></div>
`);
const medir = (solto) => page.evaluate(({ lista, solto }) => {
// um valor plausível para cada família de propriedade
const candidatos = ['3px', '3', '30%', 'rgb(1, 2, 3)', 'hidden', 'collapse',
'italic', 'bold', 'uppercase', 'serif', '"X"', '0.5', '17deg', '1.7s',
'ease-in', 'thick', 'square', 'crosshair', 'vertical-rl', 'break-all',
'pre', 'nowrap', 'ellipsis', 'both', 'center', 'flex', 'none', 'auto',
'scaleX(2)', 'blur(3px)', 'url("a.png")', 'always', 'dark', 'sideways',
'under', 'wavy', 'balance', 'anywhere', 'contents', 'invert', 'reverse',
'slice', 'space', 'round', 'stretch', 'each-line'];
// estas mudam a caixa de todo mundo e envenenariam a medição
const pular = new Set(['all', 'display', 'position', 'contain', 'content',
'content-visibility', 'container', 'container-name', 'container-type']);
const pai = document.getElementById('pai');
const filho = document.getElementById('filho');
const controle = document.getElementById('controle');
for (const el of [filho, controle]) el.style.position = solto ? 'absolute' : 'static';
const cp = getComputedStyle(pai);
const cf = getComputedStyle(filho);
const cc = getComputedStyle(controle);
const herdam = [], naoHerdam = [], semMedida = [];
for (const item of lista) {
if (pular.has(item.nome)) { semMedida.push(item.nome); continue; }
const base = cc.getPropertyValue(item.nome); // valor de fábrica, num pai intocado
if (base === '') { semMedida.push(item.nome); continue; }
let usado = null; // acha um valor que o Chrome aceite
for (const valor of candidatos) {
pai.style.setProperty(item.nome, valor);
if (cp.getPropertyValue(item.nome) !== base) { usado = valor; break; }
pai.style.removeProperty(item.nome);
}
if (usado === null) { semMedida.push(item.nome); continue; }
const desceu = cf.getPropertyValue(item.nome) === cp.getPropertyValue(item.nome)
&& cf.getPropertyValue(item.nome) !== base;
(desceu ? herdam : naoHerdam).push(item);
pai.style.removeProperty(item.nome);
}
return { herdam, naoHerdam, semMedida };
}, { lista, solto });
const fluxo = await medir(false); // filho no fluxo normal
const solta = await medir(true); // filho em position: absolute
// só vale como herança o que desceu nas duas rodadas
const noAbsoluto = new Set(solta.herdam.map((x) => x.nome));
const confirmadas = fluxo.herdam.filter((x) => noAbsoluto.has(x.nome));
const layout = fluxo.herdam.filter((x) => !noAbsoluto.has(x.nome)).map((x) => x.nome);
const nomes = (arr) => arr.map((x) => x.nome).join(', ') || '(nenhuma)';
console.log('propriedades padronizadas na lista .......', lista.length);
console.log('mediveis (o Chrome respondeu a um valor) .', fluxo.herdam.length + fluxo.naoHerdam.length);
console.log('sem medida possivel ......................', fluxo.semMedida.length);
console.log('desceram com o filho no fluxo ............', fluxo.herdam.length);
console.log('desceram com o filho absoluto ............', solta.herdam.length);
console.log('CONFIRMADAS COMO HERDADAS ................', confirmadas.length);
console.log('descartadas (era efeito de layout) .......', layout.join(', '));
console.log('\nherdam no Chrome, mas o mdn-data diz que nao:', nomes(confirmadas.filter((x) => !x.mdn)));
console.log('o mdn-data diz que herdam, e nao desceram ...:', nomes(lista.filter((x) => x.mdn
&& !confirmadas.some((c) => c.nome === x.nome) && !fluxo.semMedida.includes(x.nome))));
await browser.close();A segunda rodada, com o filho em position: absolute, existe por um motivo
específico: propriedades de tamanho enganam a medição. Se o pai recebe
width: 30%, o filho width: auto computa exatamente a mesma largura em pixels
— e parece herança, sem ser. Tirando o filho do fluxo, ele encolhe para o
conteúdo e a coincidência desaparece. Só entram na lista as propriedades que
desceram nos dois cenários.
herdam no Chrome, mas o mdn-data diz que nao: user-select o mdn-data diz que herdam, e nao desceram …: interest-delay, interest-delay-end, interest-delay-start, object-position
81 de 373. Pouco mais de um quinto. É por isso que a herança não resolve layout: ela cuida de texto, cor e alguns detalhes de interação, e larga completamente a caixa.
As 81 confirmadas cabem em famílias:
| família | propriedades confirmadas | por que faz sentido descer |
|---|---|---|
| fonte | font-family, font-size, font-style, font-weight, font-variant, font-kerning, font-size-adjust, font-synthesis, font-palette |
um bloco de texto é um bloco de texto até o fim |
| ritmo do texto | line-height, letter-spacing, word-spacing, text-indent, text-align, text-transform, tab-size |
mudam a mancha de texto inteira, não um elemento |
| quebra de linha | white-space, text-wrap, word-break, overflow-wrap, line-break, hyphens, widows, orphans |
a regra de quebra vale para o parágrafo todo |
| cor | color, accent-color, caret-color, color-scheme |
tom da região, não do elemento |
| listas | list-style-type, list-style-image |
a lista aninhada continua sendo lista |
| tabelas | border-collapse, border-spacing |
são decisões da tabela, aplicadas nas células |
| interação | cursor, pointer-events, visibility, user-select |
valem para a área, e a área tem filhos |
| SVG | fill, stroke, stroke-width, marker-* |
um <g> pinta o grupo inteiro |
Duas surpresas na saída merecem nota. user-select está marcado como não
herdado no mdn-data 2.27.1, mas o Chrome propaga o valor para os filhos — o
comportamento é definido na especificação por uma regra própria, e não pela
herança normal. E object-position, que o mesmo arquivo marca como herdado,
simplesmente não desce:
<style>
.cartao { object-position: 30% 10%; user-select: none; }
</style>
<div class="cartao"><img id="foto" src="x.png" alt=""><span id="texto">Mel</span></div>Moral prática: quando a dúvida for cara, meça no navegador em que o seu código vai rodar. Tabela é ponto de partida, não sentença.
Por que o link ignora o pai, e por que !important não resolve
Volte ao link azul da ficha. A tentação é subir o peso da regra do pai. Quatro
rodadas, medindo color no p e no a a cada mudança:
/* rodada 1 */ .ficha { color: #14532d; }
/* rodada 2 */ .ficha { color: #14532d !important; }
/* rodada 3 */ .ficha { color: #14532d !important; }
html body div.ficha a#a { color: #14532d; }
/* rodada 4 */ .ficha { color: #14532d; }
.ficha a { color: inherit; }O !important no pai não mudou nada no filho, e não mudaria nunca. Ele
decide qual declaração vence no .ficha. O a tem a disputa dele, e nessa
disputa a única candidata é a regra do navegador. Não existe declaração do autor
para comparar, então não existe nada para o !important ganhar.
Dá para confirmar quem declarou, perguntando ao próprio motor do Chrome pelo protocolo de depuração — é a mesma informação que o painel Styles do DevTools mostra:
import { chromium } from 'playwright-core';
const CHROME = process.env.HOME + '/Library/Caches/ms-playwright/chromium-1234/' +
'chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing';
const browser = await chromium.launch({ executablePath: CHROME });
const page = await browser.newPage();
await page.setContent(`
<style> .ficha { color: #14532d } .ficha a { color: inherit } </style>
<div class="ficha"><a id="a" href="/prontuario">Ver prontuário</a></div>
`);
const cdp = await page.context().newCDPSession(page);
await cdp.send('DOM.enable');
await cdp.send('CSS.enable');
const { root } = await cdp.send('DOM.getDocument');
const { nodeId } = await cdp.send('DOM.querySelector', { nodeId: root.nodeId, selector: '#a' });
const m = await cdp.send('CSS.getMatchedStylesForNode', { nodeId });
const cor = (r) => r.rule.style.cssProperties.find((p) => p.name === 'color');
for (const r of m.matchedCSSRules ?? []) {
if (cor(r)) console.log(`origem=${r.rule.origin.padEnd(10)} seletor=${r.rule.selectorList.text.padEnd(24)} color: ${cor(r).value}`);
}
for (const h of m.inherited ?? []) { // os ancestrais vêm num grupo à parte
for (const r of h.matchedCSSRules ?? []) {
if (cor(r)) console.log(`herdado origem=${r.rule.origin.padEnd(10)} seletor=${r.rule.selectorList.text.padEnd(15)} color: ${cor(r).value}`);
}
}
await browser.close();A leitura foi feita com o CSS da quarta rodada no lugar, e as três linhas contam a
história inteira. A primeira é a culpada: a:-webkit-any-link { color: -webkit-link }, origem
user-agent. Nas rodadas 1 e 2 ela estava sozinha na lista, e por isso ganhava
sem esforço. A segunda linha é a correção que entrou na rodada 4 — uma
declaração do autor, origem regular, que agora ocupa a mesma vaga e vence. A
terceira aparece num grupo à parte, rotulado como herdado: é a regra do .ficha,
que o Chrome guarda como candidata a fornecer o valor por herança.
O que desce é o valor computado, não o que você escreveu
Herança copia o valor computado do pai — o valor já resolvido, com as unidades relativas transformadas em absolutas. Não copia o que está escrito na folha de estilo. A diferença aparece na hora que você usa porcentagem.
Na agenda da clínica, cada nível aninhado pede 80% da fonte:
.agenda { font-size: 20px; }
.agenda .grupo { font-size: 80%; }<div class="agenda" id="n0">Agenda da semana
<div class="grupo" id="n1">Segunda
<div class="grupo" id="n2">09:00 Mel — vacina
<div class="grupo" id="n3">observação do tutor</div>
</div>
</div>
</div>Três níveis e o texto virou 10 pixels. Cada 80% é calculado sobre o computado
do pai, que já era 80% do avô. Porcentagem de fonte acumula, e o efeito é
multiplicativo — este é o motivo pelo qual rem, que sempre se resolve contra a
raiz, ganhou o dia a dia. As unidades do CSS merecem
uma leitura só delas por causa disso.
O mesmo mecanismo produz o bug clássico do line-height:
.porcento { font-size: 20px; line-height: 150%; }
.numero { font-size: 20px; line-height: 1.5; }
.titulo { font-size: 40px; }<div class="porcento"><p class="titulo" id="p1">Mel — Golden Retriever</p></div>
<div class="numero"><p class="titulo" id="p2">Mel — Golden Retriever</p></div>Com 150%, o computado do pai é 30px, e é esse 30px que desce. O título de
40 pixels ficou com linha de 30 — a letra é maior que a linha, e as linhas se
encavalam. Com 1.5, o valor computado continua sendo o número 1.5; cada
descendente multiplica pelo próprio font-size e o título chega a 60px.
inherit, initial, unset e revert: forçar a mão
As quatro palavras-chave existem justamente para você intervir em cada etapa
daquele fluxo de decisão. Elas funcionam em qualquer propriedade, herdada ou
não. O teste: um link dentro da ficha, com uma regra do autor pintando color e
background-color, e cada palavra-chave aplicada por cima.
.ficha { color: #14532d; background-color: #ecfdf5; }
.ficha a { color: #b91c1c; background-color: #fee2e2; }
/* e, em cada rodada, uma destas: */
.ficha a#alvo { color: inherit; background-color: inherit; }
.ficha a#alvo { color: initial; background-color: initial; }
.ficha a#alvo { color: unset; background-color: unset; }
.ficha a#alvo { color: revert; background-color: revert; }Leia a linha do unset com atenção: a mesma palavra produziu resultados
diferentes nas duas propriedades. color é herdada, então unset virou
inherit e pegou o verde do pai. background-color não é herdada, então unset
virou initial e ficou transparente. É a única das quatro que muda de
comportamento conforme a propriedade.
E o revert na cor do link é o detalhe que separa quem entendeu de quem
decorou: rgb(0, 0, 238) é o azul de link do navegador. Ele desfez só o CSS do
autor — inclusive a regra .ficha a — e deixou de pé o que a folha padrão
declara. unset, na mesma propriedade e no mesmo elemento, ignorou essa folha e
foi buscar o verde no pai.
| palavra-chave | o que faz | resultado no link do teste |
|---|---|---|
inherit |
copia o valor computado do pai, seja a propriedade herdada ou não | verde do .ficha |
initial |
usa o valor inicial da propriedade, definido na especificação | preto e transparente |
unset |
inherit se a propriedade é herdada, initial se não é |
verde e transparente |
revert |
apaga as declarações do autor e devolve o valor do navegador | azul de link e transparente |
revert-layer |
apaga só a camada @layer atual, mantendo as anteriores |
depende das camadas |
A mesma diferença fica gritante com o atalho all, que aplica a palavra-chave a
todas as propriedades de uma vez. Num botão que o autor já tinha estilizado:
.barra { font-family: Georgia, serif; font-size: 18px; color: #14532d; }
.barra button { font: inherit; color: #14532d; background: none; border: 0; padding: 0; }<div class="barra">
<button id="b1">Confirmar</button>
<button id="b2" style="all: revert">Confirmar</button>
<button id="b3" style="all: unset">Confirmar</button>
</div>all: revert devolveu o botão cinza de fábrica, com borda e fundo. all: unset
fez o oposto: apagou tudo, inclusive o que o navegador tinha posto, e deixou o
botão herdando a fonte e a cor do pai. Quando você quer transformar um botão em
texto puro, all: unset é o caminho — mas ele leva junto o anel de foco: no
mesmo teste, o botão intacto computa outline: auto 1px rgb(0, 95, 204) quando
recebe foco pelo teclado, e o botão com all: unset computa outline: none.
Reponha o :focus-visible na mão, e um cursor: pointer se quiser o ponteiro.
Três atalhos que a herança te dá de graça
A herança não é só um comportamento a ser contornado. Três padrões vivem dela.
currentColor empresta a cor para propriedades que não herdam. Borda não é
herdada, mas border-color: currentColor faz a borda seguir o color — que é
herdado. Variáveis CSS são herdadas por padrão, então redefinir uma no meio
da árvore muda o subconjunto inteiro abaixo. Os dois juntos:
.agenda { --acento: #14532d; color: var(--acento); }
.cartao { border: 2px solid currentColor; border-left: 6px solid var(--acento); }
.urgente { --acento: #b91c1c; color: var(--acento); }<div class="agenda">
<div class="cartao" id="c1">09:00 Mel — vacina</div>
<div class="urgente">
<div class="cartao" id="c2">10:30 Thor — sutura
<div class="cartao" id="c3">observação do tutor</div>
</div>
</div>
</div>Nenhum dos três cartões declara color, border-top-color nem
border-left-color: os três valores chegaram de graça, e o .urgente repintou o
cartão, a borda e o cartão aninhado dentro dele.
Só que o crédito não é todo da variável, e vale desmontar — porque é aqui que
muita gente escreve o tema e não entende por que metade não pegou. O .urgente
tem duas declarações. Tirando a segunda e deixando só a variável:
.urgente { --acento: #b91c1c; } /* sem o color: var(--acento) */A variável desceu — --acento está vermelho em c2 e c3 —, e mesmo assim o
color continuou verde. O motivo é a regra da seção anterior: o que a herança
copia é o valor computado. O var(--acento) do .agenda foi resolvido lá em
cima, virou verde ali, e é verde que desce — não “o que --acento valer aqui”.
Só o border-left-color mudou sozinho, porque o var(--acento) dele está no
.cartao e é resolvido de novo em cada cartão.
A regra prática: redefinir a variável muda tudo que lê a variável naquele
nível para baixo. Uma propriedade que já resolveu o var() num ancestral
precisa da linha que relê — e é essa linha que arrasta o currentColor da borda
junto. É o mecanismo que sustenta tema claro e escuro sem duplicar folha de
estilo, e o assunto da lição de variáveis CSS.
Pseudo-elementos herdam do elemento que os originou. ::before não tem pai
no HTML, mas herda do elemento em que foi criado:
.agenda { color: #14532d; font-style: italic; letter-spacing: 2px; }
.cartao::before { content: "▸ "; }O marcador sai verde, itálico e com o mesmo espaçamento, sem uma linha a mais. As pseudo-classes e pseudo-elementos têm mais detalhes sobre onde esses elementos fantasmas se encaixam.
Herança segue a árvore de elementos, não o que aparece na tela
Herança é definida sobre a árvore do documento — a mesma que o navegador
monta a partir do seu HTML. Ela não
tem nada a ver com o que está visível. A prova mais limpa disso é comparar
visibility, que é herdada, com display, que não é:
.escondido { visibility: hidden; }
.escondido .aviso { visibility: visible; }
.sumido { display: none; }
.sumido .aviso { display: block; }<div class="escondido">bloco<span class="aviso" id="v1">vaga cancelada</span></div>
<div class="sumido">bloco<span class="aviso" id="v2">vaga cancelada</span></div>No primeiro caso o filho reapareceu: o pai passou hidden por herança, e uma
declaração no filho sobrescreveu esse valor herdado — herança é sobrescrevível,
como qualquer valor. No segundo caso não há herança nenhuma para desfazer.
display: none no pai remove a subárvore inteira da renderização, e o
display: block do filho, embora tenha vencido a cascata dele, não tem onde ser
desenhado. Repare que o filho computa display: block mesmo assim — o valor
existe, a caixa é que não.
O conserto de duas linhas que todo projeto precisa
Volte à primeira tabela: button e input em Arial 13.3333px, pretos, no meio
de uma página em Georgia 18px verde. Isso não é bug do navegador, é a folha
padrão dele fazendo o trabalho dela. Mas quase nunca é o que você quer.
body { font-family: Georgia, serif; font-size: 18px; color: #14532d; }
.consertado input,
.consertado button,
.consertado select,
.consertado textarea {
font: inherit;
color: inherit;
}Duas declarações, quatro seletores, e os formulários passam a fazer parte da
página. font: inherit é o atalho: ele resolve família, tamanho, peso, estilo e
altura de linha de uma vez. Essas linhas estão em praticamente todo reset de CSS
sério, e agora você sabe exatamente por quê — elas não estão “estilizando” o
formulário, estão abrindo a vaga para a herança entrar.
O caminho de um valor, do CSS até o pixel
Juntando tudo, o percurso de uma propriedade num elemento:
Repare que a herança fica num galho só do desenho, e que esse galho começa numa resposta negativa. Toda vez que uma propriedade “não está herdando”, a resposta está lá em cima: alguma declaração venceu a cascata e desviou o fluxo para a direita.
Descobrir na hora quem passou o valor
O painel Computed do DevTools já mostra a origem de cada valor. Mas dá para responder pela linha de comando com uma função de sete linhas: subir a árvore enquanto o pai computar o mesmo valor. O último ancestral que ainda bate é onde o valor nasceu.
function origemDoValor(el, prop) {
const valor = getComputedStyle(el).getPropertyValue(prop);
let dono = el;
while (dono.parentElement &&
getComputedStyle(dono.parentElement).getPropertyValue(prop) === valor) {
dono = dono.parentElement;
}
const nome = dono.tagName.toLowerCase() + (dono.className ? '.' + dono.className : '');
const onde = dono === el ? 'definido neste elemento' : `herdado de <${nome}>`;
return `${prop.padEnd(12)} ${valor.padEnd(24)} ${onde}`;
}
const alvo = document.querySelector('.observacao');
for (const p of ['color', 'line-height', 'font-style', 'font-family', 'padding-top']) {
console.log(origemDoValor(alvo, p));
}Rodando na estrutura da agenda — body > main.pagina > section.agenda > article.cartao > p.observacao, com color e line-height só no .agenda,
font-style só no .observacao e a fonte lá no body:
Cole essa função no console e você para de adivinhar de onde vem a cor cinza que
apareceu no rodapé. É uma heurística, não uma prova, e ela erra de dois jeitos:
se dois ancestrais declararem o mesmo valor por coincidência, ela aponta o de
cima; e valor que ninguém declarou aparece como “definido neste elemento” — foi
o que aconteceu com o padding-top: 0px da última linha, que é só o valor
inicial da propriedade. Para o dia a dia, resolve; para a prova, o painel Styles
mostra a regra com nome e arquivo.
O que vem depois
Herança e cascata são os dois mecanismos que decidem tudo no CSS, e agora você tem os dois no lugar certo da fila: a cascata escolhe entre o que existe, a herança preenche o que não existe. Se a parte de “o que existe” ainda está nebulosa, a lição de especificidade no CSS destrincha o desempate declaração por declaração — e a de o que é CSS mostra a folha do navegador que apareceu aqui várias vezes.
Depois disso, o próximo passo é layout, onde a herança não ajuda em nada e cada propriedade precisa ser declarada onde é usada. O guia de CSS tem a ordem completa de estudo, da primeira folha de estilo até Grid.
Prefere aprender em vídeo?
Tem uma aula sobre este assunto no nosso canal.
Perguntas frequentes
Herança é a mesma coisa que cascata?
Por que a cor do link não muda quando eu pinto o container?
.container a { color: inherit; }.opacity: 0.5 no pai deixa o filho translúcido. Isso é herança?
Herança atravessa um iframe?
Por que line-height sem unidade é a recomendação?
Variável CSS herda?
@property e inherits: false: aí o filho ignora o valor do pai e usa o initial-value declarado.Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
Todo o código deste artigo foi executado em Chrome for Testing 151.0.7922.34 via Playwright 1.62.1 no Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.
Fontes consultadas
- MDN — Inheritance — developer.mozilla.org
- CSS Cascading and Inheritance Level 5 — Inheritance — w3.org
- MDN — Value definition: inherit, initial, unset, revert — developer.mozilla.org
- HTML Standard — Rendering (a folha de estilo padrão do navegador) — html.spec.whatwg.org



