企业级:阿拉伯市场适配解决方案
背景
最近在公司接到一个需求,是对公司的一个产品进行阿拉伯适配。之前也接过类似的需求,什么西班牙语,俄罗斯语啦,这些无非就是对语言进行翻译,(因为公司原有的产品就已经使用了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 转换包
-
在线转换工具
结论
方案 | 优点 | 缺点 |
---|---|---|
transform | 无需修改js逻辑,只需要处理css | 代码入侵大,工作量大 |
direction | 工作量减少,代码入侵减少 | 处理方向性的图标的方向和被元素拼接的语句(断句) |
转载自:https://juejin.cn/post/7382987557544099840