Hello-CSS第二章CSS的逻辑属性与盒子模型

31次阅读

共计 7173 个字符,预计需要花费 18 分钟才能阅读完成。

  • 作者:陈大鱼头
  • github:KRISACHAN

在上一篇 【Hello CSS】 的第一章 CSS 的语法与工作流中介绍了 CSS 的语法规则以及基本的渲染流程。本篇则会分享 CSS 的逻辑属性以及盒子模型。

首先开篇之前先提个问题:

为什么 Flex boxGrid box的是以 startend 为排列规则,而不是常规的toprightbottomleft

先不要急着往下翻,大家先思考一下。

这个问题的答案,鱼头会在文章中给出,欢迎大家带着这个问题往下翻阅,如果已经知道答案,也可以看看跟大家所知道的答案是否一致。

CSS 的逻辑属性

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 中国里的内容。

对于前端来说,我们一直习惯于使用 toprightbottomleft 来定义我们的 HTML 元素,这跟我们物理上的概念是一致的。但是对于 CSS 这个原本是为了服务于图文展示才诞生的语言来说,其实是不匹配的,为什么这么说?

writing-mode

writing-mode:定义了文本水平或垂直排布以及在块级元素中文本的行进方向。

writing-mode一共有以下 5 个改变 HTML 文本书写规则的值 (还有几个是用在SVG 上的,本文不予讨论):

writing-mode: horizontal-tb;

writing-mode: horizontal-tb 定义了内容从左到右水平流动,从上到下垂直流动。下一条水平线位于上一条线下方。

writing-mode: vertical-rl;

writing-mode: vertical-rl 定义了内容从上到下垂直流动,从右到左水平流动。下一条垂直线位于上一行的左侧。

writing-mode: vertical-lr;

writing-mode: vertical-lr定义了内容从上到下垂直流动,从左到右水平流动。下一条垂直线位于上一行的右侧。

writing-mode: sideways-rl; (仅 Firefox41+ 实现)

writing-mode: sideways-rl定义了内容从上到下垂直流动,所有字形,甚至是垂直脚本中的字形,都设置在右侧。

writing-mode: sideways-lr;(仅 Firefox41+ 实现)

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; 的时候,不同的书写规则,展示效果是不一样的。

在最开始的时候,HTMLCSS 只服务于英语国家,但是随着互联网的发展,逐渐各个不同书写规则的国家也开始流行了起来。

我们原来的 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

对于不同语系的国家,书写顺序会可能有很大的差异,意思就是 blockinline的方向不同。例如:

  • 在英语国家 padding-inline-start = padding-left
  • 在阿拉伯padding-inline-start = padding-right
  • 在日本 padding-inline-start = padding-top

这就意味着旧的逻辑属性,在某些国家里会变得不合常理。

CSS 定位

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):

CSS 浮动

浮动 float 的属性也改了。

旧的逻辑属性 新的逻辑属性
float: left float: inline-start
float: right float: inline-end

text-align

文本 text-align 的属性也改了。

旧的逻辑属性 新的逻辑属性
text-align: left text-align: start
text-align: right text-align: end

direction

除了 writing-mode,还有一个排版属性就是direction,跟writing-mode 类似,不一样的是 writing-mode 是控住网页布局方向的,而 direction 是控制文本对齐方向的。属性如下:

direction: ltr;

默认值,让文本和其他元素从左到右显示。

direction: rtl;

让文本和其他元素从右到左显示。

吐槽一下,看到这里的切图仔们,抓紧 跑路 重构吧,等哪天此属性正式被启用,就真的 GG 了。不过我想应该会立个属性来选择性开启物理属性还是逻辑属性,不然这对前端来说将会是一场灾难!

CSS 的盒子模型

基础盒模型(CSS basic box model)

当浏览器对一个 render tree 进行渲染时,浏览器的渲染引擎就会根据 基础盒模型 (CSS basic box model),将所有元素划分为一个个矩形的盒子,这些盒子的外观,属性由CSS 来决定。

