Comparte un archivo CSS entre páginas LTR y RTL configurando explícitamente la dirección HTML, usando propiedades lógicas para el espaciado direccional y usando gap entre los elementos del diseño. Esta guía crea un ejemplo local de dos páginas que puedes comparar en un navegador de Mac.
La tarea consiste en lograr que el mismo componente pequeño mantenga el espaciado previsto cuando cambia su dirección en línea. Necesitas un editor de texto sin formato y un navegador de escritorio actualizado. El ejemplo usa etiquetas ficticias y un círculo decorativo, sin framework, recursos externos ni JavaScript.
¿Qué debe controlar la hoja de estilos compartida?
Deja que el HTML se encargue de la dirección y que la hoja de estilos se encargue del espaciado. Ambas páginas cargan el mismo recurso CSS y usan las mismas clases de componente; la raíz de cada página especifica dir="ltr" o dir="rtl". HTML define rel="stylesheet" como un enlace a un recurso externo que contribuye al estilo del documento. Estándar HTML: enlaces a hojas de estilo.
Usa HTML dir cuando se conozca la dirección. Por lo general, los elementos descendientes heredan la dirección, y lang no la establece. Para esta comparación controlada, prefiere una dirección explícita en lugar de dir="auto": la dirección automática depende del contenido y haría que las etiquetas de muestra en alfabeto latino eligieran LTR. MDN: el atributo dir.
La distinción útil está entre un borde físico y una posición en el flujo del contenido. En el modo de escritura horizontal-tb de este ejemplo, el inicio en línea corresponde a la izquierda en LTR y a la derecha en RTL. El inicio de bloque sigue estando arriba. Las propiedades lógicas expresan directamente esas relaciones. MDN: márgenes, bordes y relleno lógicos.
| Espaciado previsto | Opción de CSS compartida | Resultado al cambiar la dirección |
|---|---|---|
| Espacio dentro del borde inicial del componente | padding-inline-start |
Se desplaza al otro lado físico |
| Espacio dentro de ambos bordes en línea | padding-inline |
Aplica los valores de inicio y fin en la nueva dirección |
| Espacio entre elementos de Flexbox | gap |
Mantiene el espacio especificado entre elementos |
| Espacio arriba y abajo en este diseño horizontal | padding-block |
Permanece arriba y abajo |
| Un margen antes de un elemento en el flujo en línea | margin-inline-start |
Se asigna al nuevo lado de inicio en línea |
La asignación de márgenes y relleno sigue el modo de escritura y la dirección del elemento. En cambio, gap crea separaciones en los contenedores de diseño compatibles. Son funciones distintas: usa relleno alrededor del contenido y gap entre elementos hermanos. MDN: espaciado lógico, MDN: gap.
Crea dos páginas locales que usen un solo archivo CSS
Crea una carpeta llamada spacing-demo en tu Mac. Guarda los siguientes archivos como texto sin formato y con sus extensiones exactas. Evita los editores que añaden .txt después de .html o .css.
spacing-demo/
ltr.html
rtl.html
components.css
Guarda este documento HTML completo como ltr.html. Después guarda una segunda copia como rtl.html, cambiando solo el atributo raíz de dir="ltr" a dir="rtl". Mantén idénticos la referencia a la hoja de estilos y el marcado del componente. Las etiquetas seguirán en inglés porque se trata de una comparación de diseño ficticia.
<!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>
Ahora guarda la siguiente hoja de estilos completa como components.css. El relleno en línea deliberadamente desigual facilita la inspección de los cambios de dirección: la sangría mayor debe seguir el inicio en línea.
: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;
}
Aquí, padding-inline: 24px 8px significa que el relleno inicial va seguido del relleno final. No significa izquierda seguido de derecha. Un solo valor se aplicaría a ambos bordes en línea. MDN: padding-inline.
Mantén flex-direction: row en ambas páginas. Una fila de Flexbox ya sigue la dirección de su contenedor: va de izquierda a derecha en LTR y de derecha a izquierda en RTL. Añadir row-reverse a la versión RTL volvería a invertir esa dirección. MDN: flex-direction.
El círculo neutro no tiene significado direccional, así que su dibujo permanece igual mientras su posición sigue la fila. Las etiquetas en alfabeto latino también conservan el orden de sus letras; este ejemplo comprueba el diseño del componente, no un texto traducido.
¿Cómo verificas que el espaciado realmente se comparte?
Abre ambos archivos HTML en el navegador de tu Mac y compáralos con el mismo ancho de ventana. Los siguientes valores son los que se esperan según las declaraciones, no mediciones del navegador. El borde de la tarjeta es independiente de su relleno.
| Comprobación | Página LTR | Página RTL |
|---|---|---|
| Posición del círculo | Primer elemento a la izquierda | Primer elemento a la derecha |
| Relleno izquierdo de la tarjeta | 24px |
8px |
| Relleno derecho de la tarjeta | 8px |
24px |
| Espacio entre elementos flex adyacentes | 16px |
16px |
| Relleno superior e inferior de la tarjeta | 16px |
16px |
| Espacio antes de la descripción | 8px arriba |
8px arriba |
Comprueba por separado que se comparte el recurso y que cambia la dirección. Cambia --space-medium en components.css de 16px a 20px, guarda y vuelve a cargar ambas páginas. En las dos debería aumentar el espacio entre elementos y el relleno de bloque, porque esas declaraciones hacen referencia a la misma variable. Restablece 16px después de la comparación.
A continuación, estrecha la ventana del navegador y reemplaza la descripción por una etiqueta ficticia más larga, como Module A extended sample description. Comprueba que el texto se ajuste sin cubrir el círculo ni la etiqueta. Esto añade una segunda prueba útil: un componente puede reflejarse correctamente en un ancho y quedar demasiado apretado en otro.
No evalúes todas las distancias visibles basándote solo en gap. Los márgenes de los elementos, el relleno interno y la alineación distribuida pueden hacer que la separación visible sea mayor que la separación declarada. La muestra restablece los márgenes del texto y evita la alineación distribuida para que la comparación sea clara. MDN: descripción de gap.
¿Cómo migras un componente existente sin conflictos de espaciado?
Empieza por identificar el propósito de cada declaración existente. Una sangría inicial del texto suele corresponder al inicio en línea; un borde físico fijo a propósito quizá aún requiera una propiedad física. Convierte las declaraciones según la intención del diseño, en lugar de reemplazar mecánicamente cada aparición de left.
Para un componente como esta muestra, sigue estos pasos:
- Identifica el elemento antecesor que proporciona la dirección.
- Reemplaza el espaciado interior direccional por relleno lógico.
- Reemplaza, donde sea necesario, el espaciado exterior direccional por márgenes lógicos.
- Usa
gapdel elemento padre para el espaciado habitual entre elementos flex y elimina los márgenes que antes proporcionaban ese mismo espacio. - Repite las comparaciones con relleno desigual y ventana estrecha en ambas direcciones.
Durante la migración, busca las declaraciones físicas antiguas y las abreviaturas posteriores. Las propiedades lógicas y físicas que se asignan al mismo lado participan juntas en la cascada; una propiedad lógica no prevalece automáticamente por ser lógica. Si los demás factores de la cascada son iguales, una declaración posterior de padding puede restablecer el relleno que se había asignado mediante propiedades lógicas. Propiedades y valores lógicos de CSS, nivel 1: propiedades del modelo de caja.
Ten presente también el límite de la dirección. Un componente anidado con su propio dir="ltr" debería usar las asignaciones LTR incluso dentro de una página RTL. En cambio, margin-inline no se hereda, así que asigna a cada componente las declaraciones de espaciado que necesita, en lugar de esperar que se le transfiera el margen de un elemento antecesor. MDN: herencia de direction, MDN: definición formal de margin-inline.
¿Qué límites de los navegadores afectan a este enfoque?
MDN indica que padding-inline y margin-inline están ampliamente disponibles en los navegadores desde abril de 2021. Esto respalda su uso en navegadores de escritorio actuales, pero no garantiza la compatibilidad con todos los navegadores antiguos ni con toda la sintaxis más reciente que aparezca en esas páginas de referencia. Este ejemplo usa longitudes corrientes y auto, sin funciones de tamaño más recientes. MDN: padding-inline, MDN: margin-inline.
Flexbox gap tiene una trayectoria aparte. Safari lo añadió en la versión 14.1; Grid gap ya era compatible desde Safari 12. WebKit señala específicamente que una consulta de características de una propiedad no podía distinguir esos contextos, por lo que @supports (gap: 16px) por sí solo no basta para detectar la compatibilidad con Flexbox gap en versiones antiguas de Safari. WebKit: novedades de WebKit en Safari 14.1.
Si el navegador de destino admite márgenes lógicos, pero no Flexbox gap, añade este fragmento de reemplazo después de las reglas principales de la hoja de estilos. Proporciona espaciado para este componente específico de una sola fila. Úsalo en lugar del espaciado activo con gap, como se muestra; no es una solución general para filas que se ajustan.
/* Optional single-row replacement for Flexbox gap. */
.sample-card {
gap: 0;
}
.sample-card > * + * {
margin-inline-start: var(--space-medium);
}
Si los navegadores tampoco admiten propiedades lógicas, esta alternativa no es suficiente. Usa un navegador actual para la tarea local, o crea y prueba reglas físicas explícitas para LTR y RTL dirigidas al navegador antiguo. Mantén esa decisión específica del navegador separada del diseño principal de la hoja de estilos compartida.
La comparación terminada debería mostrar un contrato coherente: el HTML proporciona la dirección, el CSS compartido proporciona el espaciado y la sangría inicial del componente sigue el inicio en línea. Conserva las dos páginas locales como una prueba de regresión compacta cada vez que cambies el espaciado o el diseño del componente.
Fuentes
- Estándar HTML — tipo de enlace «stylesheet» — WHATWG.
- Atributo global HTML dir — MDN Web Docs.
- Propiedades lógicas para márgenes, bordes y relleno — MDN Web Docs.
- Propiedad CSS padding-inline — MDN Web Docs.
- Propiedad CSS margin-inline — MDN Web Docs.
- Propiedad CSS gap — MDN Web Docs.
- Propiedad CSS flex-direction — MDN Web Docs.
- Módulo 1 de propiedades y valores lógicos de CSS — W3C.
- Novedades de WebKit en Safari 14.1 — WebKit.