构建 RTL 感知 Web 应用和网站:第二部分

推动 Web 发展意味着使其对开发者和用户都更加友好。这意味着要解决当前 Web 所面临的问题;对于让响应式 RTL 设计和开发更容易实现,这一点尤其重要。

在继续讨论前沿 RTL 主题之前,这里有一个包含实际示例的视频教程,可以帮助你回顾一下如何正确地编写当今的 RTL 代码

 

承接上一篇文章,现在我们来深入探讨一下关于从右到左 UI 实现的一些高级主题。在第一部分中,我们介绍了 RTL 的基础知识。在第二部分中,我们将介绍关于双向 (BIDI) 用户界面的前沿技巧。这是 Web 的 Alpha 状态,我们可以看看 RTL 的未来会有什么发展。

前沿的 RTL

Web 上的 RTL UI 设计和开发的核心是 CSS 属性,就像 Web 开发的各个方面一样,这些属性一直在不断改进。

以下是可以从今天开始在多个现代浏览器的 Alpha 版本中开始使用的 CSS 属性。(随着浏览器更新的发布,此信息可能会发生变化。)

文本对齐:过去,我们曾经使用 text-align leftright 来显式设置文本的水平对齐方式(例如 text-align: left)。现在,我们可以使用 startend 值来代替它们。例如,text-align: start 将根据内容设置为 RTL 或 LTR 而产生不同的结果。start 在 LTR 中表示左侧,在 RTL 中表示右侧,而 end 则相反。

使用 left/right 的示例


#content {
  text-align: left:
}
html[dir="rtl"] #content {
  text-align: right;
}

使用 start/end 的示例


#content {
  text-align: start;
}

使用 start/end 时,不需要使用 RTL 规则。
浏览器支持:Chrome 1.0+、Safari 3.1+、Firefox 3.6+、Android、iOS。目前 Internet Explorer 不支持。

填充、边距和边框:这些属性有一些改进。
它们中的每一个现在都可以添加 -inline-start-inline-end 后缀,例如,你可以写 padding-inline-endmargin-inline-start。这些新的关键字与文本对齐中的 start 和 end 具有相同的结果:padding-inline-start 在 LTR 中等效于 padding-left,在 RTL 中等效于 padding-rightmargin-inline-end 在 LTR 中等效于 margin-right,在 RTL 中等效于 margin-left

使用 left/right 的示例


#content {
  padding-left: 12px:
  margin-right: 20px;
}
html[dir="rtl"] #content {
  padding-left: 0;
  padding-right: 12px;
  margin-left: 20px;
  margin-right: 0px;
}

使用 start/end 的示例


#content {
  padding-inline-start: 12px:
  margin-inline-end: 20px;
}

同样,不需要使用 RTL 规则;例如,margin-inline-end 在 LTR 中将充当 margin-right,在 RTL 中将充当 margin-left
浏览器支持:仅限 Firefox 41+

绝对定位:leftright 是始终是绝对定位的关键 CSS 属性,但很快你将使用新的 offset-inline-startoffset-inline-end 属性为用户编写更加智能的 CSS 代码。

值得一提的是,top 和 bottom 可以用 offset-block-startoffset-block-end 代替。

使用 left/right 的示例


#content {
  position: absolute;
  left: 5rem;
}
html[dir="rtl"] #content {
  left: auto;
  right: 5rem;
}

使用 start/end 的示例


#content {
  offset-inline-start: 5rem;
}

再一次,start/end 概念为我们省去了 CSS 文件中的规则。
浏览器支持:仅限 Firefox 41+

浮动:float: leftfloat: right 已经存在并被使用很长时间了,但很快你就能在 Firefox Nightly 中使用 float: inline-startfloat: inline-endinline-start 将在从左到右 (LTR) 布局中将元素浮动到左侧,在从右到左 (RTL) 布局中将元素浮动到右侧。

使用 start/end 的示例


#content {
  float: left;
}
html[dir="rtl"] #content {
  float: right;
}

使用 start/end


#content {
  float: inline-start;
}

浏览器支持:Firefox 44(即将登陆 Firefox Nightly)。

