利用 Sass 优雅解决 RTL 语言布局适配
October 07, 2021
前言
不同于国内的活动,国际化活动投放大量地区,这些地区有着不同的语言体系、阅读风格,意味着界面布局上要进行相应的适配,以获得更好的用户体验。
本文介绍如何利用 Sass(CSS 预处理器)@mixin and @include
特性去优雅解决国际化 UI 布局。
适配 RTL
首先需要考虑到 RTL(right-to-left) 语言的适配,其文字的阅读书写方向是从右向左的,例如阿拉伯语(Arabic)、希伯来语(Hebrew)、波斯语(Persian)等。在这些语言环境下的用户界面,需要从右向左「镜像 Mirroring」设计。
什么是镜像设计呢?所谓一图胜千言:
从示例图中可以看出,从右到左的布局进行了水平翻转,使 LTR 和 RTL 沿着中轴线对折,能完全贴合,即镜像设计。
想要阅读更多有关 RTL 的设计,可查阅 RTL 镜像指南。
下面举一场活动中真实的 🌰,为了实现对照,我同时放上了正常布局和 RTL 布局:
codepen demo:
核心的 Sass 代码如下:
scss
@mixin dir($dir: "rtl") {[dir="#{$dir}"] & {@content;}}.logo {/* ... */border-bottom-right-radius: 6px;left: 0;@include dir {left: unset; /* 还原 LTR 模式下的 left 属性 */right: 0; /* 为实现镜像效果,将 left 方向进行翻转,即 right */border-bottom-right-radius: unset;border-bottom-left-radius: 6px;}}
scss
@mixin dir($dir: "rtl") {[dir="#{$dir}"] & {@content;}}.logo {/* ... */border-bottom-right-radius: 6px;left: 0;@include dir {left: unset; /* 还原 LTR 模式下的 left 属性 */right: 0; /* 为实现镜像效果,将 left 方向进行翻转,即 right */border-bottom-right-radius: unset;border-bottom-left-radius: 6px;}}
unset 的作用非常之大,可以用它来还原样式属性。
因为对于所有 CSS 属性,都存在三个可选值:
- initial,该属性使用默认值
- inherit,该属性继承父元素的值
- unset,如果该属性是可继承属性,该值等同于 inherit;如果该属性是非继承属性,该值等同于 initial
最后,来看编译后的 CSS 代码:
css
[dir="rtl"] .container .logo {left: unset;right: 0;border-bottom-right-radius: unset;border-bottom-left-radius: 6px;}
css
[dir="rtl"] .container .logo {left: unset;right: 0;border-bottom-right-radius: unset;border-bottom-left-radius: 6px;}
不知道大家发现没有,虽然我没有显式设置 display-direction: row-reverse
,但实际上 flex 的布局方向自动变成了从右到左。
根据 MDN 的解释,这是由于值 row 和 row-reverse 受 flex 容器的方向性的影响, 如果它的 dir 属性是 ltr,row 表示从左到右定向的水平轴,而 row-reverse 表示从右到左; 如果 dir 属性是 rtl,row 表示从右到左定向的轴,而 row-reverse 表示从左到右。
切记在你的 HTML 结构最外层的 DOM 节点加上 dir 属性,否则该 mixin 不会生效。
适配字号
其次需要考虑到文字字号的适配,同样的一句话:”user daily tasks“,在不同语言环境下的字符长度不一,需要做 font-size
的适配。
先看反面例子,俄语翻译文案由 local 同学提供,如果不对 font-size
做适配,就会造成文字溢出内容的情况,这是非常低级的错误。
codepen demo:
经过适配后,表现如下:
核心的 Sass 代码如下:
scss
@mixin lang($languages...) {@for $i from 0 to length($languages) {[lang="#{nth($languages, $i + 1)}"] & {@content;}}}p {/* ... */@include lang("en") {color: Crimson;}@include lang("ru-RU") {/* 支持传入多个语言,如 lang("vi-VN", "ko-KR") */color: DeepSkyBlue;font-size: 12px;}}
scss
@mixin lang($languages...) {@for $i from 0 to length($languages) {[lang="#{nth($languages, $i + 1)}"] & {@content;}}}p {/* ... */@include lang("en") {color: Crimson;}@include lang("ru-RU") {/* 支持传入多个语言,如 lang("vi-VN", "ko-KR") */color: DeepSkyBlue;font-size: 12px;}}
同样来看编译后的 CSS 代码:
css
[lang="en"] p {color: Crimson;}[lang="ru-RU"] p {color: DeepSkyBlue;font-size: 12px;}
css
[lang="en"] p {color: Crimson;}[lang="ru-RU"] p {color: DeepSkyBlue;font-size: 12px;}
切记在你的 HTML 结构最外层的 DOM 节点加上 lang 属性,否则该 mixin 不会生效。