writing mode与4大文字系统

写在前面

writing-mode是一个强大的CSS属性,能让文字竖排(实际上能让任何东西竖排,因为能改变默认布局流),例如:

小池

泉眼无声惜细流
树阴照水爱晴柔
小荷才露尖尖角
早有蜻蜓立上头

Demo见:http://ayqy.net/temp/writing-mode.html

起关键作用的CSS规则为:

/* 竖直-从右向左 */
-webkit-writing-mode: vertical-rl;
writing-mode: vertical-rl;

writing-mode从默认的horizontal top-to-bottom mode改为vertical right-to-left mode。看起来好像除了特殊文字排版场景之外,再没什么用了,但实际上要强大得多,如果给html元素应用该规则,整页都会切换成从右向左竖排模式,包括滚动方向、下拉列表方向等等都会受到影响

强大归强大,但为什么要了解这个东西?

  • 世界上的语言多种多样,除了英文、中文这些横的,还有阿拉伯文、希伯来文等等竖的,而一些场景(比如多语言混排)下需要双向排列(bidi

  • writing-mode能改变“CSS世界的纵横规则,可以说是最逆天的CSS属性”,“理论上讲,有了writing-mode,我们能够做的事情比以前多了50%”。这是一个具有无限创造力的属性,不仅能改变现有的东西,未来的东西也将受到影响,例如margin-start/end

  • 有助于理解Flexbox和CSS Grid

一.属性值及兼容性

从目前(2017-1-21)的草案来看,属性可选值如下:

/* 默认horizontal-tb */
writing-mode: horizontal-tb | vertical-rl | vertical-lr | sideways-rl | sideways-lr

默认是horizontal-tb横向从上到下排列,也就是CSS里最基本的规则,元素从左向右,从上到下依次排列。vertical-rl/lr分别表示纵向从右向左排列、纵向从左向右排列。剩余2个,不一定有没有:

This value is at-risk and may be dropped during CR.
sideways-rl:纵向从右向左排列,但印刷方式(typographic mode)是横向的
sideways-lr:纵向从左向右排列,但印刷方式是横向的

writing-mode属性还处于草案阶段,但因为IE老早就提出了这个东西,后来其它浏览器跟进,目前兼容性很不错:

sideways-rl | sideways-lr目前没有支持
horizontal-tb | vertical-rl | vertical-lr广泛支持,Android[3+],iOS[5.1+],都需要-webkit-
IE[6-10]只支持老版本值:lr-tb | rl-tb | tb-rl | tb-lr,其中与上面3个广泛支持的对应的是lr-tb | tb-rl | tb-lr

移动端可以带着前缀放心使用,关于兼容性的详细信息,请查看Can I use writing-mode ?

P.S.IE老版本值见CSS3 Text Module W3C Candidate Recommendation 14 May 2003

二.内联方向、块方向和字符方向

内联方向:默认writing-mode下,块从页面顶部开始纵向排列

内联方向是指文本流每一行的排列方向,默认从左向右排列,想象打字机效果,字符一个一个出来,就是内联方向

字符方向是说字符指向哪边,输入一个大A(这个指向太明显了,像箭头一样),字符指向页面顶部,但不同语言会指向不同方向

three concepts

three concepts

图中,块方向从上到下,内联方向从左向右,字符方向是指向页面顶部

三.4大文字系统

CSS Writing Mode从设计上满足了4大主要文字系统:拉丁文,阿拉伯文,中文和蒙古文

1.拉丁文系统

世界上最大的文字系统,70%人都用这个。文字从左向右排列,块方向是向上到下(见上图)

拉丁文系统很庞大,包括了所有用拉丁字母的其它语言,例如英文、西班牙文、德文、法文等等。此外,很多不用拉丁字母的语言也属于拉丁文系统,包括用希腊字母、西里尔(Cyrillic)字母的,例如俄文、乌克兰文、保加利亚文、塞尔维亚文等等,以及婆罗米系文字(Brahmic scripts),例如梵文、泰文、藏文等等

不需要通过CSS来触发这种模式,默认就是这样。但最好声明语言和排列方向,例如:

<html lang='en-gb' dir='ltr'>

好让浏览器知道内容是英国版英文,从左向右排列

2.阿拉伯文系统

阿拉伯文、希伯来文是少数内联方向是从右向左的,称为RTL

注意内联方向还是横向的,块方向从上到下,字符方向向上:

arabic system

arabic system

不仅文本流从右向左,布局相关的所有东西都是从右向左的,从右上角开始,眼睛从右向左浏览,所以一般RTL站点的布局与LTR类似,只是水平翻转一下

RTL下的CSS布局

一般为了支持RTL,需要做很多准备工作,比如先找到所有的margin-left/right, padding-left/right, float: left/right,标记出来,再弄一份样式表把左右反过来。这个工作很枯燥且容易出错,CSS需要提供一种只写一次布局代码,能够通过简单指令方便切换语言方向的方式

新的CSS布局系统就在做这个事情,Flexbox,Grid和Alignment用startend来代替leftright。这样就能根据文字系统定义布局,很容易切换方向。例如justify-content: flex-start; justify-items: end; margin-inline-start: 1rem都不需要再动。这种方式更好,虽然用startend替换leftright比较迷惑,但有益于多语言项目,也有益于web大环境

所以花一点点时间弄清楚内联方向、块方向,把startend用起来,很快就会习惯的

如何声明方向

应该在HTML里声明方向,而不是CSS里,这样即便CSS没加载完,浏览器也能正确显示内容。主要通过html元素完成,同时还应该声明语言,例如:

<html lang='ar' dir='rtl'>

表示页面内容是阿拉伯文,用RTL布局

无论是拉丁文系统还是阿拉伯文系统,writing-mode属性应该用一样的:

writing-mode: horizontal-tb;

因为内联文本流都是横向的,块方向也都是从上到下,用CSS表示出来就是horizontal-tb,也是默认writing-mode,所以不需要手动声明,除非想覆盖其它的或者想要更高的级联优先级。所以可以想象以前做的每个页面都有一行:

html {
    writing-mode: horizontal-tb;
}

3.汉字系统

汉字系统包括CJK语言,中文、日文、韩文等等,有两种布局方式,有时会一起出现

很多CJK文字布局和拉丁文语言一样,块方向从上到下,内联方向从左向右。布局需要的CSS与上面相同:

section {
    writing-mode: horizontal-tb;
}

或者什么都不写,默认就是这样

另外,汉字系统也可以纵向排列,内联方向是竖向,块方向从右向左,如图:

han system

han system

注意横向文本流从左向右,而纵向文本流从右向左

整页的默认设置取决于场景,但每个元素,每行标题,每节,每篇文章都可以设置成与默认的相反。例如,默认设置为horizontal-tb,再对竖直元素设置:

div.articletext {
    writing-mode: vertical-rl;
}

或者可以把页面默认设置为纵向排列,然后给某些元素设置horizontal-tb,例如:

html { 
    writing-mode: vertical-rl;
}
h2, .photocaptions, section {
    writing-mode: horizontal-tb;
}

如果页面有侧向滚动的话,writing-mode会让页面布局从左上角开始,向右滚动(horizontal-tb),或者页面布局从右上角开始,向左滚动显示溢出的部分

有一个切换writing-mode的例子:文字的故事,比较有意思的是切换是通过选择器实现的(日常猥琐扒代码):

.c-switcher:not(:checked)~main figure {
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    text-align: center
}

.c-switcher:checked~main figure {
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -ms-flex-wrap: nowrap;
    flex-wrap: nowrap
}

4.蒙古文系统

蒙古文也是一种纵向文字语言,文本在页面上纵向排列,像汉字系统一样。有2点主要差异

首先块方向不同,蒙古文块级元素从左向右排列。块方向屏幕左边开始,向右边排列。内联方向从上到下,和RTL文本很像,想象把这个页面逆时针旋转90度的样子。

另一个差异是,字符方向上下反过来,蒙古文字符的顶部不是指向左边(指向块方向的起始边),而是指向右边,如图:

mongolian system

mongolian system

writing-mode: vertical-lr就是为了处理这种情况,是为蒙古文量身定做的,所以writing-mode: vertical-lr实际效果可能与想象的不同:

vertical actual

vertical actual

因为vertical-rl确实是把页面顺时针旋转90度的结果,而vertical-lr逆时针旋转90度后,还要把文字方向反转。属性值的含义是根据文字系统表现来定义的,而不是字面意思

还有例外情况,在writing-mode: vertical-rl/lr下,拉丁文都顺时针旋转,writing-mode没办法让它逆时针旋转

如果要排版蒙古文内容的话,CSS应用方式与汉字系统相同,在html元素上设置整页的,或者声明指定元素的:

section {
    writing-mode: vertical-lr;
}

如果把writing-mode用作非横向语言的平面设计效果的话,writing-mode: vertical-lr可能没什么用,如果文本换行了,排列方式会很奇怪。所以可能经常用vertical-rl,而不怎么用vertical-lr

四.Writing Mode与平面设计

那要怎么才能用writing-mode把英文标题行侧过来?可以用transform: rotate()搞定(因为vertical-rl/lr会反转字符方向,所以需要vertical-rl + rotate模拟)

/* 顺时针旋转90度效果 */
h1 {
    writing-mode: vertical-rl;
}

/* 逆时针旋转90度效果 */
h1 {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    text-align: right;
}

这里不用writing-mode: vertical-lr,因为前面提到的换行时文本排列会很奇怪(亲测没有发现奇怪的地方,也不知道指的是什么),所以用vertical-rl + rotate实现,text-align: right;是为了让文本贴住容器顶部,这里是针对vertical-rl的,算是hack

另外,可以配合text-orientation: upright;让字符方向保持向上

这样可以让小节标题竖排在侧边,阅读体验“可能”会更好一些

五.Writing Mode技巧

利用Writing Mode把横向规则搬到纵向,例如margin: auto 0;实现竖直居中:

/* 容器 */
-webkit-writing-mode: vertical-rl;
writing-mode: vertical-rl;
/* 元素 */
height: 100px;
margin: auto 0;

或者更粗暴的:

/* 容器 */
-webkit-writing-mode: vertical-rl;
writing-mode: vertical-rl;
text-align: center;
/* 元素 */
display: inline-block;
text-align: left;

但是在有transfrom的时代,一些技巧也不很实用,例如:

  • 纵向text-indent实现按下按钮时文字下沉

  • 纵向iconfont实现展开/收起箭头

text-indent在多字情况下会换行,纵向字体只能顺时针旋转,做不到逆时针旋转

如果没有transform的话,writing-mode在布局效果上会大放光彩,例如[IE6+]环境,writing-mode就像魔法一样

writing-mode确实增加了50%的可能性,是另一扇门

参考资料

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*

code