背景
最近在公司接到一个需求,是对公司的一个产品进行阿拉伯适配。之前也接过类似的需求,什么西班牙语,俄罗斯语啦,这些无非就是对语言进行翻译,(因为公司原有的产品就已经使用了i18n进行了国际化适配了),但是仔细了解过后发现阿拉伯的适配和之前的方案有很大的不同。
这主要是由于阿拉伯国家的阅读习惯的不同导致的。大多数国家的阅读习惯都是是从左往右的,但阿拉伯的阅读习惯却是从右往左的。
这也就导致了阿拉伯国家的页面特点:
- 排版是从右往左。
- 文本是向右对齐且从右往左阅读,文本方向始终和语言保持一致,比如数字(电话号码、时间)
- 方向性图标和我们的方向相反,但其他的图标和图片不会镜像
所以要适配阿拉伯国际,不仅仅在于它文案的适配,更多的是在于其语言习惯的变化。
如何适配页面呢?
目前市面上最常见的适配方案有两种,一种是"通过transform进行镜像翻转",另一种是“在html标签上直接添加dir="rtl"来改变页面的排版方向”。下面我们来详细分析分析两种方案的利弊吧!
方案一:通过transform进行镜像翻转
在阿拉伯语页面上,我们可以对全局应用 transform: scaleX(-1) 来实现页面的水平翻转。这样可以快速解决布局镜像的问题。然后,再对于不需要翻转的内容,进行二次翻转。这里我们可以使用一个特定的类(如 .not-flip)来包裹,并再次应用 transform: scaleX(-1) 来进行反向翻转,从而保持内容的正常显示。
在阿拉伯语页面上添加上全局翻转:
/* 全局应用水平翻转 */
html[lang="ar"] {
transform: scaleX(-1);
}
/* 对不需要翻转的内容进行反向翻转 */
html[lang="ar"] .not-flip {
transform: scaleX(-1);
}
我们可以将翻转相关的样式单独放在一个CSS文件中,并通过条件加载或动态添加CSS类的方式来应用,如果需要动态处理,可以使用JavaScript来检测语言并应用或移除翻转样式。
示例:
// 等待整个文档内容完全加载后再执行
document.addEventListener("DOMContentLoaded", function() {
// 检查文档的根元素(html)的语言是否为阿拉伯语
if (document.documentElement.lang === "ar") {
// 如果是阿拉伯语,将根元素的水平缩放设置为-1,实现水平翻转
document.documentElement.style.transform = "scaleX(-1)";
// 选择所有带有类名 "not-flip" 的元素
const notFlipElements = document.querySelectorAll(".not-flip");
// 遍历所有选中的 "not-flip" 元素
notFlipElements.forEach(function(element) {
// 将每个 "not-flip" 元素的水平缩放设置为-1,恢复正常显示
element.style.transform = "scaleX(-1)";
});
}
});
处理后的效果如下:
如上图所示,通过翻转解决了布局问题,但文字和图像也被翻转。为了解决这个问题,对于不需要翻转的内容(如文字、非指向性图像),需要进行二次翻转。
优缺点
优点: 无需修改js逻辑,只需要处理css。
缺点: 首次翻转只需要处理根节点,而二次翻转则需要处理所有不需要翻转的元素,工作量较大。
方案二:在html标签上直接添加dir="rtl"
在html标签上直接添加dir="rtl"的作用和direction: rtl样式的效果是一样,它可以改变我们网站的整体布局,实现从右到左(RTL)的页面布局,这种方式会改变文本、表格列和水平溢出的方向,但不会改变文字和图片的显示方向
html标签属性添加默认值dir="ltr", 例如如: <html dir="rtl">
处理后的效果如下:
在设置页面为RTL(从右到左)布局后,我们可以发现UI并没有完全兼容RTL场景。具体观察到以下情况:
- 文本对齐:
- 如果元素没有预先定义
text-align,那么该元素的文本会从左对齐变成右对齐。 - 如果设置了
left或center,则direction的设置不会对其产生影响。
- 如果元素没有预先定义
- 布局方向:
inline-block、flex、table、grid的布局方向会受到影响。absolute、fixed、float、margin、padding等属性不会受到影响。
为了确保页面在RTL布局时能够正常呈现,我们需要对未被影响的属性进行调整。目前有以下三种解决方案:
使用CSS逻辑属性与逻辑值
CSS逻辑属性和逻辑值使用抽象术语块向和行向描述其流向:
- 块向尺度(block):垂直于文本流向的尺寸。
- 行向尺度(inline):与行内文本流向平行的方向上的尺度。
在LTR(从左到右)布局时:(把css样式代码从物理特性修改成逻辑性质)
逻辑值
详细的对照可以看下面这两张图
Physical Property(物理特性)
Logical Property (逻辑性质)
通过改写为逻辑属性,可以同时适配LTR和RTL布局,无需专门为RTL布局进行适配。例如:将 margin-left 改写成 margin-inline-start将 left: 0; 改写成 inline-start: 0;我们只需要全局替换需要调整的行向尺度的CSS属性即可。
使用开源工具 postcss-rtl
在GitHub上可以找到 postcss-rtl 开源插件,它的原理是对CSS文件进行处理,将CSS属性中的 left 改为 right,right 改为 left,从而自动适配RTL布局。
我们需要注意的是
- 浏览器兼容性:
使用逻辑属性时需要考虑浏览器的兼容性问题。对于B端项目,可以考虑使用逻辑属性,因为这些项目通常在兼容性较好的环境中运行。
- 代码处理范围:
开发者只能处理本地代码,无法处理npm包中的代码。因此,使用 postcss-rtl 插件可以自动处理所有CSS文件,包括本地代码和第三方库的样式。
vue引入示例
webpack中引入插件postcss-rtl(opens new window)
vue-cli2脚手架配置: 安装依赖npm install postcss-loader postcss-rtl --save-dev
在 webpack 配置文件(例如 cloud/build/utils.js)中添加 postcss-loader 和 postcss-rtl 插件。
// 定义一个 postcssLoader 对象,用于配置 postcss-loader
var postcssLoader = {
loader: 'postcss-loader', // 指定使用 postcss-loader
options: {
postcssOptions: { // 配置 postcss 的选项
plugins: [
[ 'postcss-rtl', {} ] // 添加阿拉伯语右排布局插件 postcss-rtl
]
}
}
}
// 生成用于 extract text plugin 的加载器字符串的函数
function generateLoaders(loader, loaderOptions) {
// 初始化一个包含 cssLoader、autoprefixerLoader 和 postcssLoader 的加载器数组
var loaders = [cssLoader, autoprefixerLoader, postcssLoader]
// 如果传入了 loader 参数,则将相应的 loader 配置添加到加载器数组中
if (loader) {
loaders.push({
loader: loader + '-loader', // 动态指定 loader 名称,例如 'sass-loader'
options: Object.assign({}, loaderOptions, { // 合并传入的 loaderOptions 和 sourceMap 选项
sourceMap: options.sourceMap // 将 sourceMap 选项添加到 loader 配置中
})
})
}
// 省略其他代码...
...
}
vue-cli3脚手架配置: 安装依赖yarn add postcss-rtl -D
在webpack中(apps-moblie-docs/vue.config.js)文件里添加postcss-rtl插件
css: {
// 是否启用 sourceMap,根据 isProduction 变量确定
sourceMap: !isProduction,
// 加载器选项
loaderOptions: {
// PostCSS 相关配置
postcss: {
// PostCSS 插件列表
plugins: [
// 添加阿拉伯语右排布局插件 postcss-rtl
require('postcss-rtl')()
]
}
}
}
在app.vue入口里添加根据语言判断修改html的dir属性,比如: document.documentElement.setAttribute('dir', this.$i18n.locale === 'ar' ? 'rtl' : 'ltr')
方向的图标处理:
// 适配右排布局图标方向
[dir=rtl]{
.components-icons{
&.components-icons-back{
&:before {
display: inline-block;
transform: scaleX(-1);
}
}
}
}
- 元素拼接的语句的处理:
// 适配右排布局
[dir=rtl] {
.yun-row__desc {
direction: ltr;
display: inline-flex;
justify-content: flex-end;
}
}
使用[dir="rtl"]和[dir="ltr"]对不能自动适配的属性进行适配
示例:
[dir="rtl"].box {
//选择所有具有 dir="rtl" 属性并且类名为 .box 的元素。
float: right;
margin-right: 0;
margin-left: 16px;
}
[dir="ltr"] .box {
float: left;
margin-right: 16px;
margin-left: 0;
}
优点:是工作量减少,代码入侵减少;
缺点:是需要处理方向性的图标的方向和被元素拼接的语句(断句)。
这里推荐几个自动将 CSS 从 LTR 转换为 RTL 的工具
-
CSS 转换包
-
在线转换工具
结论
| 方案 | 浏览器支持 | 优点 | 缺点 | 适用场景 | 样式体积影响 |
|---|---|---|---|---|---|
direction: rtl; | CSS2 属性,所有现代浏览器均支持,包括 IE9+ | - 原生支持:无需构建或工具链,直接生效 - 简单一行即可切换整个容器或文档为 RTL 布局 | - 会影响所有子元素排版顺序,需手动在 Flex 或 inline-block 布局中做兼容性调整 - 无法自动翻转背景图、图标等非文本内容 | 全局或容器级页面 RTL 转换 | 无 |
transform: scaleX(-1); | CSS3 变换,自 2015 年起所有主流浏览器均支持 | - 极简方案:一行 transform 即可镜像整个元素 - 兼容旧布局,尤其是非 Flex/Grid 场景 | - 文本、图标和背景均被镜像,需针对内容单独做反向补偿 - 可访问性与选中文本逻辑可能受影响 | 小范围图标或单个组件镜像 | 无 |
| CSS 逻辑属性 (如 margin-inline-start) | CSS Logical Properties,Chrome/Firefox/Safari 支持良好,IE/Edge Legacy 兼容性较差 | - 原生逻辑:根据 direction 自动映射物理边距/填充/边框 - 不改动 DOM 结构,与 Flex/Grid 协同良好 | - 部分属性(如 background-position)仍需手动处理 - 在旧版浏览器需 polyfill 或降级方案 | 需要细粒度、可维护的多方向布局 | 极小(仅逻辑属性定义) |
| CSS‑in‑JS (Emotion, Styled‑Components) | 由 JS 运行时插入样式,所有现代浏览器均支持 | - 与组件高度耦合,可在 JS 中动态生成 RTL 样式 - 支持主题化、复用 mixin,运行时即时切换 | - 需全盘采用 CSS‑in‑JS,学习与维护成本高 - 运行时解析插入样式存在性能开销,可读性与静态分析困难 | 动态主题或按组件懒加载样式 | 中等(运行时生成) |
| Less/SCSS 混合指令 | 预处理阶段生成标准 CSS,所有浏览器均可识别 | - 可复用 mixin/函数批量生成 RTL 代码 - 与现有 Less/SCSS 架构无缝集成 | - 仍需手工在入口或每个文件中 @include rtl-mixin - 代码量与维护成本随项目增长线性增加 | 传统项目、已使用 Less/SCSS 架构 | 较大(双倍 CSS 量) |
| RTLCSS (MohammadYounes/rtlcss) | Node.js 工具,CLI/Web/API/PostCSS/Webpack 插件可用,支持完整 CSS3 属性集 | - 构建时自动 LTR→RTL 转换,无需手动编写 - 支持注释指令( /* rtl:ignore */ 等)进行精细控制 | - 如同时保留 LTR 与 RTL,产物体积会增加 ~30%–50% - 对动态插入或 CSS‑in‑JS 场景支持有限 | 中大型项目需全自动化双向输出 | 中等(+30%–+50% CSS) |
| css‑flip (Twitter/css-flip) | Node.js 工具,npm 包,已数年无更新,支持常用方向属性 | - 构建时按需翻转常见 CSS 属性(如 left⇄right、float)- 轻量易集成,适合 Less/Gulp/Grunt 管道 | - 不支持完整 CSS3 属性集(如 border-inline-*、text-shadow 等)- 社区维护度低,更新停滞,与现代 PostCSS 生态兼容性差 | 轻量级项目、仅需简单属性翻转 | 轻微(按需翻转) |