局部加dir不能只靠父级继承,因为unicode双向算法(uba)需每个混排片段有明确方向上下文,不依赖继承;表单控件、表格单元格、动态内容等必须显式声明dir或使用隔离。

局部加 dir 为什么不能只靠父级继承
很多开发者给 就以为所有子元素自动适配,结果阿拉伯语段落里的英文 URL 被拆成两行、括号反向、数字显示为 "321"。这不是渲染 bug,而是 Unicode 双向算法(UBA)没被正确触发——UBA 需要每个混排片段有明确的方向上下文,不是靠继承就能隔离的。
常见错误现象包括:<p dir="rtl">نص عربي https://example.com</p> 中 URL 仍被 RTL 环境“拖拽”变形;<input> 里输入 "أحمد123",退格键从右往左删错位置;<select></select> 下拉项文字顺序正常,但箭头图标还在右边。
<table> 或 <code><tr> 上设 <code>dir无效,必须落到每个<td> 或 <code><th> 上 <li> <code><input type="text">和<textarea></textarea>必须显式加dir="rtl"或dir="auto",否则光标行为仍按文档根方向走- 服务端渲染(SSR)中若初始 HTML 没带
dir,客户端 hydration 后补上也不会重算已渲染文本的方向 - 正确写法:
<bdi>{{username}}</bdi>—— 自动识别强方向字符并隔离处理 - 错误写法:
<span dir="auto">{{username}}</span>—— 首字符非强方向时直接失效 - 危险写法:
<bdo dir="rtl">{{username}}</bdo>—— 强制翻转,把"123"显示成"321",仅适合调试 - 对已知 LTR 片段(如 URL、邮箱、版本号),直接用
<span dir="ltr">https://example.com</span>更简明 -
<input type="text" dir="rtl">和<textarea dir="rtl"></textarea>必须显式设置,否则用户输入阿拉伯语时行为异常 -
<select></select>的下拉项方向由其自身dir决定,需在<option></option>或容器上加dir="rtl" -
<td dir="rtl">مرحبا</td>和<td dir="ltr">Hello</td>可共存于同一行,互不干扰 -
<label></label>文本方向应与对应控件一致,避免视觉与逻辑脱节(例如<label for="name">الاسم</label><input id="name" dir="rtl">) - 必须主动触发重排:读取一次
offsetHeight或getComputedStyle(document.documentElement).direction -
<textarea></textarea>的placeholder不会随dir动态变化,需手动设置placeholder属性或用 JS 替换 - CSS
:dir(rtl)伪类在 Safari ≤17.3 中不支持,需降级为[dir="rtl"]属性选择器 - 第三方 UI 库(如 MUI、Bootstrap)依赖
的dir生成逻辑类名(ms-2→me-2),切换后需确保样式表已加载并重新计算
<bdi></bdi> 是混合文本唯一靠谱的局部隔离方案
当文本来自 API(如用户名、搜索词、评论内容),且可能混排("أحمد123"、"Hello عالم"、"v2.4.1 (الإصدار)"),dir="auto" 在生产环境基本不可用:首字符是数字、ASCII 字母、中文或空格时,一律 fallback 到 ltr;Safari ≤17.3 对带变音符号的阿拉伯字符识别也不稳定。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
<bdi></bdi> 创建独立 Bidi 隔离上下文,不污染父级方向,所有现代浏览器支持良好,且无需 polyfill。
表单控件和表格单元格必须单独声明 dir
表单和表格是局部方向最容易漏掉的关键区域。<input> 不继承 <div dir="rtl"> 的方向,光标起始、退格逻辑、双击选词全按文档根方向运行;<code><table> 容器本身不参与文本排版,方向不向下继承,<code><tr> 加 <code>dir 也无效果。
动态切换 dir 后哪些行为不会自动更新
执行 document.documentElement.dir = "rtl" 后,部分浏览器(尤其是旧版 Safari)不会立即重排,导致 <input> 光标仍在左边、getSelection().getRangeAt(0) 返回的偏移量错乱、Flex 主轴起点未翻转。
dir,而是判断哪一层该继承、哪一层该隔离、哪一层该显式覆盖——多数方向问题都出在“以为设了 dir="rtl" 就结束了”,结果输入框光标还在左边,或者阿拉伯语里的英文 URL 被拆成两行还反向换行。










