写在前面
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
从目前(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
图中,块方向从上到下,内联方向从左向右,字符方向是指向页面顶部
CSS Writing Mode从设计上满足了4大主要文字系统:拉丁文,阿拉伯文,中文和蒙古文
世界上最大的文字系统,70%人都用这个。文字从左向右排列,块方向是向上到下(见上图)
拉丁文系统很庞大,包括了所有用拉丁字母的其它语言,例如英文、西班牙文、德文、法文等等。此外,很多不用拉丁字母的语言也属于拉丁文系统,包括用希腊字母、西里尔(Cyrillic)字母的,例如俄文、乌克兰文、保加利亚文、塞尔维亚文等等,以及婆罗米系文字(Brahmic scripts),例如梵文、泰文、藏文等等
不需要通过CSS来触发这种模式,默认就是这样。但最好声明语言和排列方向,例如:
<html lang='en-gb' dir='ltr'>
好让浏览器知道内容是英国版英文,从左向右排列
阿拉伯文、希伯来文是少数内联方向是从右向左的,称为RTL
注意内联方向还是横向的,块方向从上到下,字符方向向上:
arabic system
不仅文本流从右向左,布局相关的所有东西都是从右向左的,从右上角开始,眼睛从右向左浏览,所以一般RTL站点的布局与LTR类似,只是水平翻转一下
一般为了支持RTL,需要做很多准备工作,比如先找到所有的margin-left/right, padding-left/right, float: left/right
,标记出来,再弄一份样式表把左右反过来。这个工作很枯燥且容易出错,CSS需要提供一种只写一次布局代码,能够通过简单指令方便切换语言方向的方式
新的CSS布局系统就在做这个事情,Flexbox,Grid和Alignment用start
和end
来代替left
和right
。这样就能根据文字系统定义布局,很容易切换方向。例如justify-content: flex-start; justify-items: end; margin-inline-start: 1rem
都不需要再动。这种方式更好,虽然用start
和end
替换left
和right
比较迷惑,但有益于多语言项目,也有益于web大环境
所以花一点点时间弄清楚内联方向、块方向,把start
和end
用起来,很快就会习惯的
应该在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;
}
汉字系统包括CJK语言,中文、日文、韩文等等,有两种布局方式,有时会一起出现
很多CJK文字布局和拉丁文语言一样,块方向从上到下,内联方向从左向右。布局需要的CSS与上面相同:
section {
writing-mode: horizontal-tb;
}
或者什么都不写,默认就是这样
另外,汉字系统也可以纵向排列,内联方向是竖向,块方向从右向左,如图:
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
}
蒙古文也是一种纵向文字语言,文本在页面上纵向排列,像汉字系统一样。有2点主要差异
首先块方向不同,蒙古文块级元素从左向右排列。块方向屏幕左边开始,向右边排列。内联方向从上到下,和RTL文本很像,想象把这个页面逆时针旋转90度的样子。
另一个差异是,字符方向上下反过来,蒙古文字符的顶部不是指向左边(指向块方向的起始边),而是指向右边,如图:
mongolian system
writing-mode: vertical-lr
就是为了处理这种情况,是为蒙古文量身定做的,所以writing-mode: vertical-lr
实际效果可能与想象的不同:
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
把英文标题行侧过来?可以用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把横向规则搬到纵向,例如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
实现按下按钮时文字下沉text-indent
在多字情况下会换行,纵向字体只能顺时针旋转,做不到逆时针旋转
如果没有transform
的话,writing-mode
在布局效果上会大放光彩,例如[IE6+]
环境,writing-mode
就像魔法一样
但writing-mode
确实增加了50%的可能性,是另一扇门