arabic-rtl-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Arabic RTL Best Practices

阿拉伯语RTL布局最佳实践

Instructions

操作指南

Step 1: Set Up Document Direction

步骤1:设置文档方向

Always start with the HTML attribute (not just CSS):
html
<html lang="ar" dir="rtl">
This tells browsers, screen readers, and CSS to use RTL as the base direction.
始终从HTML属性开始设置(不要仅依赖CSS):
html
<html lang="ar" dir="rtl">
这会告知浏览器、屏幕阅读器和CSS以RTL作为基础方向。

Step 2: Use CSS Logical Properties

步骤2:使用CSS逻辑属性

NEVER use physical directional properties for layout:
Physical (avoid)Logical (use)
margin-left
margin-inline-start
margin-right
margin-inline-end
padding-left
padding-inline-start
padding-right
padding-inline-end
border-left
border-inline-start
text-align: left
text-align: start
text-align: right
text-align: end
float: left
float: inline-start
left: 10px
inset-inline-start: 10px
This ensures the layout automatically mirrors in RTL mode.
绝对不要使用物理方向属性进行布局:
物理属性(避免使用)逻辑属性(推荐使用)
margin-left
margin-inline-start
margin-right
margin-inline-end
padding-left
padding-inline-start
padding-right
padding-inline-end
border-left
border-inline-start
text-align: left
text-align: start
text-align: right
text-align: end
float: left
float: inline-start
left: 10px
inset-inline-start: 10px
这确保布局在RTL模式下自动镜像。

Step 3: Handle Bidirectional Text

步骤3:处理双向文本

When mixing Arabic and English/numbers:
css
/* Isolate embedded LTR content */
.ltr-content {
  unicode-bidi: isolate;
  direction: ltr;
}

/* For inline elements with mixed content */
.bidi-override {
  unicode-bidi: bidi-override;
}
Common bidi issues:
  • Phone numbers appearing reversed: Wrap in
    <bdo dir="ltr">
  • Punctuation at wrong end of sentence: Use
    unicode-bidi: isolate
  • URLs/emails in Arabic text: Wrap in
    <span dir="ltr">
混合阿拉伯语与英语/数字内容时:
css
/* 隔离嵌入的LTR内容 */
.ltr-content {
  unicode-bidi: isolate;
  direction: ltr;
}

/* 用于包含混合内容的行内元素 */
.bidi-override {
  unicode-bidi: bidi-override;
}
常见双向文本问题:
  • 电话号码显示颠倒:用
    <bdo dir="ltr">
    包裹
  • 标点符号出现在句子错误的一端:使用
    unicode-bidi: isolate
  • 阿拉伯语文本中的URL/邮箱:用
    <span dir="ltr">
    包裹

Step 4: Arabic Typography

步骤4:阿拉伯语排版

Recommended font stack:
css
font-family: 'Tajawal', 'Assistant', 'Rubik', 'Noto Sans Arabic', sans-serif;
Typography settings:
css
body[dir="rtl"] {
  font-size: 16px; /* Arabic needs slightly larger than Latin */
  line-height: 1.7;
  letter-spacing: normal; /* NEVER add letter-spacing for Arabic */
  word-spacing: 0.05em; /* Slight word spacing improves readability */
}
推荐字体栈:
css
font-family: 'Tajawal', 'Assistant', 'Rubik', 'Noto Sans Arabic', sans-serif;
排版设置:
css
body[dir="rtl"] {
  font-size: 16px; /* 阿拉伯语字体需要比拉丁语系字体稍大 */
  line-height: 1.7;
  letter-spacing: normal; /* 绝对不要为阿拉伯语添加字母间距 */
  word-spacing: 0.05em; /* 轻微的单词间距可提升可读性 */
}

Step 5: Framework-Specific Setup

步骤5:框架专属配置

