¿Qué hace Árabe RTL Web?
Un checklist para páginas árabes que se lean de forma natural, se maqueten correctamente a 375px y nunca mezclen números, URL o palabras en inglés. Aplica cada sección que toque la tarea, luego ejecuta el checklist final.
1. Dirección e idioma
- Elemento raíz:
<html lang="ar" dir="rtl">, escrito en el HTML (no añadido por JavaScript) para que el primer pintado ya sea RTL. - No reemplaces
dircon CSSdirection: rtl. El atributo también controla bidi, controles de formulario y lectores de pantalla. - Un bloque de inglés dentro de una página árabe:
<p lang="en" dir="ltr">. Texto escrito por usuarios (nombres, comentarios, chat):dir="auto".
2. Maquetación con propiedades lógicas
Las propiedades físicas izquierda/derecha nunca se invierten. Usa propiedades lógicas para que una misma hoja de estilos funcione en ambas direcciones.
| Evitar | Usar |
|---|---|
margin-left, padding-right | margin-inline-start, padding-inline-end |
left: 0, right: 0 | inset-inline-start: 0, inset-inline-end: 0 |
text-align: left | text-align: start |
border-left | border-inline-start |
border-top-left-radius | border-start-start-radius |
float: left | float: inline-start |
- Flexbox y grid ya siguen
dir: en RTL,flex-direction: rowcomienza por la derecha. No añadasrow-reversepara "arreglar" RTL. transform: translateX(),background-positiony los desplazamientos de box-shadow son físicos. Inviértelos con:dir(rtl)o[dir="rtl"]cuando sea necesario.- Tailwind:
ms-*,me-*,ps-*,pe-*,start-*,end-*,text-starty las variantesrtl:/ltr:.
3. Fuentes web árabes
- Elige una familia diseñada para árabe (IBM Plex Sans Arabic, Noto Naskh Arabic, Noto Sans Arabic, Tajawal, Cairo, Almarai, Readex Pro). Reserva las caras decorativas como Aref Ruqaa solo para encabezados.
- Autoaloja archivos WOFF2: sin peticiones a terceros, funciona sin conexión, nada se filtra a una CDN de fuentes. Verifica la licencia (OFL permite autoalojamiento).
- Usa
font-display: swapy divide los archivos árabes y latinos conunicode-range, para que cada página descargue solo lo que usa:
@font-face { font-family: 'Plex'; font-weight: 400; font-display: swap;
src: url(plex-400-ar.woff2) format('woff2');
unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+200C-200E, U+FB50-FDFF, U+FE70-FEFC; }
@font-face { font-family: 'Plex'; font-weight: 400; font-display: swap;
src: url(plex-400-lat.woff2) format('woff2');
unicode-range: U+0000-00FF, U+2000-206F; }
body { font: 400 17px/1.75 'Plex', 'Segoe UI', Tahoma, sans-serif; }
- El árabe necesita una altura de línea mayor (1.6 a 1.8) para los diacríticos y descendentes, y un tamaño ligeramente mayor que el texto latino.
- Nunca uses
letter-spacingen árabe (rompe la unión de letras). No usestext-transform, ni cursivas falsas. Evitatext-align: justifyen columnas estrechas. - No estires las palabras con tatweel (U+0640). Rompe la búsqueda y el copiado y pegado.
4. Bidi: números, URLs e inglés dentro de árabe
El algoritmo bidi de Unicode reordena los caracteres neutros junto a números y texto latino. Dos errores clásicos en un párrafo RTL:
- El teléfono
+966 55 123 4567muestra sus grupos de dígitos en orden inverso:4567 123 55 +966. - El intervalo horario
10:00 - 12:00se muestra como12:00 - 10:00.
Correcciones:
<bdi>alrededor de valores insertados de dirección desconocida:مرحبًا <bdi>${userName}</bdi>، أهلًا بك.dir="ltr"en valores que siempre son LTR:<span dir="ltr">+966 55 123 4567</span>, URLs, correos electrónicos, rutas de archivos, IBAN,<code dir="ltr">,<pre dir="ltr">.- CSS para patrones repetidos:
.num, .code { unicode-bidi: isolate; }. Nota que<bdi>aísla por defecto. - Campos de entrada para correo, URL y teléfono:
<input type="email" dir="ltr">. - Cuando el marcado es imposible (título del documento, notificaciones, cadenas simples), envuelve con aislantes de Unicode: FSI U+2068 ... PDI U+2069, o LRI U+2066 ... PDI para texto conocido LTR.
5. Dígitos: un sistema por página
- Elige latinos
0-9o arábigo-indios٠-٩(U+0660 a U+0669) y úsalos en todas partes de la página, incluyendo tablas, gráficos y fechas. - Mezclar confunde a los lectores (una tabla con ambos parece un error), rompe la búsqueda ("15" no coincide con "١٥"), el ordenamiento y el copiado y pegado en hojas de cálculo.
- Los dígitos persas
۰-۹(U+06F0 a U+06F9) son puntos de código diferentes. No los mezcles. - Los valores predeterminados de
Intldifieren según la configuración regional y la versión del motor: en Node 24,ar-SAformatea con dígitos arábigo-indios mientras quearsimple da latinos. Establece explícitamente el sistema de numeración:new Intl.NumberFormat('ar-SA-u-nu-latn')o'ar-SA-u-nu-arab'. - Con dígitos arábigo-indios, el separador decimal es
٫(U+066B) y el separador de miles es٬(U+066C). - Peligro real: un punto medio (U+00B7) usado como separador junto a dígitos arábigo-indios se parece al cero arábigo-indio (U+0660), que también es un punto pequeño. "12, separador, 3" se lee entonces como "1203". Separa con la coma árabe «،», una barra oblicua o espacio adicional (CSS
gap) en su lugar.
6. Puntuación árabe
- Usa
،(U+060C),؛(U+061B) y؟(U+061F), no,;?. El punto final y!son compartidos. - Sin espacio antes del signo de puntuación, un espacio después: «كيف حالك؟» no «كيف حالك ؟».
- Elige un estilo de comillas («...» o "...") por página.
7. Iconos y espejado
Refleja los iconos que muestran dirección o secuencia: flechas atrás y siguiente, cheurones en listas y migas de pan, steppers y dirección de progreso, "enviar", sangría de texto e iconos de lista.
No reflejes: logotipos y marcas, controles multimedia (reproducir, rebobinar, avanzar rápido), relojes y temporizadores, marcas de verificación, fotos e iconos que contengan letras latinas o dígitos.
:dir(rtl) .icon-dir { transform: scaleX(-1); } /* clase opt-in, nunca global */
8. Entrada de números desde teclados árabes
- Prefiere
<input inputmode="decimal" autocomplete="off">sobretype="number". El valor de un input numérico solo es válido con dígitos ASCII, por lo que los dígitos arábigo-indios pueden devolverse como una cadena vacía; además añade spinners. - Los usuarios escriben
٠-٩, el separador decimal árabe٫y a veces dígitos persas. Normaliza antes deNumber():
function parseArabicNumber(raw) {
const s = String(raw ?? '').trim()
.replace(/[٠-٩]/g, (d) => d.charCodeAt(0) - 0x0660)
.replace(/[۰-۹]/g, (d) => d.charCodeAt(0) - 0x06F0)
.replace(/٫/g, '.')
.replace(/٬/g, '');
if (s === '') return null; // Number('') es 0, así que primero verifica vacío
const n = Number(s);
return Number.isFinite(n) ? n : NaN;
}
parseArabicNumber('٩٥٫٥'); // 95.5
- Decide cómo se trata una
,escrita (marca decimal o separador de miles) y documéntalo. - Muestra mensajes de validación en árabe, establece
aria-invalidy enlaza el mensaje conaria-describedby. - Ordena nombres árabes con
new Intl.Collator('ar').compare. Para búsqueda, normaliza las formas de alef (أ إ آ a ا), elimina tashkeel y tatweel tanto en la consulta como en los datos.
9. Pruebas
- Prueba a 375px de ancho (y a 320px si es posible). Confirma que
document.documentElement.scrollWidth <= innerWidth. - Prueba palabras árabes largas con letras unidas, como «والمستشفيات» o «باستخداماتها», en encabezados y botones. Usa
overflow-wrap: anywhereen encabezados y tarjetas, ymin-width: 0en hijos de flex y grid. - Usa contenido árabe real con mezcla de inglés y números, no lorem ipsum.
- Verifica en Safari en iOS y Chrome en Android, además de zoom al 200% y orden de enfoque del teclado (Tab se mueve de derecha a izquierda).
10. El problema de [hidden]
El atributo hidden es solo un display: none del agente de usuario. Cualquier regla del autor como .card { display: flex } lo sobrescribe, por lo que el.hidden = true deja de funcionar silenciosamente. Añade esto a la hoja de estilos base:
[hidden] { display: none !important; }
Checklist final
-
<html lang="ar" dir="rtl">en el código fuente - No quedan propiedades físicas izquierda/derecha en el nuevo CSS
- Fuente árabe autoalojada,
font-display: swap, división porunicode-range - Números de teléfono, URLs, código y nombres de usuario aislados
- Un solo sistema de dígitos; sin punto medio junto a dígitos arábigo-indios
- Puntuación árabe, sin espacio antes de ella
- Solo iconos direccionales reflejados
- Los campos numéricos aceptan
٠-٩y٫ - Sin desplazamiento horizontal a 375px; palabras largas se envuelven
-
[hidden] { display: none !important; }presente