2023-07-12 重新认识CSS的包含块、盒模型以及定位
前言
之前在开发的时候查阅MDN文档的CSS这块知识时,发现文档更新了,而且有很多新的点,像新增了包含块、块盒什么的,仔细阅读后发现确实过去的一些概念模糊不清,现在重新阅读,理解这块的知识,整理成文档如下
块级盒子与内联盒子
块级盒子:display为block,而且会有以下行为:
- 盒子会在内联的方向上扩展并且占据其包含块在该方向上的所有可用空间,在绝大数情况下意味着盒子会和其包含块一样宽
- 每个盒子都会换行
width
和height
属性起作用- 内边距(
padding
)、外边距(margin
)和边框(border
)会将其他元素从当前盒子周围推开
常见的块盒元素:浏览器默认样式表设置的块盒,容器元素诸如div
、p
等
行内盒子:display为inline,显著特点如下:
- 盒子沿着内容延伸
- 行盒不能设置宽高,调整行盒的宽高应该使用字体大小、行高、字体类型等间接调整
- 内边距、边框、和外边距水平方向有效,垂直方向不会实际占据空间
常见的行盒元素:文本元素与内容相关的如a
、span
、img
、video
、iframe
等
这里要注意的点是,不管是块级盒子还是行内盒子其实都是可以相互转换的,根据display属性设置即可 还有一种display为inline-block的行内块级盒子,其实这种要避免使用,因为其行为有很多不可确定性
盒模型
盒模型的组成:
Content box
:显示内容,大小可以通过设置width
和height
Padding box
:包围在内容区外部的空白区域,大小通过padding
相关属性设置Border box
:边框盒包裹内容和内边距,大小通过border
相关属性设置Margin box
:这是最外面的区域,是盒子与其他元素之间的空白区域,大小通过margin
相关属性设置
如图:
块级盒子使用了盒模型完整的内容,而内联盒子只使用了盒模型中定义的部分内容
而且盒模型分为两大类:标准的和替代(IE)的
标准盒模型
在标准模型中,如果给盒子设置了width
和height
,实际设置的就是Content box
,padding
和border
再加上设置的宽高一起决定了整个盒子的大小
.box {
width: 350px;
height: 150px;
margin: 25px;
padding: 25px;
border: 5px solid black;
}
如上给box设置所有属性,则盒子的实际占用宽度=410px和高度=210px,外边距margin不包括
替代(IE)盒模型
如果认为设置的宽高就是盒子可见的占据空间的大小,那么CSS当然有这么一个替代盒模型。使用这个模型,所有的宽度都是可见宽度,所以内容区的宽高就是该宽度减去边框盒内边距部分
浏览器默认会使用标准盒模型,如果要使用替代盒模型,则可以设置
box-sizing: border-box
即可,这个属性的默认值为content-box
如果希望所有的元素都使用替代盒模型,可以设置box-sizing
在根元素<html>
上,然后设置所有的元素继承该属性,如下:
html {
box-sizing: border-box;
}
*, *::before, *::after {
box-sizing: inherit;
}
外边距、内边距和边框
外边距-margin
外边距是盒子周围一圈看不到的空间,它会把其他元素从盒子旁边推开。外边距属性值可以为正值也可以为负值,设置负值会导致与其他盒子重叠
平常所写的margin是以下四个属性的简写
- margin-top
- margin-right
- margin-bottom
- margin-left
其中上、下外边距的设置对不可替换的内联元素无效,如<span>
和<code>
等
margin属性接收1-4个值。每个值都可以是<length>
、<percentage>
或auto
- 当只指定一个值时,该值会统一应用到全部四个边的外边距上。
- 指定两个值时,第一个值会应用于上边和下边的外边距,第二个值应用于左边和右边。
- 指定三个值时,第一个值应用于上边,第二个值应用于右边和左边,第三个则应用于下边的外边距。
- 指定四个值时,依次(顺时针方向)作为上边,右边,下边,和左边的外边距。
可取值如下:
<length>
:以固定值为外边距,如1em、10px等<percentage>
:相对于包含块的宽度,以百分比值为外边距- auto:让浏览器自己选择一个合适的外边距。该值可以使元素居中
外边距折叠
是CSS中关于外边距特有的现象是优化页面空间的,这里的折叠指的是垂直方向上两个外边距相接的元素,这些外边距将合并为一个外边距,即最大的单个外边距的大小
垂直外边距会发生重叠
- 相邻的垂直方向外边距会发生重叠现象(包含中间有空元素)
- 兄弟元素
- 兄弟元素间的相邻垂直外边距会取两者之间的较大值(两者都是正值)
- 特殊情况 如果相邻的外边距一正一负,则取两者的和 如果相邻的外边距都是负值,则取两者中绝对值较大的
- 兄弟元素之间的外边距的重叠,对于开发是有利的,所以不许哟啊进行处理
- 父子元素
- 父子元素间相邻外边距,子元素的会传递给父元素(上外边距)
- 父子外边距的折叠会影响到页面的布局,必须要进行处理
边框-border
边框是在边距和填充框之间绘制的,为边框设置样式时,有大量的属性可以使用,每个边框都有样式、宽度和颜色,可以使用border
属性一次设置所有四个边框的宽度、颜色和样式
注意:boder-width不能设置百分值
内边距-padding
内边距位于边框和内容区域之间。与外边距不同的是,内边距不能有负数,必须是0或正值
可以用padding
来简写,也可以为每个单独内边距设置属性
- padding-top
- padding-right
- padding-bottom
- padding-left
其可取值与margin一样,注意一点儿就是百分比是相当于包含块的宽度
包含块
相信小伙伴们都注意到了,文章的前面部分很多次提到了包含块,那么包含块到底是什么呢?
接下来带你一探究竟~
包含块(containing block
):每个盒子都有它的包含块,包含块决定了盒子的排列区域
绝大部分情况下,盒子的包含块为其父元素的内容区
包含块的影响
包含块的重要性不言而喻,元素的尺寸及位置,都会受到包含块的影响。
对于一些属性,例如width
、height
、padding
、margin
、绝对定位元素的偏移值(比如position
被设置为absoulte
或fixed
),当对其赋予百分比值时,这些值的计算就是通过元素的包含块来确定的
确定包含块
确定一个元素的包含块的过程完全依赖于这个元素的position
属性:
-
如果
position
属性为static
、relative
或sticky
,包含块可能由它的最近祖先块元素(如inline-block
、block
或list-item
元素)的内容区的边缘组成,也可能会建立格式化上下文(如a table container
、flex container
、grid container
或者是the block container
自身)这句话的意思表示包含块由以下两种方式确定: - 第一种是最近的祖先块元素的内容区边缘:这意味着元素的包含块会是最近的具有块级格式化上下文的祖先块元素的内容区边缘。这些块元素可能表示block、inline-block或list-item元素 - 第二种就是父元素自身建立的格式化上下文:某些元素自身就具有块级格式化上下文,如table容器、flex容器、grid容器等。在这种情况下,该元素的包含块是由其父元素建立的格式化上下文
-
如果
position
属性为absolute
,包含块就是由它的最近的position
的值不是static
(也就是值为fixed
、absolute
、relative
或sticky
)的祖先元素的内边距区的边缘组成 -
如果
position
属性为fixed
,在连续媒体(如Web页面和移动应用)的情况下包含块是viewport也就是视口,在分页媒体(如打印页面、PDF和电子书)的情况下包含块就是分页区域 -
如果
position
属性是absolute
或fixed
,包含块也可能是由满足以下条件的最近祖先元素的内边距区的边缘组成:- transform或perspective的值不是none
- will-change的值是transform或perspective
- filter的值不是none或will-change的值是filter(只在Firefox下生效)
- contain的值是paint
- backdrop-filter的值不是none
注意:根元素
<html>
所在的包含块是一个被称为初始包含块的矩形。它的尺寸是视口viewport或分页媒体 如果一个元素根据上述规则没有找到包含块,那么其包含块就是根元素<html>
所在的初始包含块
根据包含块计算百分值
如果某些属性被赋予一个百分值的话,那么它的计算值就是由这个元素的包含块计算而来的,这些属性包含盒模型属性和偏移属性
- 要计算
height
、top
及bottom
中百分值,是通过包含块的height
的值。如果包含块的height
值会根据它的内容变化,而且包含块的position
属性的值被赋予relative
或static
,那么这些值得计算为auto - 要计算
width
、left
、right
、padding
、margin
这些属性由包含块的width
属性的值来计算它的百分值
例子1:P元素的position值为absolute,距离它最近的祖先元素的transform值不为none,符合上述规则第4条,所以P元素的包含块是section元素
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>包含块</title>
<style>
body {
background-color: beige;
}
section {
/* position: absolute;
left: 30px;
top: 30px; */
width: 400px;
height: 160px;
/* margin: 30px;
padding: 15px; */
transform: rotate(90deg);
background-color: lightgray;
}
p {
position: absolute;
left: 80px;
top: 30px;
width: 50%;
height: 25%; /* height、top、bottom基于包含块的height,其他都是基于包含块的width */
margin: 5%;
padding: 5%;
/* border: 5% solid red; */ /* border不能设置百分比 */
background-color: cyan;
}
</style>
</head>
<body>
<section>
<p>这是一个包含块</p>
</section>
</body>
</html>
例子2:保持宽高比,这也是像抖音B端网站中的视频布局的例子,容器大小的改变,视频的宽高比例不变,高度为宽度的75%,宽度为父元素的100%
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>保持宽高比</title>
<style>
.container {
width: 40%;
background-color: lightblue;
padding: 20px 40px;
}
.inner {
width: 100%;
/* 如何让高度为宽度的75%? */
/* 第一种方法使用css3新属性-兼容性问题 */
/* aspect-ratio: 4/3; */
/* 第二种方法padding使用百分比是包含块的宽度的百分比 */
padding-bottom: 75%;
height: 0;
background-color: lightseagreen;
position: relative;
}
.main {
position: absolute;
inset: 0;
background-color: gray;
}
</style>
</head>
<body>
<main class="container">
<section class="inner">
<section class="main">主内容</section>
</section>
<p>这里会有一些文字</p>
</main>
</body>
</html>
视觉格式化模型(布局规则)
视觉格式化模型是页面中多个盒子排列规则
其大体将页面中盒子的排列分为三种方式:
- 常规流
- 浮动
- 定位
常规流布局
常规流又称文档流、普通文档流、常规文档流
所有元素,默认情况下都属于常规流布局
总体规则就是:块盒独占一行,行盒水平依次排列
浮动布局
应用场景
- 文字环绕-就是利用文字是匿名行盒排列时会避开浮动元素
- 横向排列
浮动的基本特点
修改float属性值:left为左浮动、right为右浮动,默认为none
-
当一个元素浮动后,元素必定为块盒(更改display属性为block)
-
浮动元素的包含块和常规流一样,为其父元素的内容区
-
盒子尺寸
1. 宽度为auto时,适应内容宽度 2. 高度为auto时,与常规流一致,适应内容的高度 3. margin为auto,为0 4. 边框、内边距的百分比设置与常规流一致
-
盒子排列
1. 左浮动的盒子靠上靠左排列 2. 右浮动的盒子靠上靠右排列 3. 浮动盒子在包含块中排列时,会避开常规流块盒 4. 常规流块盒在排列时,无视浮动盒子 5. 行盒在排列时,会避开浮动盒子
定位布局
position属性用于指定一个元素在文档中的定位方式,top、right、bottom和left属性则决定了该元素的最终位置
定位的类型分为以下四种
- 定位元素:是其计算后位置属性为relative、absolute、fixed或sticky的一个元素(换句话说,除static以外的任何元素)
- 相对定位元素:是计算后位置属性为relative的元素
- 绝对定位元素:是计算后位置属性为absolute或fixed的元素
- 粘性定位元素:是计算后位置属性为sticky的元素
可取值
static
:默认值,指定元素使用正常的布局行为,即元素在文档常规流中当前的布局位置。此时top、right、bottom、left和z-index等属性无效relative
:元素先放置在未添加定位时的位置,在不改变页面布局的前提下调整元素位置(因此会在元素未添加定位时所在位置留下空白),该属性对表格元素无效absolute
:元素会被移出正常文档流,并不为元素预留空间,通过指定元素相对于最近的非static定位祖先元素的偏移,来确定元素位置。决定定位元素可以设置外边距,且不会与其他边距合并fixed
:元素被移出文档流,不会预留空间,而是通过指定元素相对于屏幕视口(viewport)的位置来指定元素。元素的位置在屏幕滚动时不会改变。打印时,元素会出现在每页的固定位置。fixed属性会创建新的层叠上下文。当元素祖先的transform、perspective、filter或backdrop-filter属性非none时,容器由视口改为祖先sticky
:元素根据正常文档流进行定位,然后相对于它的最近滚动祖先和包含块,基于top、right、bottom和left的值进行偏移。偏移值不会影响任何其它元素的位置。该值总是创建一个新的层叠上下文。一个sticky元素会固定在离它最近的一个拥有滚动机制的祖先上(当该祖先的overflow是hidden、scroll、auto或overlay时),即便这个祖先不是最近的真实可滚动祖先
粘性定位的例子:可以被认为是相对定位和固定定位的混合
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title>粘性定位</title>
<style>
* {
box-sizing: border-box;
}
div {
height: 500px;
overflow: auto;
}
dl {
margin: 0;
padding: 24px 0 0 0;
}
dt {
background: #b8c1c8;
border-bottom: 1px solid #989ea4;
border-top: 1px solid #717d85;
color: #fff;
font: bold 18px/21px Helvetica, Arial, sans-serif;
margin: 0;
padding: 2px 0 0 12px;
position: sticky;
top: -1px;
}
dd {
font: bold 20px/45px Helvetica, Arial, sans-serif;
margin: 0;
padding: 0 0 0 12px;
white-space: nowrap;
}
dd + dd {
border-top: 1px solid #ccc;
}
</style>
</head>
<body>
<div>
<dl>
<dt>A</dt>
<dd>Andrew W.K.</dd>
<dd>Apparat</dd>
<dd>Arcade Fire</dd>
<dd>At The Drive-In</dd>
<dd>Aziz Ansari</dd>
</dl>
<dl>
<dt>C</dt>
<dd>Chromeo</dd>
<dd>Common</dd>
<dd>Converge</dd>
<dd>Crystal Castles</dd>
<dd>Cursive</dd>
</dl>
<dl>
<dt>E</dt>
<dd>Explosions In The Sky</dd>
</dl>
<dl>
<dt>T</dt>
<dd>Ted Leo & The Pharmacists</dd>
<dd>T-Pain</dd>
<dd>Thrice</dd>
<dd>TV On The Radio</dd>
<dd>Two Gallants</dd>
</dl>
</div>
</body>
</html>
完结撒花~
转载自:https://juejin.cn/post/7254829363022086199