我们在浏览器控制台输入如下代码就可以看到页面的每一个元素都是由一个矩形来包裹的,这些就是 盒子

$$('*').forEach(e => {e.style.border = '1px solid';})

图示如下:

每个盒子都由四个部分组成:

内容(content)

盒子(box) 的内容,显示标签内一切的文本,图案或者别的内容。

内边距(padding)

盒子(box) 内的填充物,样式为透明,主要负责扩展盒子内区域大小。

外边距(margin)

盒子(box) 外部的区域,样式为透明,负责隔离相邻的元素。

边框(border)

盒子(box) 的边界,负责隔离外边距以及内边距。

盒子模型的值

盒子模型一共有三个值:

content-box

content-box为标准的盒子模型。盒子的 widthheight只包括盒子本身的 widthheight属性。

计算法则:

width = width

height = height

border-box

border-box为盒子模型可选的属性之一。盒子的 widthheight包括 contentpaddingborder。这也是当文档处于 Quirks 模式 时 Internet Explorer 使用的盒模型。

计算法则:

width = width + border + padding

height = height + border + padding

padding-box

padding-box为非标准属性,曾经在 Firefox 中实现过,但是在 Firefox 50 中被删除。padding-boxwidthheight 属性包括内容和内边距,但是不包括边框和外边距。

图示:

这里吐槽一下,不知道为何没有 margin-box,虽然并没有太大意义,当真实现了效果估计也很诡异,但是作为一个强迫症患者晚期,少了一个属性总感觉好不舒服。

视觉格式化模型(visual formatting model)

CSS 视觉格式化模型 (visual formatting model) 是根据 基础盒模型 (CSS basic box model) 文档(doucment) 中的元素转换一个个盒子的实际算法。

官方说法就是:它规定了用户端在媒介中如何处理文档树(document tree)。

每个盒子的布局由以下因素决定:

  • 盒子的尺寸
  • 盒子的类型:行内盒子 (inline)行内级盒子 (inline-level)原子行内级盒子 (atomic inline-level)块盒子 (block)
  • 定位:普通流 浮动 绝对定位
  • 文档树中当前盒子的 子元素 兄弟元素
  • 视口 (viewport) 尺寸 位置
  • 盒子内部图片的 尺寸
  • 其他某些外部因素

视觉格式化模型 (visual formatting model) 的计算,都取决于一个矩形的边界,这个矩形,被称作是 包含块 (containing block)。一般来说,(元素) 生成的框会扮演它子孙元素包含块的角色;我们称之为:一个 (元素的) 框为它的子孙节点建造了包含块。包含块是一个相对的概念。

例子如下:

<div>
    <table>
        <tr>
            <td>hi</td>
        </tr>
    </table>
</div>

以上代码为例,divtable 都是包含块。divtable 的包含块,同时 table 又是 td 的包含块,不是绝对的。

图示:(图片来自 w3help):

盒子的生成

