Compartilhe um arquivo CSS entre páginas LTR e RTL definindo a direção HTML explicitamente, usando propriedades lógicas para espaçamento direcional e usando gap entre itens de layout. Este guia cria um exemplo local de duas páginas que você pode comparar em um navegador Mac.

A tarefa é fazer com que o mesmo pequeno componente mantenha seu espaçamento pretendido quando sua direção inline muda. Você precisa de um editor de texto simples e de um navegador desktop atual. O exemplo usa rótulos sintéticos e um círculo decorativo, sem framework, assets externos ou JavaScript.

O que a folha de estilos compartilhada deve controlar?

Dê ao HTML a responsabilidade pela direção e à folha de estilos a responsabilidade pelo espaçamento. Ambas as páginas carregam o mesmo recurso CSS e usam as mesmas classes de componente; a raiz da página fornece dir="ltr" ou dir="rtl". O HTML define rel="stylesheet" como um link de recurso externo que contribui para o estilo do documento. HTML Standard: stylesheet links.

Use o dir HTML quando a direção for conhecida. Descendentes geralmente herdam a direção, e lang não a define. Prefira direção explícita em vez de dir="auto" para esta comparação controlada: direção automática depende do conteúdo e faria os rótulos de exemplo em latim escolherem LTR. MDN: o atributo dir.

A distinção útil é entre uma borda física e uma posição no fluxo de conteúdo. No modo de escrita horizontal-tb deste exemplo, inline start significa esquerda em LTR e direita em RTL. Block start permanece no topo. Propriedades lógicas expressam essas relações diretamente. MDN: logical margins, borders, and padding.

Espaçamento pretendido Escolha CSS compartilhada Resultado quando a direção muda
Espaço dentro da borda inicial do componente padding-inline-start Move para o outro lado físico
Espaço dentro de ambas as bordas inline padding-inline Aplica valores de início e fim na nova direção
Espaço entre itens Flexbox gap Mantém o gap entre itens especificado
Espaço acima e abaixo neste layout horizontal padding-block Permanece acima e abaixo
Uma margem antes de um elemento no fluxo inline margin-inline-start Mapeia para o novo lado inline-start

Os mapeamentos de margin e padding seguem o modo de escrita e a direção do elemento. gap cria calhas em containers de layout suportados. São tarefas separadas: use padding ao redor do conteúdo e gap entre itens irmãos. MDN: logical spacing, MDN: gap.

Criar duas páginas locais que usam um arquivo CSS

Crie uma pasta chamada spacing-demo no seu Mac. Salve os seguintes arquivos como texto simples com suas extensões exatas. Evite um editor que adicione .txt após .html ou .css.

spacing-demo/
  ltr.html
  rtl.html
  components.css

Salve este documento HTML completo como ltr.html. Em seguida, salve uma segunda cópia como rtl.html, alterando apenas o atributo raiz de dir="ltr" para dir="rtl". Mantenha a referência da folha de estilos e a marcação do componente idênticas. Os rótulos permanecem em inglês porque esta é uma comparação de layout sintética.

<!doctype html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Component spacing sample</title>
  <link rel="stylesheet" href="components.css">
</head>
<body>
  <main class="demo">
    <h1>Spacing sample</h1>
    <article class="sample-card">
      <span class="sample-card__shape" aria-hidden="true"></span>
      <div class="sample-card__copy">
        <h2 class="sample-card__title">Module A</h2>
        <p class="sample-card__description">A compact sample tile</p>
      </div>
      <span class="sample-card__tag">Set B</span>
    </article>
  </main>
</body>
</html>

Agora salve a seguinte folha de estilos completa como components.css. O padding inline deliberadamente desigual torna as mudanças de direção fáceis de inspecionar: o recuo maior deve seguir o inline start.

:root {
  --space-small: 8px;
  --space-medium: 16px;
  --space-large: 24px;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 24px;
  font-family: system-ui, sans-serif;
  line-height: 1.5;
  color: #243447;
  background: #f2f5f8;
}

.demo {
  writing-mode: horizontal-tb;
  max-width: 640px;
  margin-inline: auto;
}

.sample-card {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-medium);
  padding-block: var(--space-medium);
  padding-inline: var(--space-large) var(--space-small);
  border: 1px solid #8594a5;
  border-radius: 12px;
  background: #ffffff;
}

.sample-card__shape {
  flex: 0 0 32px;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: #5477a3;
}

.sample-card__copy {
  flex: 1 1 0;
  min-width: 0;
  overflow-wrap: anywhere;
}

.sample-card__title,
.sample-card__description {
  margin: 0;
}

.sample-card__title {
  font-size: 18px;
}

.sample-card__description {
  margin-block-start: var(--space-small);
}

.sample-card__tag {
  flex: 0 0 auto;
  padding-block: 4px;
  padding-inline: var(--space-small);
  border: 1px solid #8594a5;
  border-radius: 6px;
}

Aqui, padding-inline: 24px 8px significa padding de início seguido por padding de fim. Não significa esquerda seguido por direita. Um único valor se aplicaria a ambas as bordas inline. MDN: padding-inline.

Mantenha flex-direction: row em ambas as páginas. Uma linha Flexbox já segue a direção do seu container: ela vai da esquerda para a direita em LTR e da direita para a esquerda em RTL. Adicionar row-reverse à versão RTL inverteria essa direção novamente. MDN: flex-direction.