Tailwind CSS RTL (v3.3+ / v4):
Prefer logical property utilities over
rtl:
/
ltr:
variants:
Physical classLogical classCSS property
ml-4
ms-4
margin-inline-start
mr-4
me-4
margin-inline-end
pl-4
ps-4
padding-inline-start
pr-4
pe-4
padding-inline-end
left-4
start-4
inset-inline-start
right-4
end-4
inset-inline-end
rounded-l-lg
rounded-s-lg
border-start-start-radius
+
border-end-start-radius
rounded-r-lg
rounded-e-lg
border-start-end-radius
+
border-end-end-radius
html
<!-- Bad: requires two classes, breaks without dir attribute -->
<div class="ltr:ml-4 rtl:mr-4">...</div>

<!-- Good: single class, auto-mirrors based on dir -->
<div class="ms-4">...</div>
Reserve
rtl:
/
ltr:
variants only for cases logical properties cannot handle (e.g., directional icons, transforms).
Tailwind v4 note: v4 uses CSS-first configuration (
@import "tailwindcss"
in CSS) instead of
tailwind.config.js
. Logical utilities work identically in both v3 and v4.
Next.js App Router:
tsx
// app/layout.tsx
import { Tajawal } from 'next/font/google';

const tajawal = Tajawal({
  subsets: ['arabic', 'latin'],
  weight: ['400', '500', '700'],
});

export default async function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale } = await params;
  const isRTL = locale === 'he';

  return (
    <html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}>
      <body className={tajawal.className}>{children}</body>
    </html>
  );
}
next/font
self-hosts the font (no external Google Fonts requests, zero layout shift).
React with MUI:
jsx
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import rtlPlugin from 'stylis-plugin-rtl';
import { prefixer } from 'stylis';

const cacheRtl = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

const theme = createTheme({ direction: 'rtl' });
Tailwind CSS RTL(v3.3+ / v4):
优先使用逻辑属性工具类,而非
rtl:
/
ltr:
变体:
物理类名逻辑类名CSS属性
ml-4
ms-4
margin-inline-start
mr-4
me-4
margin-inline-end
pl-4
ps-4
padding-inline-start
pr-4
pe-4
padding-inline-end
left-4
start-4
inset-inline-start
right-4
end-4
inset-inline-end
rounded-l-lg
rounded-s-lg
border-start-start-radius
+
border-end-start-radius
rounded-r-lg
rounded-e-lg
border-start-end-radius
+
border-end-end-radius
html
<!-- 不推荐:需要两个类名,无dir属性时会失效 -->
<div class="ltr:ml-4 rtl:mr-4">...</div>

<!-- 推荐:单个类名,根据dir属性自动镜像 -->
<div class="ms-4">...</div>
仅在逻辑属性无法处理的场景(如方向图标、变换)中保留
rtl:
/
ltr:
变体。
Tailwind v4注意事项: v4采用CSS优先配置(在CSS中
@import "tailwindcss"
),而非
tailwind.config.js
。逻辑工具类在v3和v4中的工作方式完全相同。
Next.js App Router:
tsx
// app/layout.tsx
import { Tajawal } from 'next/font/google';

const tajawal = Tajawal({
  subsets: ['arabic', 'latin'],
  weight: ['400', '500', '700'],
});

export default async function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale } = await params;
  const isRTL = locale === 'he';

  return (
    <html lang={locale} dir={isRTL ? 'rtl' : 'ltr'}>
      <body className={tajawal.className}>{children}</body>
    </html>
  );
}
next/font
会自托管字体(无外部Google Fonts请求,零布局偏移)。
React搭配MUI:
jsx
import { createTheme, ThemeProvider } from '@mui/material/styles';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
import rtlPlugin from 'stylis-plugin-rtl';
import { prefixer } from 'stylis';

const cacheRtl = createCache({
  key: 'muirtl',
  stylisPlugins: [prefixer, rtlPlugin],
});

const theme = createTheme({ direction: 'rtl' });

Step 6: Common Pitfalls to Check

