在上一篇 【HelloCSS】
的第一章CSS的语法与工作流中介绍了 CSS
的语法规则以及基本的渲染流程。本篇则会分享 CSS
的逻辑属性以及盒子模型。
首先开篇之前先提个问题:
为什么 Flexbox
跟 Gridbox
的是以 start
、 end
为排列规则,而不是常规的 top
、 right
、 bottom
跟 left
?
先不要急着往下翻,大家先思考一下。
这个问题的答案,鱼头会在文章中给出,欢迎大家带着这个问题往下翻阅,如果已经知道答案,也可以看看跟大家所知道的答案是否一致。
2017年5月18日,W3C的 CSS工作组(CSS Working Group) 发布了 CSS逻辑属性和值(CSS Logical Properties and Values Level 1) 的首份工作草案(First Public Working Draft)。不同的书写模式(writing mode)中,可以抽取出共性的抽象概念(如开始位置,或行),这些逻辑抽象概念需要在不同书写模式下映射到左或右、上或下等物理的概念上。一些CSS布局可能依赖这些共性的逻辑概念。该 CSS 模块给出了用于通过逻辑方式(而不是基于物理坐标、书写方向和维映射等)控制布局的逻辑属性和取值(logical properties and values)。这个模块来源于CSS21中关于逻辑属性和值的特性。
上面复制粘贴了W3C 中国里的内容。
对于前端来说,我们一直习惯于使用 top
、 right
、 bottom
、 left
来定义我们的 HTML
元素,这跟我们物理上的概念是一致的。但是对于 CSS
这个原本是为了服务于图文展示才诞生的语言来说,其实是不匹配的,为什么这么说?
writing-mode:定义了文本水平或垂直排布以及在块级元素中文本的行进方向。
writing-mode
一共有以下5个改变 HTML
文本书写规则的值(还有几个是用在 SVG
上的,本文不予讨论):
writing-mode:horizontal-tb
定义了内容从左到右水平流动,从上到下垂直流动。下一条水平线位于上一条线下方。
writing-mode:vertical-rl
定义了内容从上到下垂直流动,从右到左水平流动。下一条垂直线位于上一行的左侧。
writing-mode:vertical-lr
定义了内容从上到下垂直流动,从左到右水平流动。下一条垂直线位于上一行的右侧。
writing-mode:sideways-rl
定义了内容从上到下垂直流动,所有字形,甚至是垂直脚本中的字形,都设置在右侧。
writing-mode:sideways-lr
内容从上到下垂直流动,所有字形,甚至是垂直脚本中的字形,都设置在左侧。
上述效果请看DEMO
源码如下:
.wm-htb {
writing-mode: horizontal-tb;
}
.wm-vrl {
writing-mode: vertical-rl;
}
.wm-vlr {
writing-mode: vertical-lr;
}
.wm-srl {
writing-mode: sideways-rl;
}
.wm-slr {
writing-mode: sideways-lr;
}
.text-content {
width: 200px;
padding: 20px;
border: 1px solid;
display: inline-block;
vertical-align: top;
padding-right: 100px;
}
<div
class="text-content wm-htb">writing-mode: horizontal-tb;</div>
<div
class="text-content wm-vrl">writing-mode: vertical-rl;</div>
<div
class="text-content wm-vlr">writing-mode: vertical-lr;</div>
<div
class="text-content wm-srl">writing-mode: sideways-rl;</div>
<div
class="text-content wm-slr">writing-mode: sideways-lr;</div>
图示如下:
从上图可以发现,当我们设置了 padding-right:100px;
的时候,不同的书写规则,展示效果是不一样的。
在最开始的时候, HTML
与 CSS
只服务于英语国家,但是随着互联网的发展,逐渐各个不同书写规则的国家也开始流行了起来。
我们原来的 CSS
逻辑属性是按照物理逻辑,从上(top)、右(right)、下(bottom)、左(left)划分的。
那么按着这个规则去修改文本属性时,就会出现上述这种不符合语法规则的状态。
大概也是基于这个原因,所以W3C发布了新的逻辑属性与值。
CSS新旧逻辑属性是完全不同的两种模型。
我们首先来看看新旧有的逻辑属性的对比图示(图片来自medium):
左旧右新
通过上图可以得知新旧逻辑属性对应关系如下:
旧的逻辑属性 | 新的逻辑属性 |
---|---|
margin-top | margin-block-start |
margin-right | margin-inline-end |
margin-bottom | margin-block-end |
margin-left | margin-inline-start |
border-top | border-block-start |
border-right | border-inline-end |
border-bottom | border-block-end |
border-left | border-inline-start |
padding-top | padding-block-start |
padding-right | padding-inline-end |
padding-bottom | padding-block-end |
padding-left | padding-inline-start |
width | inline-size |
height | block-size |
由上表可以得知,把Y轴方向的属性都改为了block,X轴方向的属性都改为了inline。
对于不同语系的国家,书写顺序会可能有很大的差异,意思就是 block
跟 inline
的方向不同。例如:
padding-inline-start
= padding-left
padding-inline-start
= padding-right
padding-inline-start
= padding-top
这就意味着旧的逻辑属性,在某些国家里会变得不合常理。
CSS
的定位属性变化如下:
旧的逻辑属性 | 新的逻辑属性 |
---|---|
top | inset-block-start |
bottom | inset-block-end |
left | inset-inline-start |
right | inset-inline-end |
例子如下:
/* 旧的逻辑属性 */
.popup{
position:fixed;
top:0;
bottom:0;
left:0;
right:0;
}
/* 新的逻辑属性 */
.popup{
position:fixed;
inset-block-start:0;
/*top - in English*/
inset-block-end:0;
/*bottom - in English*/
inset-inline-start:0;
/*left - in English*/
inset-inline-end:0;
/*right - in English*/
}
/* 新的逻辑属性支持简写 */
.popup{
position:fixed;
inset:0
0
0
0;
/*top, right, bottom, left - in English*/
}
图示:(图片来自medium):
浮动 float
的属性也改了。
旧的逻辑属性 | 新的逻辑属性 |
---|---|
float: left | float: inline-start |
float: right | float: inline-end |
文本 text-align
的属性也改了。
旧的逻辑属性 | 新的逻辑属性 |
---|---|
text-align: left | text-align: start |
text-align: right | text-align: end |
除了 writing-mode
,还有一个排版属性就是 direction
,跟 writing-mode
类似,不一样的是 writing-mode
是控住网页布局方向的,而 direction
是控制文本对齐方向的。属性如下:
默认值,让文本和其他元素从左到右显示。
让文本和其他元素从右到左显示。
吐槽一下,看到这里的切图仔们,抓紧 ~~跑路~~ 重构吧,等哪天此属性正式被启用,就真的GG了。不过我想应该会立个属性来选择性开启物理属性还是逻辑属性,不然这对前端来说将会是一场灾难!
当浏览器对一个render tree进行渲染时,浏览器的渲染引擎就会根据基础盒模型(CSS basic box model),将所有元素划分为一个个矩形的盒子,这些盒子的外观,属性由 CSS
来决定。
我们在浏览器控制台输入如下代码就可以看到页面的每一个元素都是由一个矩形来包裹的,这些就是盒子
$$('*').forEach(e =>
{
e.style.border =
'1px solid';
})
图示如下:
每个盒子都由四个部分组成:
盒子(box) 的内容,显示标签内一切的文本,图案或者别的内容。
盒子(box) 内的填充物,样式为透明,主要负责扩展盒子内区域大小。
盒子(box) 外部的区域,样式为透明,负责隔离相邻的元素。
盒子(box) 的边界,负责隔离外边距以及内边距。
盒子模型一共有三个值:
content-box
为标准的盒子模型。盒子的 width
跟 height
只包括盒子本身的 width
与 height
属性。
计算法则:
width=width
height=height
border-box
为盒子模型可选的属性之一。盒子的 width
跟 height
包括 content
、 padding
跟 border
。这也是当文档处于 Quirks模式 时Internet Explorer使用的盒模型。
计算法则:
width=width+border+padding
height=height+border+padding
padding-box
为非标准属性,曾经在Firefox中实现过,但是在Firefox 50中被删除。 padding-box
的 width
和 height
属性包括内容和内边距,但是不包括边框和外边距。
图示:
这里吐槽一下,不知道为何没有margin-box,虽然并没有太大意义,当真实现了效果估计也很诡异,但是作为一个强迫症患者晚期,少了一个属性总感觉好不舒服。
CSS
的视觉格式化模型(visual formatting model) 是根据 基础盒模型(CSS basic box model) 将 文档(doucment) 中的元素转换一个个盒子的实际算法。 官方说法就是:它规定了用户端在媒介中如何处理文档树( document tree )。
每个盒子的布局由以下因素决定:
视觉格式化模型(visual formatting model) 的计算,都取决于一个矩形的边界,这个矩形,被称作是 包含块( containing block ) 。 一般来说,(元素)生成的框会扮演它子孙元素包含块的角色;我们称之为:一个(元素的)框为它的子孙节点建造了包含块。包含块是一个相对的概念。
例子如下:
<div>
<table>
<tr>
<td>hi</td>
</tr>
</table>
</div>
以上代码为例, div
和 table
都是包含块。 div
是 table
的包含块,同时 table
又是 td
的包含块,不是绝对的。
图示:(图片来自w3help):
盒子的生成是 CSS视觉格式化模型 的一部分,用于从文档元素生成盒子。盒子的类型取决于
CSS display
属性。
display
为 block
、 list-item
或 table
时,它就是块级元素。
CSS选择器
选中,也就是所有可继承的 CSS 属性值都为 inherit
,而所有不可继承的 CSS 属性值都为 initial
。因此称为匿名盒子(anonymous boxes)。
display
为 inline
、 inline-block
或 inline-table
时,它就是行内级元素。
行内格式化上下文(inlineformatting context)
的创建。
initial
。
display:run-in
来设置,它既可以是块盒子,又可以是行内盒子,这取决于它后面的盒子的类型。
一旦形成了盒子,CSS引擎就需要定位它们来完成布局。
定位所使用的规则如下:
float
不为 none
,并且 position
为 static
或 relative
时,该盒子为浮动定位。float:left
:盒子会定位到当前行盒子的开始位置(左侧)。float:right
:盒子会定位到当前行盒子的尾部位置(右侧)。position
为 absolute
或 fixed
,该元素为绝对定位。W3C 中国 (http://www.chinaw3c.org/archives/1820/)
New CSS Logical Properties! (https://medium.com/@elad/new-css-logical-properties-bc6945311ce7)
w3help (http://w3help.org/zh-cn/kb/008/)
视觉格式化模型(Visual formatting model) (https://segmentfault.com/a/1190000008541494)
MDN 视觉格式化模型 (https://developer.mozilla.org/zh-CN/docs/Web/Guide/CSS/Visualformattingmodel)
包含块( Containing block ) (http://w3help.org/zh-cn/kb/008/)
本篇文章主要介绍了 CSS
的新旧逻辑属性的状态以及盒子模型的具体情况。文章内还有部分内容没有进行太多的介绍,例如块格式化上下文(block formatting context) 跟 行内格式化上下文(inline formatting context)以及其他一些具体的名称,这些后续的文章都将会进行介绍,到时候将会进行具体的讲解,希望大家可以多多关注鱼头我的【Hello CSS】系列。
开头时,鱼头我有问到大家一个问题,就是:
为什么 Flexbox
跟 Gridbox
的是以 start
、 end
为排列规则,而不是常规的 top
、 right
、 bottom
跟 left
?
这个问题,通过本篇文章的分享,大家有答案了吗?
鱼头我将会在下一篇开头时分享答案,希望大家多多留意本系列文章。
【HelloCSS】
是以 CSS
基础概念为主题的系列文章,旨在帮助大家更深刻地了解并且提高 CSS
在各位开发者心目中的地位。由于鱼头我水平有限,文笔有限,如果各位在文章中发现有任何不合理,不正确的地方,还烦不吝指出,我会非常感谢的;如果通过文章有任何想法或疑问,也希望各位能积极留言,我们互相探讨;如果通过本系列文章有所收获,这就让鱼头我喜不自胜了!
如果你也喜欢 CSS
,喜欢探讨技术,或者对本文,本系列有任何的意见或建议,鱼头非常希望你能加入一个有趣的微信群 — “进击的CSS”。如果你有兴趣,请添加鱼头微信(krisChans95),添加时注明 “加群”,Mmmm,最后,如果觉得我的文章还不错,请加个关注跟点个“好看”呗!