Dev & EngARTIGO

Reset de tipografia moderno aproveita container queries e fontes variáveis em CSS puro

Reset de tipografia moderno aproveita container queries e fontes variáveis em CSS puro
Imagem gerada por IA
Artigo · Dev & Eng
Leitura
8 min
Tabelas
1
Código
5
Fontes
1
Em resumo

Um reset publicado pelo CSS-Tricks, batizado de tidy-typography.css, reúne clamp(), unidades de container query e propriedades experimentais de texto para resolver quebra de linha, hifenização e tipografia fluida direto no CSS.

Reset CSS↳CSS31 conteúdosArquitetura CSS: CSS FuncionalDev (Back & Front) · set 2019Entendendo posicionamento com CSS de uma vez por todasDev (Back & Front) · jul 2025Sites que combinam estética e usabilidade: reflexos da evolução do CSSDev (Back & Front) · fev 2025Ver tudo em Dev (Back & Front) → tradicionalmente resolve margem zerada e box-sizing, deixando decisões tipográficas pro CSS do projeto ou pra algum script de correção de órfãos. O CSS-Tricks publicou um reset batizado de tidy-typography.css que reúne, num só arquivo, escolhas que hoje já dá pra fazer só com CSS: quebra de linha sem palavra solta, tipografia presa ao tamanho do container (não ao da tela), hifenização configurável e ajustes finos de fontes variáveis. A ideia não é importar o arquivo inteiro: é copiar a declaração que resolve o incômodo da vez, porque parte do conjunto ainda é experimental e o suporte entre navegadores é desigual.

Para quem constrói front-end, o ganho prático é trocar JavaScript de UI (bibliotecas de balanceamento de título, hifenização manual, detecção de idioma pra aspas) por propriedades nativas que o navegador já entende ou simplesmente ignora quando não suporta. Essa degradação graciosa é o ponto central do reset: nenhuma declaração quebra o layout num navegador sem suporte, ela só deixa de se aplicar.

Renderização e fallback antes de qualquer fonte carregar

Antes de falar de tamanho de fonte, o reset cobre o básico de como o texto é desenhado na tela:

css
html {
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-synthesis: none;
  text-size-adjust: none;
}

body {
  font-size-adjust: from-font;
}

font-synthesis: none impede o navegador de inventar negrito ou itálico quando a família tipográfica não tem aquele estilo. text-rendering e o font-smoothing são dicas de renderização, principalmente para WebKit, e o resultado varia por plataforma. Já text-size-adjust: none desliga a inflação automática de fonte no mobile, que pode fazer um layout calculado de propósito saltar de tamanho na rotação da tela, enquanto font-size-adjust: from-font usa as métricas da própria fonte pra reduzir esse salto durante a troca por uma webfont.

Tipografia fluida que não erra o tamanho do container

Tipografia fluida baseada em viewport (vw) não sabe a largura do elemento onde está: um título numa sidebar estreita acaba escalando como se ocupasse a tela inteira. A solução do reset troca vw por cqi, a unidade de container query:

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

:root {
  --step-0: clamp(1rem, 0.9rem + 1cqi, 1.125rem);
  --step-3: clamp(2rem, 1.6rem + 3cqi, 2.75rem);
}

container-type: inline-size transforma o wrapper num container de consulta, e os filhos passam a escalar com base na largura desse container, não da tela. O mesmo título se comporta direito numa coluna de artigo ou numa sidebar de 300px, sem media query específica por componente. Na minha leitura, vale lembrar que declarar container-type cria um novo contexto de containment no elemento, o que pode interferir em comportamentos de layout que dependiam do fluxo normal ali dentro, então convém aplicar no wrapper certo, não em qualquer ancestral.

Ritmo vertical: cortando o half-leading

line-height inclui um espaço acima da altura das maiúsculas e abaixo da linha de base, o chamado half-leading, que fica evidente quando o texto precisa alinhar rente a outro elemento. text-box-trim: trim-both remove essa sobra, e text-box-edge: cap alphabetic mede do topo das maiúsculas até a linha de base alfabética, substituindo os ajustes de margem negativa feitos fonte por fonte.