步骤6:需检查的常见陷阱

  1. Icons with directional meaning (arrows, back buttons) -- mirror them
  2. Progress bars -- should fill from right to left
  3. Sliders/carousels -- swipe direction should reverse
  4. Form labels -- should be right-aligned
  5. Breadcrumbs -- separator direction should reverse
  6. Tables -- header alignment and cell alignment
  7. Charts -- x-axis may need to reverse for Arabic readers
  1. 具有方向含义的图标(箭头、返回按钮)——需镜像处理
  2. 进度条——应从右向左填充
  3. 滑块/轮播组件——滑动方向需反转
  4. 表单标签——应右对齐
  5. 面包屑导航——分隔符方向需反转
  6. 表格——表头和单元格对齐方式
  7. 图表——阿拉伯语用户可能需要反转X轴

Examples

示例

Example 1: Convert LTR Component to RTL

示例1:将LTR组件转换为RTL兼容

User says: "Make this card component work in Arabic"
Before (LTR-only):
css
.card {
  margin-left: 16px;
  padding-right: 12px;
  text-align: left;
  border-left: 3px solid blue;
}
After (RTL-compatible):
css
.card {
  margin-inline-start: 16px;
  padding-inline-end: 12px;
  text-align: start;
  border-inline-start: 3px solid blue;
}
With Tailwind, replace
ml-4 pr-3 text-left border-l-4
with
ms-4 pe-3 text-start border-s-4
.
用户需求:“让这个卡片组件适配阿拉伯语”
转换前(仅支持LTR):
css
.card {
  margin-left: 16px;
  padding-right: 12px;
  text-align: left;
  border-left: 3px solid blue;
}
转换后(支持RTL):
css
.card {
  margin-inline-start: 16px;
  padding-inline-end: 12px;
  text-align: start;
  border-inline-start: 3px solid blue;
}
使用Tailwind时,将
ml-4 pr-3 text-left border-l-4
替换为
ms-4 pe-3 text-start border-s-4

Example 2: Bidi Text Issue

示例2:双向文本问题

User says: "Numbers are showing backwards in my Arabic text"
html
<!-- Wrong: phone number renders as 0544-123-050 -->
<p>התקשרו אלינו: 050-321-4450</p>

<!-- Correct: isolate the LTR content -->
<p>התקשרו אלינו: <span dir="ltr">050-321-4450</span></p>
Use
unicode-bidi: isolate
on the containing span for CSS-only solutions.
用户需求:“阿拉伯语文本中的数字显示颠倒了”
html
<!-- 错误:电话号码显示为0544-123-050 -->
<p>התקשרו אלינו: 050-321-4450</p>

<!-- 正确:隔离LTR内容 -->
<p>התקשרו אלינו: <span dir="ltr">050-321-4450</span></p>
对于纯CSS解决方案,在包含元素上使用
unicode-bidi: isolate

Example 3: Tailwind RTL Navigation

示例3:Tailwind RTL导航

User says: "My sidebar is on the wrong side in Arabic"
html
<!-- Bad: sidebar stuck on left -->
<aside class="fixed left-0 w-64">...</aside>

<!-- Good: sidebar auto-mirrors -->
<aside class="fixed start-0 w-64">...</aside>

<!-- Back arrow icon still needs rtl: variant -->
<button class="rtl:rotate-180">
  <ArrowLeftIcon />
</button>
用户需求:“我的侧边栏在阿拉伯语模式下位置错误”
html
<!-- 错误:侧边栏固定在左侧 -->
<aside class="fixed left-0 w-64">...</aside>

<!-- 正确:侧边栏自动镜像 -->
<aside class="fixed start-0 w-64">...</aside>

<!-- 返回箭头图标仍需使用rtl:变体 -->
<button class="rtl:rotate-180">
  <ArrowLeftIcon />
</button>

Bundled Resources

配套资源

References

参考资料

  • references/css-logical-properties.md
    — Complete physical-to-logical CSS property mapping table (margin, padding, border, positioning, text alignment, sizing) plus Arabic font stack recommendations for sans-serif, serif, and monospace. Consult when converting any LTR stylesheet to RTL-compatible logical properties or choosing Arabic web fonts.
  • references/css-logical-properties.md
    — 完整的物理属性到逻辑属性的CSS映射表(边距、内边距、边框、定位、文本对齐、尺寸),以及适用于无衬线、衬线和等宽字体的阿拉伯语字体栈推荐。转换任何LTR样式表为RTL兼容的逻辑属性,或选择阿拉伯语网页字体时可参考此文档。

