Skip to content

视觉格式化模型这一块,我们前面提到了两种布局方式,分别是常规流和浮动,常规流其实就是从上往下的一种默认布局。而如果我们要实现横向的布局,就要使用浮动。如果只靠以上两种布局方式,我们其实可以实现大多数网页的布局,但对于一些特殊的布局,常规流和浮动其实是无能为力,或者实现起来太过复杂。

![recording 2](/notes-assets/01.HTML&CSS/2.CSS基础/assets/recording 2.gif)

可以看到,在 b 站,滚动屏幕的时候,顶部的导航条是固定的,不会随着我屏幕滚动而滚动,这种效果想用常规流和浮动是完全不可能实现的,此时就需要使用到定位这一种布局方式。

除此之外,像下图这种效果:

![Pasted image 20240219172459](/notes-assets/01.HTML&CSS/2.CSS基础/assets/Pasted image 20240219172459.png)

我要让小圆点在左下角这个位置,使用过常规流布局其实是可以做到的,但是效果不好,也相对麻烦,此时就应该使用定位布局。

定位可以允许我们手动控制元素在包含块中的精准位置,例如我要让元素位于包含块中 (19 px, 19 px)这一坐标位位置,如果使用常规流布局,可以设置 margin 实现,但如果元素一多,设置 margin 就会让元素之间的排列很混乱,此时用定位是最优选择。

定位只涉及到如下属性:

  • position
  • left
  • top
  • right
  • bottom

后面四个其实不用介绍,我们要把一个元素定位到一个具体的坐标,这个具体的坐标就由后面四个属性来给出。

定位最核心的属性是 position,这个属性用来选择定位的类型,这个属性默认值为 static,即默认为静态定位,静态定位其实就是不定位。我们常见的定位有三种,分别是相对定位,绝对定位,固定定位,分别对应的 position 属性为 relative, absolute, fixed。

一个元素 position 的默认值为 static,只要一个元素的 position 属性不为 static,我们称其是定位元素。

这三种定位适用于不同的场景,例如给定一个坐标,我要指定这个元素要位于其包含块的某一个坐标的位置,就是用绝对定位,而如果我要让这个元素相对于自己往其他方向移动几个像素,就是用相对定位,我要让元素相对于视口,或者说是始终固定在浏览器的某个位置,就用固定定位。

可以看到,绝对定位可以把元素定位在包含块的指定位置,固定定位可以把元素定位在浏览器的某个位置(或者说视口的某个固定位置 ),而相对定位不太一样,是相对于自己本身,往上下左右移动一些距离。既然相对定位是相对于自己,那么相对定位其实并不会脱离文档流,但使用绝对定位和固定定位,是会直接脱离文档流的。

脱离文档流这个概念,在浮动那里我们介绍过, 因为浮动元素就是典型的脱离文档流的元素,在浮动那里,我们其实可以得到脱离文档流元素的两个特点:

  • 文档流中元素排列的时候,是看不到脱离文档流的元素的。
  • 文档流中的元素计算自动高度(height 属性为 auto)的时候,会忽略脱离了文档流的元素。

综上,由于绝对定位和固定定位脱离了文档流,所以文档流中元素在排列的时候是看不到绝对定位和固定定位元素的。同时,文档流中的元素在计算自动高度的时候,也看不到其内部的绝对定位和固定定位元素。而相对定位则不同,相对定位是在元素原来的位置上进行一个偏移,这并不会脱离文档流。

上面对定位做了总体介绍,下面挨个介绍一下,首先是最简单的相对定位

![recording 3](/notes-assets/01.HTML&CSS/2.CSS基础/assets/recording 3.gif)

可以看到,这里原来是几个常规流的盒子,当我给其中某一个盒子设置为相对定位,即 position 属性设置为 relative 之后,其就变成了定位元素。前面提到过,相对定位并不会脱离文档流,所以它后面的常规流元素在排列的时候还是会排列在其后面,或者说能看到它,会避开它排列。

当设置相对定位的目的是让元素在原来的位置进行偏移。而具体怎么偏移,偏移多少,则是由 left, right, top, bottom 这四个属性来确定的,比如我设置 top:20px;left:30px 表示这个元素在它原来位置的基础上,上面有 20 像素,左边有 30 像素,其实相当于向下、向右分别偏移了 20 像素和 30 像素。读者也能看到,这个偏移只是视觉上的偏移,并不会改变其他元素的排列。

相对定位并不会改变盒子的 display 属性,这一点有别于后面两种定位

我们这里一共有 4 个属性可以设置相对定位的偏移距离,但里面有冲突的属性,例如设置了 left 之后设置 right,分别表示距离原来左边偏移和距离原来的右边偏移,或者向右偏移和向左偏移。这里我们要避免使用这种冲突的属性。对于一个元素我们最多可以设置两个属性。如果出现冲突属性,left 和 right 冲突,以 left 为准,top 和 bottom 冲突以 top 为准。