Firefox OS 为你提供了尝试一些最新的 CSS 属性实现的机会 - Mozilla Wiki 上有一个关于所有新 BIDI 相关 CSS 属性和值 的参考页面。

Web 组件:Web 组件是可重用的用户界面小部件 (有关更多信息,请参阅 MDN)。如果你使用过 Web 组件,你就会知道在 Shadow DOM 中定义的 CSS 样式是作用域化的,因此默认情况下,你无法从组件的作用域 CSS 中使用 html[dir=”rtl”] 获取页面的方向。但是,Shadow DOM 引入了一个新的选择器,称为 :host-context(),它可以用来根据匹配的父元素选择 Shadow 宿主元素。

让我们用一个例子来解释一下 - 假设你的 Shadow DOM 树中有一个名为 back 的元素。在没有 Shadow DOM 的正常情况下,你只需使用 html[dir=”rtl”] .back {},但你无法在 Web 组件内部使用此语法。作用域化和封装,记住吗?当 .back 在 Web 组件作用域内时,等效的选择器看起来像这样


.back:host-context(html[dir="rtl"]) { }

目前,这种语法的确切浏览器支持状态尚不清楚,但你可以使用 此 polyfill 来弥补支持方面的不足。

想要使用 Shadow CSS 的 polyfill,但仍然想要在支持它的浏览器(如 Firefox(目前隐藏在 dom.webcomponents.enabled 标志后面)和 Google Chrome)中使用 Web 组件中的 RTL 吗?你可以使用 Mutation Observers 来观察 document.documentElement.dir 属性。观察器的代码将类似于以下示例


var dirObserver = new MutationObserver(updateShadowDir);
dirObserver.observe(document.documentElement, {
  attributeFilter: ['dir'],
  attributes: true
});

此外,不要忘记在页面加载后,在观察器逻辑之后立即第一次初始化你的函数

updateShadowDir();

你的 updateShadowDir() 函数将看起来像这样


function updateShadowDir() {
  var internal = myInnerElement.shadowRoot.firstElementChild;
  if (document.documentElement.dir === 'rtl') {
    internal.setAttribute('dir', 'rtl');
  } else {
    internal.removeAttribute('dir');
  }
};

这是你应该在 JavaScript 方面做的事情 - 现在,由于你的 Web 组件的第一个子元素具有不断变化的 dir 属性,因此你的 CSS 将依赖它作为选择器,而不是 HTML 元素。假设你使用的是一个 span - 你的选择器将看起来像这样

span[dir="rtl"] rest-of-the-selectors-chain { … }

这可能看起来有点 hacky,但幸运的是,未来更加光明,所以让我们看看 W3C 在未来关于从右到左方面会为我们带来什么。

Web 上 RTL 的未来

通知服务器文本方向:目前,在文本输入和文本区域中,当提交表单时,页面/表单元素的方向会丢失。然后,服务器必须自己想办法估计发送给他们的文本的方向。

为了解决这个问题,并提供更多关于发送的文本及其方向的信息,W3C 在 HTML5 表单规范中添加了一个新属性,称为 dirname,浏览器供应商将在未来实现它。

正如规范中所述,在表单控件元素上包含 dirname “能够提交元素的方向,并在提交表单时提供包含此值的字段的名称。如果指定了此类属性,其值必须不为空字符串”。

翻译:将此属性添加到你的 <input> 或 <textarea> 中,会使它们的方向与发送到服务器的 GET 或 POST 字符串一起传递。让我们看一个真实世界的例子 - 首先,假设你有以下表单

<form action="result.php" method="post">
<input name="comment" type="text" dirname="comment.dir"/>
<button type=submit>Send!</button>
</form>

提交表单后,发送到服务器的 POST 字符串将包含一个名为 comment 的字段,以及另一个名为 comment.dir 的字段。如果用户在文本区域中输入 Hello 并提交它,则结果字符串将是
comment=Hello&comment.dir=ltr

但如果他们输入 “مرحبا”,它将看起来像这样

comment=%D9%85%D8%B1%D8%AD%D8%A8%D8%A7&comment.dir=rtl

