10_CSS - 布局 - 元素定位

102 阅读6分钟

CSS - 布局 - 元素定位

标准流 - Normal Flow

默认情况下,元素都是按照normal flow(标准流、常规流、正常流、文档流【document flow】)进行排布

  1. 块级元素独占一行,多个行内元素或行内块级元素可以在同一行进行显示
  2. 元素按照从左到右、从上到下按顺序依次摆放好
  3. 默认情况下,元素互相之间不存在层叠现象

Snipaste_2022-10-20_20-48-40.png

在标准流中,可以使用margin、padding对元素进行定位

但是在标准流中,设置一个元素的margin或者padding,通常会影响到标准流中其他元素的定位效果

此外在标准流中,不便于实现元素层叠的效果

为此CSS 提供了position属性,来帮助我们实现将一个元素脱离标准流(脱标),并对其进行定位操作

position属性可选值

说明
static静态定位, 默认值, 不脱标, 即布局为 normal flow
relative相对定位, 不脱标
absolute绝对定位, 脱标
fixed固定定位, 脱标
sticky粘性定位,可以在脱标和不脱标之间切换

固定定位 - fixed

 .box {
   /*
     通过将position的值设置为fixed
     来为某个元素开启相对定位
   */
   position: fixed;
 }

  • 元素脱离normal flow (脱离标准流、脱标)

  • 可以通过left、right、top、bottom进行定位

  • 定位参照对象是视口(viewport),

    • 当画布滚动时,因为viewport是固定不动,所以开启了固定定位的元素也会固定不动