以上其实就介绍完了相对定位,另外两种定位分别是绝对定位和固定定位。

首先是绝对定位,这里先说一下元素的位置如何来表达,元素的位置是根据坐标来表达的,每一个元素都有一个坐标轴,这个坐标轴以元素的左上角为原点,向右为 x 轴正方形,向下为 y 轴正方向。在整个页面有一个大的坐标轴,也是向右为 x 轴正方向,向下为 y 轴正方向。页面最左上角为坐标原点。

绝对定位,就可以把一个元素的位置强制放到某一个位置上去,或者说让一个元素定位到其包含块的某个坐标上去。

当元素被设置为绝对定位之后,其脱离了文档流,所有常规流元素是完全看不见的。在浮动中,设置为浮动的元素也脱离了文档流,其宽高默认 auto 的时候,其实也就是由内容撑开的。实际上和浮动非常类似,将元素设置为绝对定位之后,元素的 display 属性也会强制设置为 block。

这里要记住一个细节,在前面常规流和浮动中,一个元素的包含块始终是其父元素的 content-box 区域。但是绝对定位元素的包含块会改变,并不一定是其父元素的 content-box。当我们讲一个元素设置绝对定位之后,我们一层一层找它的祖先元素,找到第一个定位元素,这个元素的 padding-box 就是该元素的包含块。

我们来看一下下面的例子:

html
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>box</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }
        .box1 {
            height: 300px;
            width: 300px;
            margin: 0 auto;
            border: 1px solid;
        }
        .box2 {
            height: 200px;
            width: 200px;
            margin: 0 auto;
            border: 1px solid;
        }
        .box3 {
            height: 50px;
            width: 50px;
            background-color: aqua;
        }
    </style>
</head>
<body>
    <div class="box1">
        <div class="box2">
            <div class="box3"></div>
        </div>
    </div>
</body>
</html>

![Pasted image 20240221162949](/notes-assets/01.HTML&CSS/2.CSS基础/assets/Pasted image 20240221162949.png)

效果如上图所示,接下来我们将 box3 设置为绝对定位,然后让它 top:0;left:0;,即让它位置处于包含块的最左上角。

![Pasted image 20240221163112](/notes-assets/01.HTML&CSS/2.CSS基础/assets/Pasted image 20240221163112.png)

很显然,此时其包含块肯定不是 box1 和 box2,由于其所有祖先元素都不是定位元素,对于这种情况,它的包含块为初始包含块,在大多数浏览器中,初始包含块是整个网页。

接下来我们将 box 1 设置为定位元素。

![Pasted image 20240221164144](/notes-assets/01.HTML&CSS/2.CSS基础/assets/Pasted image 20240221164144.png)

效果就是这样,由于 box 1 是 box 3 的第一个祖先定位元素,所以这个 box 1 的 padding-box 就是其包含块,所以 box 3 就会处于上图的位置。

一般来说,如果我们要让一个小元素盖在另一个元素的某个指定位置,就要使用绝对定位,例如最开始提到的轮播图游标。而且我们要让一个元素覆盖在另一个元素上,那这个另一个元素,就应该是这个元素的包含块,为了让它成为包含块的同时不改变其位置,一般会强制设置为相对定位。实际上,相对定位最主要的用途就是讲一个元素变成一个绝对定位元素的包含块。

最后一种定位为固定定位,固定定位非常简单,就是一种特殊的绝对定位,唯一的区别就是包含块,在绝对定位中,包含块是其祖先元素的第一个定位元素,只有所有祖先元素都不是定位元素的情况下,其包含块就是初始包含块。而固定定位的祖先元素一定是视口。

注:初始包含块并不等于视口,初始包含块可以认为是 html 元素的区域,视口则是浏览器可视区域。

对于定宽定高的绝对定位元素,我们可以让它水平垂直居中。

css
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
margin:auto;

这样其实就实现了水平垂直居中,我们可以看到,left 和 right 是有矛盾的,都必须是 0,此时是按照 left 的,这个我们前面说过,当我们设置了 margin 为 auto,这个时候它就有了一个出路,也就是可以通过调整 margin 的值来实现 left 和 right 都是 0,此时就是实现了居中,同样,垂直也一样。

这里其实还有一个问题,就是定位不同于常规流,定位经常用来做重叠效果,也就是一个元素叠在另一个元素的上面。这个时候就涉及到一个问题,谁在上面谁在下面。这个是可以通过 z-index 属性来设置的,z-index 属性的值越大,越靠近用户。该值默认为 auto,通常情况下为 0。如果两个元素的 z-index 值一样,HTML 中写在后面的元素会越靠近用户。

只有定位元素可以通过 z-index 改变层叠关系。但如果 z-index 的值为负数,则常规流元素和浮动元素会覆盖定位元素。

^ee6d2b

绝对定位和固定定位的元素,不仅 display 属性会强制为 block,float 属性也会强制变为 none。同时也没有外边距合并的问题。

以笔记为镜,可以知得失