在 CSS 中,我們經常會與各種方向方位打交道。
譬如 margin
、padding
,它們就會有 margin-left
、margin-right
或者是 padding-left
、padding-right
。還有定位中的 left
、top
、right
、bottom
,它們表示了上下左右不同的方位。
還有一種情況是從x方位到x方位,譬如 writing-mode
、direction
,它代表了一種順序,表示塊流動方向,或者文字書寫的方向等。
本文將捋一捋 CSS 世界中的方位與順序,探尋其中一些有意思的點。
writing-mode
& direction
& unicode-bidi
在 CSS 世界中,這 3 個屬性都與排版順序相關,互有關聯但作用各異。
writing-mode
:定義了文字水平或垂直排布以及在塊級元素中文字的行進方向。direction
:設定文字排列的方向。 rtl 表示從右到左 (類似希伯來語或阿拉伯語), ltr 表示從左到右。unicode-bidi
:它與direction
非常類似,兩個會經常一起出現。在現代計算機應用中,最常用來處理雙向文字的演算法是Unicode 雙向演算法。而unicode-bidi
這個屬性是用來重寫這個演算法的。
單純看定義有點懵逼,我們簡單的看幾個應用示意圖:
writing-mode
示意
writing-mode
基本只需要留意最常見的 horizontal-tb
、vertical-lr
、vertical-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: ltr
及 direction: 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-override
,unicode-bidi: isolate-override
也能得到同樣的效果。
這裡涉及了一個非常重要的知識 -- Unicode 雙向演算法。
Unicode 雙向演算法
雙向文字就是一個字串中包含了兩種文字,既包含從左到右的文字又包含從右到左的文字。
對於文字書寫習慣,分為:
- 大多數文字都是從左到右的書寫習慣:比如拉丁文字(英文字母)和漢字;
- 少數文字是從右到左的書寫方式比如阿拉伯文(ar)跟希伯來文(he)。
在現代計算機應用中,最常用來處理雙向文字的演算法是 Unicode 雙向演算法(Unicode Bidirectional Algorithm)。
一個區域內有總體方向,決定從這個區域的哪邊開始書寫文字,通常稱為基礎方向。瀏覽器會根據你的預設語言來設定預設的基礎方向,如英語、漢語的基礎方向為從左到右,阿拉伯語的基礎方向為從右到左。
在 Web 中,我們有 3 種方式可以控制文字方向:
- html實體 -
‎
與‏
) <bid>
與<bdo>
標籤 與dir
屬性- 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 中的邏輯位置。
我們知道,在我們使用類似 margin
和 padding
的時候,可以單獨控制每個方向,例如 margin-top
、padding-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 |
- 等等...(完整的列表,你可以戳這裡:MDN - CSS 邏輯屬性與值)
在邏輯屬性中沒有方向性的概念,只有開始(start)和結束(end)、塊(block)和內聯(inline)的概念。比如說,在從左到右(LTR)中,start 是 left,但在從右到左(RTL),它是 right。
邏輯屬性下的盒子模型
考慮到不同排版帶來的邏輯問題,整個盒子模型也可以隨之進行改變。
下圖,左邊是物理盒子模型,右邊是邏輯屬性下的盒子模型。
物理方向與邏輯方向重疊
當然,還有這樣一種情況,就是設定的邏輯方向和物理方向重疊,譬如我們給一個正常從左往右,從上至下的元素同時設定 padding-top
和 padding-block-start
,看看會發生什麼:
div {
padding-top: 120px;
padding-block-start: 100px;
}
這裡如果物理方向與邏輯方向設定的 padding
重疊,將會取兩個值中後面定義的那個。這裡由於 padding-block-start
後於 padding-top
定義,所以 padding
的值為 100px
。
margin
和 border
同理。這裡我的理解是,同個方向上還是隻能存在一個 margin\padding\border
,無論是邏輯方向還是物理方向,取後定義的值為準。
CodePen Demo-- 物理方向與邏輯方向重疊 DEMO 展示
總結一下
總結一下,當專案開始國際化,當國內更多的業務開始出海,國際化相容適配也會越來越重要。好在 CSS 也一直在緊跟時代,推陳出新,當你的排版佈局需要考慮不同的 writing-mode
的時,你需要開始考慮使用邏輯屬性替代物理屬性!
最後
好了,本文到此結束,希望對你有幫助 ?
想 Get 到最有意思的 CSS 資訊,千萬不要錯過我的公眾號 -- iCSS前端趣聞 ?
更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。
如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。