示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .handle {
      position: fixed;
      right: 30px;
      bottom: 30px;
    }

    .handle .item {
      width: 80px;
      height: 40px;
      text-align: center;
      line-height: 40px;
      background-color: brown;
      color: #fff;
      border-radius: 8px;
      cursor: pointer;
    }

    .handle .item:hover {
      background-color: red;
    }

    .top {
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  
  <div class="handle">
    <div class="item top">顶部</div>
    <div class="item bottom">反馈</div>
  </div>

  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>
  <br><br><br><br><br>

</body>
</html>

绝对定位 - absolute

  1. 开启了绝对定位的元素脱离normal flow (脱离标准流、脱标)

  2. 可以通过left、right、top、bottom进行定位

    • 定位参照对象是最邻近的定位祖先元素
    • 如果找不到这样的祖先元素,参照对象是视口

开启了绝对定位的元素的定位参照元素是最近的那个定位元素,也就是最近的那个position不是fixed的元素

而我们绝大多数情况下,都希望父元素不脱标,只是作为绝对定位元素的定位参照元素,

所以在绝大多数情况下,绝对定位元素的定位参照元素开启的都是相对定位

因为相对定位成为了定位元素,但不脱标,此时我们可以简称为 子绝父相

绝对定位元素特点

  1. 可以随意设置宽高且 元素宽高默认由内容决定

    • 此时看上去 特性和行内块级元素的特性是一致的,但是它不是行内块级元素
    • 当一个元素的position值为absolute或者fixed的时候,这个元素就被称之为 绝对定位元素(absolutely positioned element)
  2. 不再受标准流的约束

  • 不再严格按照从上到下、从左到右排布
  • 不再严格区分块级(block)、行内级(inline),行内块级(inline-block)
  1. 不再给父元素汇报自己的宽度或高度
  2. 脱标元素内部默认还是按照标准流布局

此外,对于绝对定位元素来说,存在如下计算方式

定位参照对象的宽度 = left + right + margin-left + margin-right + 绝对定位元素的实际占用宽度 定位参照对象的高度 = top + bottom + margin-top + margin-bottom + 绝对定位元素的实际占用高度

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .father {
      width: 300px;
      height: 300px;
      background-color: red;
      position: relative;
    }

    /*
      此时div.child的参照定位元素为box.father

      fatherWidth = childWidth + left + right + marginLeft + marginRight
      因为 marginLeft 和 marginRight的默认值是0
      得到300 = auto + 0 + 0 + 0 + 0
      所以在这里 auto的值为 300
      因此auto的本质是 由浏览器来决定需要显示的具体值是多少

      高度同理
    */
    .child {
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      background-color: blue;
    }
  </style>
</head>
<body>
  <!-- 绝对定位元素的宽高和定位参照对象一样 -->
  <div class="father">
    <div class="child"></div>
  </div>
</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .father {
      width: 300px;
      height: 300px;
      background-color: red;
      position: relative;
    }

    /*
      此时div.child的参照定位元素为box.father
      tips:
    	1. 一定要设置元素的宽度和高度
    	2. margin四个方向的值都需要设置为auto

      fatherWidth = childWidth + left + right + marginLeft + marginRight
      此时设置childWidth的值为100
      得到 300 = 100 + 0 + 0 + 0 + 0
      公式不成立 => 默认情况下,浏览器会把剩余的值全部赋值给marginRight
      但是这里设置margin各个方向上的值为auto
      => 300 = 100 + 0 + auto + auto
      => 2auto = 300
      => auto = 150
      => marginLeft = marginRight = 150
      => div.child相对于div.father 水平居中


    */
    .child {
      width: 100px;
      height: 100px;
      position: absolute;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      margin: auto;
      background-color: blue;
    }
  </style>
</head>
<body>
  <!-- 绝对定位元素在定位参照对象中居中显示 --- 同时满足水平居中和垂直居中 -->
  <div class="father">
    <div class="child"></div>
  </div>
</body>
</html>

粘性定位 - sticky

另外还有一个定位的值是position: sticky,比起其他定位值要新一些.

sticky可以看做是相对定位和固定(绝对)定位的结合体 --- 在展示效果上

它允许被定位的元素表现得像相对定位一样,直到它滚动到某个阈值点

当达到这个阈值点时, 就会变成固定(绝对)定位

sticky是相对于最近的滚动祖先元素,也就是sticky是相对于滚动视口( scrollport )的

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .nav {
      background-color: #f00;
      color: #fff;

      /* position: relative;
      top: 0;
      left: 0;
      right: 0; */
      position: sticky;
      top: 0;
    }
  </style>
</head>
<body>

  <h1>我是标题</h1>
  <div class="nav">
    <span>电脑</span>
    <span>手机</span>
    <span>衣服</span>
    <span>鞋子</span>
  </div>
  <ul>
    <li>电脑列表1</li>
    <li>电脑列表2</li>
    <li>电脑列表3</li>
    <li>电脑列表4</li>
    <li>电脑列表5</li>
    <li>电脑列表6</li>
    <li>电脑列表7</li>
    <li>电脑列表8</li>
    <li>电脑列表9</li>
    <li>电脑列表10</li>
    <li>电脑列表11</li>
    <li>电脑列表12</li>
    <li>电脑列表13</li>
    <li>电脑列表14</li>
    <li>电脑列表15</li>
    <li>电脑列表16</li>
    <li>电脑列表17</li>
    <li>电脑列表18</li>
    <li>电脑列表19</li>
    <li>电脑列表20</li>
    <li>电脑列表21</li>
    <li>电脑列表22</li>
    <li>电脑列表23</li>
    <li>电脑列表24</li>
    <li>电脑列表25</li>
    <li>电脑列表26</li>
    <li>电脑列表27</li>
    <li>电脑列表28</li>
    <li>电脑列表29</li>
    <li>电脑列表30</li>
    <li>电脑列表31</li>
    <li>电脑列表32</li>
    <li>电脑列表33</li>
    <li>电脑列表34</li>
    <li>电脑列表35</li>
    <li>电脑列表36</li>
    <li>电脑列表37</li>
    <li>电脑列表38</li>
    <li>电脑列表39</li>
    <li>电脑列表40</li>
    <li>电脑列表41</li>
    <li>电脑列表42</li>
    <li>电脑列表43</li>
    <li>电脑列表44</li>
    <li>电脑列表45</li>
    <li>电脑列表46</li>
    <li>电脑列表47</li>
    <li>电脑列表48</li>
    <li>电脑列表49</li>
    <li>电脑列表50</li>
    <li>电脑列表51</li>
    <li>电脑列表52</li>
    <li>电脑列表53</li>
    <li>电脑列表54</li>
    <li>电脑列表55</li>
    <li>电脑列表56</li>
    <li>电脑列表57</li>
    <li>电脑列表58</li>
    <li>电脑列表59</li>
    <li>电脑列表60</li>
    <li>电脑列表61</li>
    <li>电脑列表62</li>
    <li>电脑列表63</li>
    <li>电脑列表64</li>
    <li>电脑列表65</li>
    <li>电脑列表66</li>
    <li>电脑列表67</li>
    <li>电脑列表68</li>
    <li>电脑列表69</li>
    <li>电脑列表70</li>
    <li>电脑列表71</li>
    <li>电脑列表72</li>
    <li>电脑列表73</li>
    <li>电脑列表74</li>
    <li>电脑列表75</li>
    <li>电脑列表76</li>
    <li>电脑列表77</li>
    <li>电脑列表78</li>
    <li>电脑列表79</li>
    <li>电脑列表80</li>
    <li>电脑列表81</li>
    <li>电脑列表82</li>
    <li>电脑列表83</li>
    <li>电脑列表84</li>
    <li>电脑列表85</li>
    <li>电脑列表86</li>
    <li>电脑列表87</li>
    <li>电脑列表88</li>
    <li>电脑列表89</li>
    <li>电脑列表90</li>
    <li>电脑列表91</li>
    <li>电脑列表92</li>
    <li>电脑列表93</li>
    <li>电脑列表94</li>
    <li>电脑列表95</li>
    <li>电脑列表96</li>
    <li>电脑列表97</li>
    <li>电脑列表98</li>
    <li>电脑列表99</li>
    <li>电脑列表100</li>
  </ul>

</body>
</html>

postiton各值比较

Snipaste_2022-10-20_20-57-10.png sticky在效果上是在多个定位状态之间进行切换,所以没有列在表中

对于定位元素,当脱标后,不设置left,right,top,bottom的时候,他们的默认值皆为auto

表现形式为

  1. 尽可能到达父级定位元素的左上角(也就是left和top值为0)
  2. 定位元素后边的元素上移
  3. 定位元素之前的元素不动,且不会被定位元素覆盖

z-index

对于定位元素,默认情况下,写在后面的那个元素会层叠在写在前面的那个元素上

如果我们需要调整定位元素的层叠顺序,我们可以使用z-index

z-index属性用来设置定位元素的层叠顺序(仅对定位元素有效)  取值可以是正整数、负整数、0

z-index的比较原则

  1. 对于兄弟定位元素

    • z-index越大,层叠在越上面
    • z-index相等,写在后面的那个元素层叠在上面
  2. 如果不是兄弟关系

    • 各自从元素自己以及祖先元素中,找出最邻近的那几个兄弟定位元素来进行比较
    • 而且这几个兄弟定位元素必须有设置z-index
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .item {
      position: fixed;
      width: 100px;
      height: 100px;
      left: 0;
      top: 0;
      background-color: #f00;
    }

    .box2 {
      left: 20px;
      top: 20px;
      background-color: #0f0;
      z-index: -1;
    }

    .box3 {
      left: 40px;
      top: 40px;
      background-color: #00f;
    }

    .info {
      position: absolute;
      z-index: 999;
    }
  </style>
</head>
<body>
  
  <div class="item box1">1</div>
  <div class="container">
    <div class="item box2">
      <div class="info">哈哈哈</div>
      <div>呵呵呵</div>
    </div>
  </div>
  <div class="item box3">3</div>

</body>
</html>