css
:is(h1, h2, h3, h4, h5, h6), p, blockquote, figcaption, li {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

@supports selector(:heading) {
  :heading {
    text-box: trim-both cap alphabetic;
  }
}

O seletor :heading, que casaria com h1 a h6 e com [role="heading"], é proposta do Selectors Level 5 e ainda não existe em nenhum navegador, por isso fica atrás de um @supports selector().

Blocos balanceados, sem órfãos e sem reembaralhar enquanto alguém digita

O reset usa três valores de text-wrap para três problemas diferentes, e misturar os três no lugar errado produz efeito ruim:

ValorEfeitoMelhor uso
balanceDistribui o texto entre as linhas do blocoTítulos e blocos curtos, até cerca de 6 linhas
prettyEvita só a palavra solta na última linha, sem balancear o bloco inteiroParágrafos e listas
stableImpede que o texto se reorganize a cada palavra novaCampos contenteditable

Os três substituem scripts de correção de órfãos que rodavam no cliente pra medir e reposicionar quebras de linha. Em navegador sem suporte, a declaração é ignorada e o texto volta ao comportamento padrão, sem quebrar o layout.

Hifenização sob controle, sem escada de hífens

hyphens: auto depende de dicionário por idioma, então o atributo lang precisa estar correto no HTML ou no CSS pra funcionar. O problema é que o comportamento padrão pode gerar fragmentos minúsculos ou várias linhas hifenizadas seguidas, e o reset ataca isso com um conjunto de propriedades mais novas:

css
p {
  hyphens: auto;
  lang: en;
  hyphenate-limit-chars: 6 3 3;
  hyphenate-character: "‐";
  hyphenate-limit-lines: 2;
  hyphenate-limit-zone: 8%;
  hyphenate-limit-last: always;

  -webkit-hyphens: auto;
  -webkit-hyphenate-limit-before: 4;
  -webkit-hyphenate-limit-after: 3;
  -webkit-hyphenate-limit-lines: 2;
}

pre, code, var, samp, kbd, :is(h1, h2, h3, h4, h5, h6) {
  hyphens: manual;
  -webkit-hyphens: manual;
}

hyphenate-limit-chars controla o tamanho mínimo da palavra quebrável e o número de caracteres antes e depois do hífen; hyphenate-limit-lines evita o efeito escada de hífens empilhados; hyphenate-limit-zone reduz a frequência geral das quebras; hyphenate-limit-last protege a última palavra do parágrafo. Safari ainda depende dos equivalentes com prefixo, por isso os dois conjuntos aparecem juntos. Código, variáveis e títulos ficam com hyphens: manual: uma palavra de código quebrada pode mudar de significado, e um título hifenizado costuma parecer erro de diagramação.

Pontuação suspensa e sublinhados que respeitam a tinta

Sinais de pontuação não têm o mesmo peso visual das letras, então uma aspa no início de linha parece ligeiramente recuada em relação ao texto abaixo. hanging-punctuation: first allow-end last deixa a pontuação especificada sair fracionadamente da borda do bloco de texto, de forma que as margens leiam como realmente alinhadas.

Sublinhados têm um problema parecido: o navegador aplica espessura e posição fixas, independente do peso real da fonte. text-decoration-thickness: from-font lê a espessura pensada pelo desenhista da fonte, text-underline-offset dá espaço pras descendentes respirarem, e text-decoration-skip-ink: auto interrompe o traço onde uma descendente cruza a linha, em vez de desenhar por cima da letra.

Fontes variáveis: tamanho óptico e correção de peso no modo escuro

Fontes variáveis costumam trazer um eixo de tamanho óptico, o opsz, que deixa a fonte usar traços mais finos em tamanhos grandes de exibição e traços mais grossos e legíveis em tamanhos pequenos. font-optical-sizing: auto delega essa escolha ao tamanho renderizado de fato, com um @supports (font-variation-settings: normal) cobrindo a sintaxe antiga que alguns navegadores ainda pedem.

Em resumo: texto claro sobre fundo escuro lê mais pesado do que o mesmo peso sobre fundo claro, e fontes com eixo GRAD (grade) permitem compensar essa percepção sem alterar a forma nem a largura dos glifos, como uma mudança de peso de verdade faria. O reset troca uma variável --vf-grad dentro de @media (prefers-color-scheme: dark), e fontes sem esse eixo simplesmente ignoram a declaração.

Um detalhe menos óbvio aparece ao misturar uma fonte monoespaçada no meio de texto corrido: a altura-x costuma destoar mesmo com o mesmo font-size declarado. size-adjust, definido uma vez dentro do @font-face, reescala a saída renderizada daquela fonte especificamente, sem tocar no valor de font-size usado no resto do CSS.

Números tabulares, emoji consistente e aspas por idioma

Números numa tabela precisam ter a mesma largura pra formar coluna limpa; números no meio de um parágrafo não precisam disso e devem acompanhar o texto ao redor. font-variant-numeric: tabular-nums lining-nums resolve o primeiro caso; oldstyle-nums proportional-nums resolve o segundo, deixando os dígitos na altura da caixa baixa.

font-variant-emoji: emoji ou text torna explícita a escolha entre emoji colorido e monocromático: sem essa declaração, quem decide é o navegador ou a plataforma, e o resultado varia mais do que parece razoável. A recomendação do reset é aplicar em containers específicos, não globalmente no body.

A propriedade quotes declara a ordem de aspas por :lang(), e o elemento nativo q insere o par certo via open-quote e close-quote, sem precisar fixar caractere no conteúdo. Envolver essas regras em :where() mantém especificidade zero, então um projeto consegue sobrescrever o estilo de aspas com uma classe simples. Sub e sobrescrito sintetizados (o navegador só encolhe o texto e desloca a linha de base) ganham alternativa com font-variant-position, que usa os glifos desenhados pra essa posição quando a fonte os tem, embora a maioria das famílias só traga numerais nessa variante, não o alfabeto completo.

:is() e :where(): a diferença que importa num reset

:where() sempre resolve para especificidade zero, o que é útil justamente porque cada regra do reset é um valor padrão opinativo, e qualquer projeto precisa conseguir sobrescrever com uma classe comum:

css
:where(h1, h2, h3, h4, h5, h6) {
  margin-block: 0.5em;
}

:is() resolve outro problema, o de repetição: a lista de seletores de título aparece várias vezes numa folha de estilo tipográfica, e agrupar evita esquecer um nível. A diferença prática é que :is() carrega a especificidade do argumento mais específico da lista, enquanto :where() não carrega nenhuma.

Onde isso vale a pena, e onde não

Muita dessa CSS tira trabalho que antes vazava pro JavaScript: text-wrap assume a correção de órfãos, as unidades de container query mantêm a escala de um componente presa à sua própria largura, e text-box-trim evita as margens negativas usadas antes pra compensar entrelinha. quotes, font-variant-position e font-optical-sizing devolvem detalhes menores pro idioma e pra fonte, em vez de uma coleção de correções pontuais.

O suporte de navegador vai continuar mudando, principalmente para text-wrap e text-box-trim. Declarações não suportadas são ignoradas, mas isso só ajuda quando a tipografia sem o reforço já é aceitável por conta própria. Uma notícia, uma página de marketing e uma interface de produto editável não pedem as mesmas coisas do texto: o conjunto que cabe no seu projeto depende da fonte escolhida, do tipo de conteúdo e dos navegadores que você ainda precisa suportar. Vale ler o código completo do tidy-typography.css no artigo original do CSS-Tricks antes de decidir o que entra na sua folha de estilo.

Fonte: CSS-Tricks

Highlights

  1. tidy-typography.css usa container queries (cqi) em vez de viewport (vw) para tipografia fluida que respeita o tamanho real do elemento
  2. text-wrap: pretty evita palavra solta sem balancear bloco inteiro; text-wrap: balance redistribui títulos e citações; text-wrap: stable para campos editáveis
  3. Troca scripts de balanceamento de órfãos, hifenização manual e detecção de idioma por propriedades CSS nativas que o navegador entende ou ignora graciosamente
  4. text-box-trim e text-box-edge removem half-leading, alinhando texto rente a elementos vizinhos sem margem negativa por fonte
  5. Fontes variáveis ganham eixo GRAD para compensar peso visual em modo escuro sem alterar forma dos glifos

Este artigo foi escrito por Carina Ferreira, colunista de front-end. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.

Especialista virtual de front-end. Vive de TypeScript, React/Next e da fronteira AI + front (copilots, geração de UI, edge). Obcecada por DX e performance percebida — mede antes de opinar e mostra o antes/depois.

Mais de Carina Ferreira
Ver perfil →