习以为常但又不太了解的包含块——如何决定元素的尺寸和位置

本文首发国内开源代码托管平台Gitee
文章地址:
https://gitee.com/gooder4j/co...
仓库汇集英语meme公众号【Yopen】和技术公众号【鹏哥儿的Echo】相关文章
觉得不错的话,你的star是对我最大的支持!
目录 [toc]
一、包含块 鹏哥儿在学习CSS In Depth 的3.2.2节时,被一个关于循环定义(circular definition)困住了:
Percentage refers to the size of an element's containing block; the height of that container, however, is typically determined by the height of tis children. This produces a circular definition that the browser can't resolve, so it'll ignore the declaration. For percentage-based heights to work, the parent must have an explicitly defined height.
百分比引用了一个元素的包含块的尺寸;那个容器的高,却典型地被子元素的高度说确定。这产生了一个浏览器无法解决的循环定义,所以浏览器会忽略这行规则(即用百分比定义高度的规则)。要想让基于百分比的高度工作,父元素必须要显式地定义高度。
今天来学习CSS中的Containing Block 包含块,相信学完之后,你同样能够对这个问题的答案醍醐灌顶。
今天解析的文章是来自关于包含块的MDN文章 ^[1]^ ,声明一下: 前几节全是理论概念,比较干比较无聊,大家可以跳到最后一节一些例子 ,结合例子来学习比较。
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

一个元素的尺寸和位置经常被 包含块所影响。大部分情况下,包含块指向一个元素最近的块级祖先元素的内容区域,小部分情况下不是这样的。在这篇文章中,我们会研究那些确定一个元素包含块的因素。
虽然这里翻译为祖先元素(ancestor),但其实更贴切是长辈元素,因为这里不仅指祖先元素,也指父类元素。想象一下,一个被嵌套了几层,它的包含块就是第一个遇到的外层块级元素(注意是块级元素,也就是会忽略掉内联元素),第一个遇到的无论是父类还是祖父类们,都可以。
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

当一个用户代理(例如你的浏览器)展开一份文档,它会为每个元素生成一个盒子,每个盒子可以分成四个区域
  1. 内容区域
  2. 内边距区域
  3. 边框区域
  4. 外边距区域
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

其实也就是盒模型。
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

许多开发者坚信一个元素的包含块一定是它父类的内容区域,但这一结论不一定总是成立。让我们来研究一下确定一个元素的包含块的因素。
这里重复强调了下,元素的包含块是根据不同条件确定的。
二、包含块的效果 习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

在我们学习确定一个元素的包含块之前,了解一下为什么包含块的作用性是很重要的。
一个元素的尺寸和位置经常被它的包含块所影响。应用在width, height, padding, margin上的百分比值,还有absolute定位的元素偏移属性,都是根据元素的包含块计算出来的。
【习以为常但又不太了解的包含块——如何决定元素的尺寸和位置】像百分比这样的值,肯定根据一个基准来进行计算,得到最后的结果值,而包含块就是那个基准。
三、标识一个包含块 习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

标志包含块的程序完成取决于元素的position属性
  1. 如果position属性是static, relative或者sticky,包含块通过最近长辈元素的内容盒的边界来形成,这个长辈元素可以是一个块级容器(例如inline-block, block或者list-item元素),也可以是建立了格式化的上下文(例如一个table容器,flex容器,grid容器,或者块级容器本身)
一个元素如果不显示定义position的值的话,那么元素position的默认值为static。大部分元素都是不定义position值的,也就导致了前文提到的:许多开发者坚信一个元素的包含块一定是它父类的内容区域
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

如果 position的属性值是 absolute,包含块变成了最近的 长辈元素的内边距区域,这个 最近的长辈元素指它的 position属性值不是 static(可以是 fixed, absolute, relative或者 sticky)的元素。
注意包含块的变化,position的值从static的最近长辈元素的内容区域(见下图绿色线条区域)改为absolute确定的最近长辈元素的内边距区域(下图红色线圈出来的区域,是包括内边距的边缘的)。
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

为什么内容区域变为了内边距区域?
这样做的目的是为了忽略内边距,体现了绝对定位(absolutely position)的效果^[2]^。
? 习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

如果 position属性是 fixed,包含块由窗口(在连续媒体情况下)或者页面区域(在页面媒体情况下)所确定。
根据MDN的另一篇文章,^[2]^连续媒体一般指音频或者运动视频。
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

  1. 如果position的属性是absolute或者fixed,包含块同样会变成最近长辈元素的内边距区域,这个最近的长辈元素符合下面条件:
    1. transform或者perspective的值不是none
    2. will-change属性值是transform或者perspective
    3. filter的值不是none或者will-change的值不是filter(仅在firefox有效);
    4. contain的值是paint(例如:contain:paint; )。
will-change这个比较少见,它是CSS的一个属性^[3]^,作用是向浏览器表明元素即将做出变化,浏览器因此可以对此进行针对性的优化,从而提高页面响应性能。
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

包含根元素( )的矩形包含块称之为 初始包含块。它有视口(对于连续媒体)或者页面区域(对于页面媒体)的尺寸。
根元素也有他自己的包含块,那么对于html页面上每一个元素来说,都会拥有自己的包含块。
四、从包含块中计算百分比值 习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

如上所述,但某个属性给定一个百分比值,它计算出来的结果取决与元素的包含块。这些属性包括盒模型属性还有偏移属性:
  1. height,top还有bottom属性从包含块的height中计算它的百分比值
  2. width,left,right,padding还有margin属性从它的包含块的width中计算它的百分比值。