盒子的生成是 CSS 视觉格式化模型 的一部分,用于从文档元素生成盒子。盒子的类型取决于CSS display 属性。

  • 块级元素

    • 当元素的displayblocklist-itemtable 时,它就是块级元素。
  • 块级盒子

    • 块级盒子用于描述它与父、兄弟元素之间的关系。
    • 每个块级盒子都会参与 块格式化上下文(block formatting context)的创建。
    • 每个块级元素都会至少生成一个块级盒子,即 主块级盒子(principal block-level box)
    • 主块级盒子包含由后代元素生成的盒子以及内容,同时它也会参与定位方案。
    • 一个同时是块容器盒子的块级盒子称为 块盒子(block box)
  • 匿名盒子

    • 某些情况下需要进行视觉格式化时,需要添加一些增补性的盒子,这些盒子不能被 CSS 选择器 选中,也就是所有可继承的 CSS 属性值都为 inherit,而所有不可继承的 CSS 属性值都为 initial。因此称为 匿名盒子(anonymous boxes)
  • 行内元素

    • 当元素的displayinlineinline-blockinline-table 时,它就是行内级元素。
    • 显示时可以与其他行内级内容一起显示为多行。
  • 行内盒子

    • 行内级元素会生成行内级盒子,该盒子同时会参与 行内格式化上下文(inline formatting context)的创建。
  • 匿名行内盒子

    • 类似于块盒子,CSS 引擎有时候也会自动创建一些行内盒子。这些行内盒子无法被选择符选中,因此是匿名的,它们从父元素那里继承那些可继承的属性,其他属性保持默认值 initial
  • 行盒子

    • 行盒子由行内格式化上下文创建,用来显示一行文本。在块盒子内部,行盒子总是从块盒子的一边延伸到另一边(译注:即占据整个块盒子的宽度)。当有浮动元素时,行盒子会从向左浮动的元素的右边缘延伸到向右浮动的元素的左边缘。
  • run-in 盒子(在 CSS 2.1 的标准中移除了)

    • run-in 盒子可以通过 display: run-in 来设置,它既可以是块盒子,又可以是行内盒子,这取决于它后面的盒子的类型。

定位规则

一旦形成了盒子,CSS 引擎就需要定位它们来完成布局。

定位所使用的规则如下:

  • 普通流

    • 在普通流中,盒子会依次放置。
    • 块格式化上下文(block formatting context)中,盒子在垂直方向依次排列。
    • 行内格式化上下文(inline formatting context) 中,盒子则水平摆列。
  • 浮动:当一个盒子的 float 不为 none,并且positionstaticrelative 时,该盒子为浮动定位。

    • float: left:盒子会定位到当前行盒子的开始位置(左侧)。
    • float: right:盒子会定位到当前行盒子的尾部位置(右侧)。
  • 绝对定位:如果元素的positionabsolutefixed,该元素为绝对定位。

    • 在绝对定位中,盒子会完全从当前流中移除,并且不会再与其有任何联系。

参考资料:

W3C 中国

New CSS Logical Properties!

w3help

视觉格式化模型(Visual formatting model)

MDN 视觉格式化模型

包含块(Containing block)

结语

本篇文章主要介绍了 CSS 的新旧逻辑属性的状态以及盒子模型的具体情况。文章内还有部分内容没有进行太多的介绍,例如 块格式化上下文(block formatting context)行内格式化上下文(inline formatting context)以及其他一些具体的名称,这些后续的文章都将会进行介绍,到时候将会进行具体的讲解,希望大家可以多多关注鱼头我的【Hello CSS】系列

开头时,鱼头我有问到大家一个问题,就是:

为什么 Flex boxGrid box的是以 startend 为排列规则,而不是常规的toprightbottomleft

这个问题,通过本篇文章的分享,大家有答案了吗?

鱼头我将会在下一篇开头时分享答案,希望大家多多留意本系列文章。

【Hello CSS】系列

【Hello CSS】是以 CSS 基础概念为主题的系列文章,旨在帮助大家更深刻地了解并且提高 CSS 在各位开发者心目中的地位。由于鱼头我水平有限,文笔有限,如果各位在文章中发现有任何不合理,不正确的地方,还烦不吝指出,我会非常感谢的;如果通过文章有任何想法或疑问,也希望各位能积极留言,我们互相探讨;如果通过本系列文章有所收获,这就让鱼头我喜不自胜了!

如果你也喜欢 CSS,喜欢探讨技术,或者对本文,本系列有任何的意见或建议,鱼头非常希望你能加入一个有趣的微信群 —“ 进击的 CSS”。你可以扫描下方二维码,添加鱼头微信,添加时注明“加群 ”,如果你觉得我的文章有趣,欢迎关注微信公众号“ 鱼头的 Web 海洋”。衷心希望可以遇见你。

正文完
 0