Gotchas

注意事项

  • CSS
    text-align: left
    is wrong for Arabic. Use
    text-align: start
    which respects the document direction. Agents frequently hardcode
    left
    alignment in CSS.
  • margin-left
    and
    padding-right
    do not flip in RTL mode. Use CSS logical properties:
    margin-inline-start
    and
    padding-inline-end
    instead. Agents trained on LTR CSS will generate physical properties.
  • Flexbox
    row
    direction auto-reverses in RTL, but
    row-reverse
    also reverses, causing a double-flip back to LTR order. Agents may add
    row-reverse
    thinking it creates RTL, but it actually creates LTR within an RTL context.
  • Phone numbers, credit card numbers, and code snippets must remain LTR even inside RTL containers. Wrap them in
    <bdo dir="ltr">
    or use
    direction: ltr
    on the containing element. Agents often let these inherit RTL.
  • CSS
    text-align: left
    不适用于阿拉伯语。应使用
    text-align: start
    ,它会遵循文档方向。AI助手常在CSS中硬编码
    left
    对齐方式。
  • margin-left
    padding-right
    在RTL模式下不会自动翻转。请使用CSS逻辑属性:
    margin-inline-start
    padding-inline-end
    。基于LTR CSS训练的AI助手会生成物理属性。
  • Flexbox的
    row
    方向在RTL中会自动反转,但
    row-reverse
    也会反转,导致双重翻转回到LTR顺序。AI助手可能会添加
    row-reverse
    以为这能实现RTL,但实际上它会在RTL环境中创建LTR顺序。
  • 电话号码、信用卡号和代码片段即使在RTL容器中也必须保持LTR方向。用
    <bdo dir="ltr">
    包裹它们,或在包含元素上设置
    direction: ltr
    。AI助手常让这些内容继承RTL方向。

Reference Links

参考链接

SourceURLWhat to Check
MDN CSS Logical Propertieshttps://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_valuesFull property list, browser support tables
Tailwind CSS RTL Supporthttps://tailwindcss.com/docs/hover-focus-and-other-states#rtl-support
rtl:
/
ltr:
variant syntax
Tailwind Logical Propertieshttps://tailwindcss.com/docs/margin#logical-properties
ms-*
,
me-*
,
ps-*
,
pe-*
utilities
Google Fonts Arabichttps://fonts.google.com/?subset=arabicAvailable Arabic font families
W3C Internationalizationhttps://www.w3.org/International/articles/inline-bidi-markup/Unicode bidi algorithm, markup best practices
来源URL查看内容
MDN CSS逻辑属性https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_logical_properties_and_values完整属性列表、浏览器支持表
Tailwind CSS RTL支持https://tailwindcss.com/docs/hover-focus-and-other-states#rtl-support
rtl:
/
ltr:
变体语法
Tailwind逻辑属性https://tailwindcss.com/docs/margin#logical-properties
ms-*
,
me-*
,
ps-*
,
pe-*
工具类
Google Fonts阿拉伯语https://fonts.google.com/?subset=arabic可用的阿拉伯语字体家族
W3C国际化https://www.w3.org/International/articles/inline-bidi-markup/Unicode双向算法、标记最佳实践

Troubleshooting

故障排查

Error: "Text alignment looks wrong"

错误:“文本对齐显示异常”

Cause: Using
text-align: left
instead of
text-align: start
Solution: Replace all
left
/
right
in text-align with
start
/
end
.
原因:使用
text-align: left
而非
text-align: start
解决方案:将所有text-align中的
left
/
right
替换为
start
/
end

Error: "Layout not mirroring"

错误:“布局未镜像”

Cause: Using physical margin/padding instead of logical properties Solution: Replace all
margin-left
/
margin-right
with
margin-inline-start
/
margin-inline-end
.
原因:使用物理边距/内边距而非逻辑属性 解决方案:将所有
margin-left
/
margin-right
替换为
margin-inline-start
/
margin-inline-end