在 CSS 中,我们经常会与各种方向方位打交道。

譬如 marginpadding,它们就会有 margin-leftmargin-right 或者是 padding-leftpadding-right。还有定位中的 lefttoprightbottom,它们表示了上下左右不同的方位。

还有一种情况是从x方位到x方位,譬如 writing-modedirection,它代表了一种顺序,表示块流动方向,或者文字书写的方向等。

本文将捋一捋 CSS 世界中的方位与顺序,探寻其中一些有意思的点。

writing-mode & direction & unicode-bidi

在 CSS 世界中,这 3 个属性都与排版顺序相关,互有关联但作用各异。

  • writing-mode:定义了文本水平或垂直排布以及在块级元素中文本的行进方向。
  • direction:设置文本排列的方向。 rtl 表示从右到左 (类似希伯来语或阿拉伯语), ltr 表示从左到右。
  • unicode-bidi:它与 direction 非常类似,两个会经常一起出现。在现代计算机应用中,最常用来处理双向文字的算法是Unicode 双向算法。而 unicode-bidi 这个属性是用来重写这个算法的。

单纯看定义有点懵逼,我们简单的看几个应用示意图:

writing-mode 示意

writing-mode 基本只需要留意最常见的 horizontal-tbvertical-lrvertical-rl 。表示文本的行进方向,下图表示浏览器对 writing-mode 的支持完整的情况下输出的外观:

direction 示意

OK,那 direction 又为何呢?它表示文本排列的方向

  • direction: ltr:默认属性。可设置文本和其他元素的默认方向是从左到右。
  • direction: rtl:可设置文本和其他元素的默认方向是从右到左。

有点绕,所以上 Demo 最为直观。假设,我们有如下结构:

<ul class="wrap">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<p>这是一段正常顺序的文本</p>

简单的 CSS 如下:

p, ul {
background: #ff00ff50;
padding: 10px;
}
ul {
display: flex;
justify-content: space-between; & > li {
border: 1px solid #333;
}
}

正常情况下的样式如下:

我们分别给两组元素的父容器 <p><ul> 加上 direction: ltrdirection: rtl,则最终效果如下:

可以看到,direction 可以改变子元素的排列方向,但是它确无法改变单段文本内(或是内联元素内),每一个文字的书写顺序

那如果,我希望 这是一段正常顺序的文本 这段文字,不是从左向右进行书写,而是反过来,从右到左进行书写,又该如何设置呢?

unicode-bidi 示意

这就需要请出 unicode-bidi 了。

单独使用 direction: rtl 无法使单段文本内(或是内联元素内),文字的书写顺序改为从右至左。需要配合 unicode-bidi

CSS 中的 unicode-bidi 属性,和 direction 属性,共同决定如何处理文档中的双书写方向文本。

还是上述的代码,我们改造一下:

<p>这是一段正常顺序的文本</p>
p {
direction: rtl;
unicode-bidi: bidi-override;
}

结果如下:

放到一起比较:

这里除了 unicode-bidi: bidi-overrideunicode-bidi: isolate-override 也能得到同样的效果。

这里涉及了一个非常重要的知识 -- Unicode 双向算法

Unicode 双向算法

双向文字就是一个字符串中包含了两种文字,既包含从左到右的文字又包含从右到左的文字。

对于文字书写习惯,分为:

  1. 大多数文字都是从左到右的书写习惯:比如拉丁文字(英文字母)和汉字;
  2. 少数文字是从右到左的书写方式比如阿拉伯文(ar)跟希伯来文(he)。

在现代计算机应用中,最常用来处理双向文字的算法是 Unicode 双向算法(Unicode Bidirectional Algorithm)。

一个区域内有总体方向,决定从这个区域的哪边开始书写文字,通常称为基础方向。浏览器会根据你的默认语言来设置默认的基础方向,如英语、汉语的基础方向为从左到右,阿拉伯语的基础方向为从右到左

在 Web 中,我们有 3 种方式可以控制文字方向:

  1. html实体 - &lrm;&rlm;
  2. <bid><bdo> 标签 与 dir 属性
  3. CSS 属性 direction + unicode-bidi