阅读规范:这里.

注意:为了使阿拉伯字符在浏览器中以正确的形式显示在 URL 中,这些字符使用 UTF-8 编码,每个阿拉伯字母现在使用 4 个字符,并在中间用 % 符号隔开。

例如,如果你有以下链接:http://ar.wikipedia.org/wiki/نجيب_محفوظ

当你访问它时,浏览器中的链接将转换为

http://ar.wikipedia.org/wiki/%D9%86%D8%AC%D9%8A%D8%A8_%D9%85%D8%AD%D9%81%D9%88%D8%B8

更好地管理 RTL 中的背景和图像:厌倦了使用 transform: scaleX(-1) 来镜像你的背景图像了吗?W3C 正在引入一个名为 rtlflip 的新 CSS 关键字,使用方式如下

background-image: url(backbutton.png) rtlflip;

这个关键字可以让你免去使用 transform: scaleX(-1) 属性手动镜像图像的麻烦。
它还可以用来设置列表项标记的样式,如下所示

list-style-image:url('sprite.png#xywh=10,30,60,20') rtlflip;

规范页面 还指出,这个关键字可以与 CSS3 Images 中指定图像的所有其他可能方式一起使用,例如 urlspriteimage-listlinear-gradientradial-gradient

国际化 API

我们在 一篇介绍性文章 中介绍过 JavaScript 国际化 API。让我们回顾一下与处理从右到左内容相关的重要的鲜为人知的部分。

国际化 API 支持多种语言及其派生语言。例如,它不仅支持阿拉伯语,还支持阿拉伯语-埃及、阿拉伯语-突尼斯以及所有其他变体。

使用东阿拉伯数字而不是西阿拉伯数字:在一些阿拉伯语变体中,使用东阿拉伯数字 (١٢٣) 而不是西阿拉伯数字 (123)。国际 API 允许我们指定何时显示 ١٢٣ 和何时显示 123。

console.log(new Intl.NumberFormat('ar-EG').format(1234567890));

这表示我们要将 1234567890 格式化为阿拉伯-埃及数字。
输出:١٬٢٣٤٬٥٦٧٬٨٩٠

console.log(new Intl.NumberFormat('ar-TN').format(1234567890));

这里我们说我们要以阿拉伯-突尼斯格式输出同一个数字;由于突尼斯使用西方阿拉伯语,所以输出结果为:1234567890

以伊斯兰历/回历显示日期,而不是公历: 在斋月期间,谷歌将 google.com/ramadan 改为显示与该节日相关的內容。显示的最重要信息之一是回历中的月日。谷歌使用了一个 polyfill 来获取此信息。使用国际化 API,您可以用一行 JavaScript 代码提取相同的信息,而无需整个 JavaScript 库。
这是一个例子

console.log(new Intl.DateTimeFormat("fr-FR-u-ca-islamicc").format(new Date()));
这行代码表示我们要将当前日期格式化为伊斯兰历日期,并以 fr-FR 数字(西方阿拉伯语)显示。输出:16/12/1436
console.log(new Intl.DateTimeFormat("ar-SA-u-ca-islamicc").format(new Date()));
这与上面相同,但格式化为在使用东阿拉伯数字的阿拉伯-沙特阿拉伯地区显示。
输出:١٦‏/١٢‏/١٤٣٦

最后的话

在本文中,我们总结了关于在 Web 上以正确方式进行 RTL 的深入分析。我们希望这将有助于鼓励您开始在您的网站/产品中添加 RTL 支持!如果您是 Firefox OS 贡献者,这将是您向 Gaia 添加 RTL 的指南。

与往常一样,如果您有任何问题,请在下面的评论中告诉我们!

关于 Ahmed Nefzaoui

RTL(从右到左)专家。前端 Web 开发人员。Firefox OS UI 黑客和 Mozilla 技术演讲者。

更多来自 Ahmed Nefzaoui 的文章…


一条评论

  1. Nawfel

    非常感谢。视频演示也非常棒。

    2015 年 10 月 8 日 下午 3:40

本文的评论已关闭。