O círculo neutro não tem significado direcional, então seu desenho permanece inalterado enquanto sua posição segue a linha. Os rótulos em latim também mantêm a ordem das letras; este exemplo verifica o layout do componente em vez de texto traduzido.

Como você verifica se o espaçamento é realmente compartilhado?

Abra ambos os arquivos HTML no seu navegador Mac e compare-os na mesma largura de janela. Os valores a seguir são esperados a partir das declarações, não de medições do navegador. A borda do card é separada do seu padding.

Verificação Página LTR Página RTL
Posição do círculo Primeiro item à esquerda Primeiro item à direita
Padding esquerdo do card 24px 8px
Padding direito do card 8px 24px
Gap entre itens flex adjacentes 16px 16px
Padding superior e inferior do card 16px 16px
Espaço antes da descrição 8px acima 8px acima

Teste o compartilhamento de recursos separadamente da direção. Altere --space-medium em components.css de 16px para 20px, salve e recarregue ambas as páginas. Ambas devem ganhar o maior gap entre itens e maior padding de bloco porque essas declarações referenciam a mesma variável. Restaure 16px após a comparação.

Em seguida, estreite a janela do navegador e substitua a descrição por um rótulo sintético mais longo, como Module A extended sample description. Verifique se o texto faz wrap sem cobrir o círculo ou a tag. Isso adiciona um segundo teste útil: um componente pode espelhar corretamente em uma largura enquanto fica apertado em outra.

Não julgue toda distância visível apenas por gap. Margens de itens, padding interno e alinhamento distribuído podem tornar a separação visível maior que a calha declarada. O exemplo reseta as margens do texto e evita alinhamento distribuído para que a comparação permaneça legível. MDN: descrição de gap.

Como migrar um componente existente sem conflitos de espaçamento?

Comece pelo significado de cada declaração existente. Um recuo de texto inicial geralmente pertence ao inline start; uma borda física intencionalmente fixa ainda pode precisar de uma propriedade física. Converta de acordo com a intenção do design em vez de substituir mecanicamente cada ocorrência de left.

Para um componente como este exemplo, use esta sequência:

  1. Identifique o ancestral que fornece a direção.
  2. Substitua o espaçamento interno direcional por padding lógico.
  3. Substitua o espaçamento externo direcional por margins lógicos onde necessário.
  4. Use o gap do pai para espaçamento comum entre itens flex, removendo margins que antes forneciam esse mesmo espaço.
  5. Repita as comparações de padding desigual e janela estreita em ambas as direções.

Verifique declarações físicas antigas e shorthands posteriores durante a migração. Propriedades lógicas e físicas que mapeiam para o mesmo lado participam da cascata juntas; uma propriedade lógica não vence automaticamente apenas por ser lógica. Uma declaração padding posterior pode resetar padding atribuído anteriormente através de propriedades lógicas quando os outros fatores da cascata são iguais. CSS Logical Properties and Values Level 1: box model properties.

Também mantenha o limite de direção em mente. Um componente aninhado com seu próprio dir="ltr" deve usar mapeamentos LTR mesmo dentro de uma página RTL. Por outro lado, margin-inline em si não é herdado, então dê a cada componente as declarações de espaçamento que ele precisa em vez de esperar que a margin de um ancestral seja transferida para ele. MDN: direction inheritance, MDN: definição formal de margin-inline.

Quais limites de navegador afetam esta abordagem?

O MDN marca padding-inline e margin-inline como amplamente disponíveis entre navegadores desde abril de 2021. Isso suporta seu uso em navegadores desktop atuais, mas não é uma promessa sobre todo navegador mais antigo ou toda sintaxe mais nova mostrada nas páginas de referência. Este exemplo usa comprimentos comuns e auto, sem funções de dimensionamento mais recentes. MDN: padding-inline, MDN: margin-inline.

O gap do Flexbox tem uma história separada. O Safari o adicionou na versão 14.1; o gap do Grid já era suportado desde o Safari 12. O WebKit observa especificamente que uma consulta de recurso de propriedade não poderia distinguir esses contextos, então @supports (gap: 16px) sozinho é insuficiente para detectar suporte a gap do Flexbox em versões antigas do Safari. WebKit: New WebKit Features in Safari 14.1.

Se o seu navegador alvo suporta margins lógicas, mas não tem gap do Flexbox, adicione este fragmento de substituição após as regras principais da folha de estilos. Ele fornece espaçamento para este componente específico de linha única. Use-o em vez do espaçamento gap ativo, como mostrado; não é uma solução geral para linhas com wrap.

/* Optional single-row replacement for Flexbox gap. */
.sample-card {
  gap: 0;
}

.sample-card > * + * {
  margin-inline-start: var(--space-medium);
}

Para navegadores que também não têm propriedades lógicas, este fallback é insuficiente. Use um navegador atual para a tarefa local, ou crie e teste regras físicas LTR e RTL explícitas para o alvo mais antigo. Mantenha essa decisão específica do navegador separada do design principal da folha de estilos compartilhada.

A comparação concluída deve mostrar um contrato consistente: o HTML fornece a direção, o CSS compartilhado fornece o espaçamento, e o recuo inicial do componente segue o inline start. Mantenha as duas páginas locais como um fixture de regressão compacto sempre que você alterar o espaçamento ou layout do componente.

Fontes