本文介绍的就是 CSS 中的 direction + unicode-bidi 方式控制文字的书写方向。关于 Unicode 双向算法(Unicode Bidirectional Algorithm)本身还是非常复杂的,本文也仅仅只是简单提及,更为详尽的内容,你可以参考 UNICODE BIDIRECTIONAL ALGORITHM

writing-mode & direction & unicode-bidi 的一些应用

除去本身的功能,下面我们来看看它们其它的一些应用场景。

使用 writing-mode 进行创意排布布局

writing-mode 非常适合用于进行一些创意排版。

基础的类似中国古诗词的一些竖向展示:

<div class="g-wrap">
<h2>凉州词</h2>
<p>葡萄美酒夜光杯,</p>
<p>欲饮琵琶马上催。</p>
<p>醉卧沙场君莫笑,</p>
<p>古来征战几人回。</p>
</div>

.g-wrap 分别添加 writing-mode: vertical-rl 或者 writing-mode: vertical-lr 得到不同的效果:

.rl {
writing-mode: vertical-rl;
}
.lr {
writing-mode: vertical-lr;
}

CodePen Demo -- display poems by writing-mode

又或者像是这样,利用 writing-mode:vertical-rl 实现标题的竖向排列,搭配内容形成有意思的报纸排版:

<div>
<h2>Title Loomings</h2>
<p>Call me Ishmael. Some years ago- never mind ho....
</p>
</div>
div {
width: 750px;
padding-left: 150px;
}
h2 {
position: absolute;
writing-mode: vertical-rl;
}

得到这样的排版布局:

CodePen Demo -- writing-mode Layout Demo

改变文本溢出省略位置,使之在头部进行省略

我们都知道,本文超长溢出的省略,通过都是在文本的最末尾。像是这样:

<p>Make CSS Ellipsis Beginning of String</p>
p {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

这里,我们可以通过 direction,将省略打点的位置,从尾部移动至头部:

p {
direction: rtl;
}

结果如下:

尝试了下运用在多行省略中,多行省略的打点会出现在最后一行的左侧,不符合需求。

CodePen Demo -- CSS Ellipsis Beginning of String

使用 writing-mode 改变元素方位

这个小技巧是在张老师的博客中学到的:改变CSS世界纵横规则的writing-mode属性

我们可以通过 writing-mode: vertical-rl,将元素转一个 90° 角:

<div>➤</div>
div:hover {
writing-mode: vertical-rl;
}

看看效果,当 hover 的时候,将箭头从向右️改为向下 :

当然,现在这个功能完全可以用 transform 替代,但是在之前需要兼容 IE 系列的时候,不失为一个有意思的小技巧。

CSS 中的逻辑属性

下面一个章节,我们聊聊 CSS 中的逻辑位置。

我们知道,在我们使用类似 marginpadding 的时候,可以单独控制每个方向,例如 margin-toppadding-left

然而,这种使用了 top/left/bottom/right 物理方向维度定义的属性,在不同的排版规则下,就非常容易出问题。

思考如下这样一个 DEMO,我们希望给古诗的题目的上方,添加一个 padding 值:

<div class="g-wrap pt">
<h2>凉州词</h2>
<p>葡萄美酒夜光杯,</p>
<p>欲饮琵琶马上催。</p>
<p>醉卧沙场君莫笑,</p>
<p>古来征战几人回。</p>
</div>
<div class="g-wrap pt rl">
<h2>凉州词</h2>
<p>葡萄美酒夜光杯,</p>
<p>欲饮琵琶马上催。</p>
<p>醉卧沙场君莫笑,</p>
<p>古来征战几人回。</p>
</div>
.pt {
padding-top: 100px;
}
.rl {
writing-mode: vertical-rl;
}

可以看到,无论 writing-mode 如何,padding-top 始终指代物理方向的上方。

基于这种不同排版规则,物理方向可能会带来一定的困扰这个问题,CSS 在 CSS Logical Properties and Values Level 1 规范中,推出了 CSS 逻辑属性。

CSS 逻辑属性与值是 CSS 的一个新的模块,其引入的属性与值能做到从逻辑角度控制布局,而不是从物理、方向或维度来控制。

还是上述的 DEMO,我们可以使用 padding-block-start 替代 padding-top

重点:使用 padding-block-start 替代 padding-top

.pt {
- padding-top: 100px;
+ padding-block-start: 100px;
}
.rl {
writing-mode: vertical-rl;
}

这次再看看效果:

padding 的位置由物理上的上方,变成了逻辑上的上方。

完整的 Demo 你可以戳这里:CodePen Demo-- 物理方向与逻辑方向展示

margin、padding、border、relative 物理属性到逻辑属性的映射

类似这样的属性,在规范中定义了挺多的,简单罗列一下具体的映射规则:

margin 物理属性到逻辑属性的映射:

Property 属性 Logical Property 逻辑属性
margin-top margin-block-start
margin-left margin-inline-start
margin-right margin-inline-end
margin-bottom margin-block-end

padding 物理属性到逻辑属性的映射:

Property 属性 Logical Property 逻辑属性
padding-top padding-block-start
padding-left padding-inline-start
padding-right padding-inline-end
padding-bottom padding-block-end

border 物理属性到逻辑属性的映射:

Property 属性 Logical Property 逻辑属性
border-top{-size|style|color} border-block-start{-size|style|color}
border-left{-size|style|color} border-inline-start{-size|style|color}
border-right{-size|style|color} border-inline-end{-size|style|color}
border-bottom{-size|style|color} border-block-end{-size|style|color}

relative 物理属性到逻辑属性的映射:

Property 属性 Logical Property 逻辑属性
top inset-block-start
left inset-inline-start
right inset-inline-end
bottom inset-block-end

在逻辑属性中没有方向性的概念,只有开始(start)和结束(end)、块(block)和内联(inline)的概念。比如说,在从左到右(LTR)中,start 是 left,但在从右到左(RTL),它是 right。

逻辑属性下的盒子模型

考虑到不同排版带来的逻辑问题,整个盒子模型也可以随之进行改变。

下图,左边是物理盒子模型,右边是逻辑属性下的盒子模型。

物理方向与逻辑方向重叠

当然,还有这样一种情况,就是设置的逻辑方向和物理方向重叠,譬如我们给一个正常从左往右,从上至下的元素同时设置 padding-toppadding-block-start,看看会发生什么:

div {
padding-top: 100px;
padding-block-start: 100px;
}

这里如果物理方向与逻辑方向重叠设置的 padding 重叠,将会取两个值中更大的一个,类似外边距重叠。

CodePen Demo-- 物理方向与逻辑方向重叠 DEMO 展示

总结一下

总结一下,当项目开始国际化,当国内更多的业务开始出海,国际化兼容适配也会越来越重要。好在 CSS 也一直在紧跟时代,推陈出新,当你的排版布局需要考虑不同的 writing-mode 的时,你需要开始考虑使用逻辑属性替代物理属性!

最后

好了,本文到此结束,希望对你有帮助

想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

参考文章

CSS 世界中的方位与顺序的更多相关文章

  1. CSS世界中那些说起来很冷的知识

    CSS世界中那些说起来很冷的知识 最近读了张鑫旭的新书<CSS世界>收获了不少对CSS的深度理解 也正值个人在公司内部进行部分章节的内容分享,于是顺带着直接把我即将分享的内容先给大家过过目 ...

  2. CSS世界中的“盒子”

    1.块级元素 HTML标签通常被分为两类:块级元素和内联元素. “块级元素”和“display为block的元素”不是同一个概念.例如<li>元素默认的display值为list-item ...

  3. 改变CSS世界纵横规则的writing-mode属性

    改变CSS世界纵横规则的writing-mode属性 这篇文章发布于 2016年04月27日,星期三,23:12,归类于 css相关. 阅读 8292 次, 今日 71 次 by zhangxinxu ...

  4. 《CSS世界》读书笔记(十五)

    <!-- <CSS世界>张鑫旭著 --> 字母x——CSS世界中隐匿的举足轻重的角色 在各种内联相关模型中,凡是涉及垂直方向的排版或者对齐的,都离不开最基本的基线(baseli ...

  5. 《CSS世界》读书笔记(一)

    <!-- <CSS世界> 张鑫旭 著 --> CSS世界构建的基石是HTML,而HTML最具代表的两个基石<div>和<span>正好是CSS世界中块级 ...

  6. 《CSS世界》学习笔记(一)

    <CSS世界>,张鑫旭著,人民邮电出版社,2017年12月第一版. 1.P9二维码链接文章的demo值得一看,可以实现有关“某些区域颜色始终保持一致”的效果. P9二维码所链接文章的一个d ...

  7. 《CSS世界》读书笔记(十三)

    <!-- <CSS世界>张鑫旭著 --> margin 无效情形解析 (1)display 计算值 inline 的非替换元素的垂直 margin 是无效的.对于内联替换元素, ...

  8. 《CSS世界》读书笔记(十二)

    <!-- <CSS世界>张鑫旭著 --> 正确看待 CSS 世界里的 margin 合并 什么是 margin 合并 块元素的上外边距(margin-top)与下外边距(mar ...

  9. 《CSS世界》读书笔记(十一)

    激进的margin属性 margin与元素尺寸以及相关布局 元素尺寸 border box尺寸,对应jQuery中的$().outerWidth()和$().outerHeight()方法,在原生DO ...

随机推荐

  1. Go timer 是如何被调度的?

    hi,大家好,我是 haohongfan. 本篇文章剖析下 Go 定时器的相关内容.定时器不管是业务开发,还是基础架构开发,都是绕不过去的存在,由此可见定时器的重要程度. 我们不管用 NewTimer ...

  2. ADAS摄像头图像环视拼接算法

    ADAS摄像头图像环视拼接算法 输入输出接口 Input: (1)4个摄像头采集的图像视频分辨率 (整型int) (2)4个摄像头采集的图像视频格式 (RGB,YUV,MP4等) (3)摄像头标定参数 ...

  3. vue3函数setUp和reactive函数详细讲解

    1 setUp的执行时机 我们都知道,现在vue3是可以正常去使用methods的. 但是我们却不可以在setUp中去调用methods中的方法. 为什么了??? 我们先了解一下下面这两个生命周期函数 ...

  4. MIT6.828-LAB1 : PC启动

    Lab1 1. 先熟悉PC的物理地址空间 这里其实有很多可以说的,不过先简单描述一下吧.从0x00000000到0x00100000这1mb的地址空间时机器处于16位的实模式.也就是说这个时候机器的汇 ...

  5. NOIP模拟测试17「入阵曲&#183;将军令&#183;星空」

    入阵曲 题解 应用了一种美妙移项思想, 我们先考虑在一维上的做法 维护前缀和$(sum[r]-sum[l-1])\%k==0$可以转化为 $sum[r]\% k==sum[l-1]\%k$开个桶维护一 ...

  6. [.NET Core知识点回顾]-自动内存管理

    自动内存管理是公共语言运行时在托管执行过程中提供的服务之一.公共语言运行时的垃圾回收器为应用程序管理内存 的分配和释放.对开发人员而言,在开发托管应用程序时不必编写执行内存管理任务代码. 分配内存 初 ...

  7. 动态路由及RIP协议

    动态路由及 RIP协议 目录 一.动态路由协议 1.1.定义 1.2.特点 1.3.动态路由协议概述 1.4.度量值 1.5.收敛 1.6.静态路由和动态路由的比较 二.动态路由协议的分类 2.1.距 ...

  8. 十八、.net core(.NET 6)搭建ElasticSearch(ES)系列之使用Logstash通过Rabbitmq接收Serilog日志到ES

    使用Logstash通过Rabbitmq接收Serilog日志到ES 首先,要部署logstash 为了与前面的ElasticSearch版本保持一致,此处Logstash下载的版本也是7.13.1, ...

  9. ECMAScript 2021 正式确认

    ECMAScript 2021 主要包含内容: ECMAScript 2021 于2021年6月22日获得 ECMA International 的批准.ECMAScript 是标准化的 JavaSc ...

  10. SpringCloud入门及创建分布式项目

    1.了解微服务 1.1 什么是微服务 微服务是一种架构风格 一个应用拆分为一组小型服务 每个服务运行在自己的进程内,也就是可独立部署和升级 服务之间使用轻量级HTTP交互 服务围绕业务功能拆分 可以由 ...