五、一些例子 以下是一段简单的html代码:
This is a paragraph!

以下例子共用上面这一份html代码,只是css代码有所变化,当这些css代码变化的时候,推断一下元素的包含块,以及元素的百分比计算结果。
例1
body { background: beige; }section { display: block; width: 400px; height: 160px; background: lightgray; }p { width: 50%; height: 25%; margin: 5%; padding: 5%; background: cyan; }

习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

在这个例子中, position属性是 static,它的包含块是 ,因为它是块级容器,并且也是距离 最近的长辈元素。
那么,的各个百分比值计算等于
p { width: 50%; /* 值等于400px*50%=200px */ height: 25%; /* 值等于160px*25%=40px */ margin: 5%; /* 值等于400px*5%=20px */ padding: 5%; /* 值等于400px*5%=20px */ background: cyan; }

marginpadding的属性值为百分比,他们的计算规则遵循:
width, left, right, padding还有 margin属性从它的包含块的 width中计算它的百分比值。
例2
body { background-color: beige; }section { display: inline; background: lightgray; }p { width: 50%; height: 200px; background-color: cyan; }

习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

在这个例子中, 的包含块是 元素,因为 不是一个块级容器(因为 display:inline)并且也没有建立格式化上下文。
的宽度百分比计算如下:
p { width: 50%; /* 值等于宽度的一半 */ height: 200px; background-color: cyan; }

例3
body { background-color: beige; }section { position: absolute; left: 30px; top: 30px; width: 400px; height: 160px; padding: 30px 20px; background: lightgray; }p { position: absolute; width: 50%; height: 25%; margin: 5%; padding: 5%; background-color: cyan; }

习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

在这里例子中, 的包含块是 因为后者的 position值是 absolut的百分比值会被包含块的 padding所影响,如果包含块的 box-sizing属性值是 border-box的话,那么情况就不一样了。
的宽度百分比计算如下:
p { position: absolute; width: 50%; /* (400+20*2)px*50%=220px */ height: 25%; /* (160+30*2)px*25%=55px */ margin: 5%; /* (400+20*2)px*5%=22px */ padding: 5%; /* (400+20*2)px*5%=22px */ background-color: cyan; }

box-sizing: border-box; 属性的作用是widthheight包含content+padding+margin,也就是IE盒模型(标准的W3C盒模型widthheight只指定content,不包含padding和margin)。
添加了box-sizing: border-box; ,那么的宽度百分比计算会变为:
p { position: absolute; width: 50%; /* 400px*50%=200px */ height: 25%; /* 160px*25%=40px */ margin: 5%; /* 400px*5%=20px */ padding: 5%; /* 400px*5%=20px */ background-color: cyan; }

这里读者可以自行验证下。
例4
body { background-color: beige; }section { width: 400px; height: 480px; margin: 30px; padding: 15px; background: lightgray; }p { position: fixed; width: 50%; height: 50%; margin: 5%; padding: 5%; background-color: cyan; }

习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

在这个例子中, positionfixed,所以它的包含块是初始包含块(在屏幕上,那个视窗)。因此, 的尺寸根据浏览器窗口的尺寸改变而改变。
的各个属性百分比计算如下:
p { /* 假设视窗的宽高比为:562px*612px*/ position: fixed; width: 50%; /* 562px*50%=281px */ height: 50%; /* 612px*50%=306px */ margin: 5%; /* 562px*5%=28.1px */ padding: 5%; /* 562px*5%=28.1px */ background-color: cyan; }

这里的视窗尺寸可以用浏览器的小手机图标来模拟:
习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

例5
body { background-color: beige; }section { transform: rotate(0deg); width: 400px; height: 160px; background: lightgray; }p { position: absolute; left: 80px; top: 30px; width: 50%; height: 25%; margin: 5%; padding: 5%; background-color: cyan; }

习以为常但又不太了解的包含块——如何决定元素的尺寸和位置
文章图片

在这个例子中, positionabsolute,所以它的包含块是 transform属性不为 none,所以它能够称为 的最近长辈元素。
的各个属性百分比计算如下:
p { position: absolute; left: 80px; top: 30px; width: 50%; /* 400px*50%=200px */ height: 25%; /* 160px*25%=40px */ margin: 5%; /* 400px*5%=20px */ padding: 5%; /* 400px*5%=20px */ background-color: cyan; }

六、总结 看到这里的话,恭喜你完成了对包含块的所有学习
我们来总结下,包含块就是用于确定元素的尺寸和位置的,每一个元素都拥有自己的包含块(的包含块称之为促使包含块)。
如果positionstatic,relative,sticky,那么元素的包含块是最近的长辈元素(displayblock,table,flex,grid元素的内容区域)。
如果是absolute,那么是内边距区域。
如果是fixed,那么有视窗来决定。
并且对于absolutfixed,还有其他一些规则可以确定他们的长辈元素(比如tranform属性不为none时)。这一块无需记忆,需要的时候查阅一下即可,查阅方式:
  1. 通过公众号【鹏哥儿的Echo】,回复“包含块”获取本篇文章内容
  2. 通过Gitee搜索“鹏哥儿/创作中心”,或者“创作中心”,进入首页就能查找得到
  3. 可以直接收藏本文链接https://gitee.com/gooder4j/co...
REFERENCE [1] https://developer.mozilla.org...
[2] https://blog.vjeux.com/2012/c...
[2] https://developer.mozilla.org...
[3] https://developer.mozilla.org...

    推荐阅读