CSS 布局实践 | 青训营

53 阅读9分钟

CSS 布局实践

常见的 CSS 布局单位

  1. 像素 px:

    • CSS像素:为web开发者提供,在 CSS 中使用的一个抽象单位
    • 物理像素:与硬件密度有关
    • 一个CSS像素可对应多个物理像素
  2. 百分比 %:相对于直接父元素

  3. 相对长度单位

    • em:相对于父元素的 font-size,默认 16 px
    • rem:相对于根元素的 font-size
  4. 视口相关单位

    • vw:视窗宽度的百分之一
    • vh:视窗高度的百分之一
    • vmin:vw 和 vh 中的最小值
    • vmax:vw 和 vh 中的最大值

应用场景:

  • 使用 px:适配少部分移动设备,且分辨率对页面影响不大
  • 使用 rem:适配各种移动设备(例如 iPhone 和 iPad等分辨率差别比较大的设备)

两栏布局

一般的两栏布局:左边一栏宽度固定,右边一栏宽度自适应

实现:

  1. 浮动法
  • 左边元素宽度固定设置为 200px,并且设置左浮动
  • 右边元素的 margin-left 设置为 200px,宽度设置为 auto(撑满整个父元素)
  •     .outer {
            height: 100px;
        }
    
        .left {
            float: left;
            width: 200px;
        }
    
        .right {
            margin-left: 200px;
            width: auto;
        }
    
  1. BFC法
  • 左边元素同上

  • 右边元素设置 overflow:hidden; 触发BFC,不会与浮动元素发生重叠

  •     .outer {
            height: 100px;
        }
    
        .left {
            float: left;
            width: 200px;
        }
    
        .right {
            margin-left: 200px;
            overflow: hidden;
        }
    
  • BFC,Block Formmatting Context,块级格式化上下文,形成一个完全独立的布局环境

  • 触发 BFC 的 CSS 属性

    • overflow: hidden

    • display: inline-block

    • position: absolute

    • position: fixed

    • display: table-cell

    • display: flex

    • BFC 解决的问题:

      1. float 脱离文档流,高度塌陷
      2. margin 边距重叠
      3. 两栏布局

3. 利用 flex

  • 左边设置固定宽度
  • 右边设置 flex1
  • .outer {
        display: flex;
        height: 100px;
    }
    
    .left {
        width: 200px;
    }
    
    .right {
        flex: 1;
    }
    

4. 利用绝对定位,父级元素设置为相对定位

  • 左边元素绝对定位,并且宽度设置为 200 px
  • 右边元素 margin-left 设置为 200px
  • .outer {
        position: relative;
        height: 100px;
    }
    
    .left {
        position: absolute;
        width: 200px;
        height: 100px;
    }
    
    .right {
        margin-left: 200px;
    }
    

5. 利用绝对定位,父级元素设置为相对定位

  • 左边元素设置宽度 200px
  • 右边元素使用绝对定位,左边定位为 200px,其余定位为0
  • .outer {
        position: relative;
        height: 100px;
    }
    
    .left {
        width: 200px;
    }
    
    .right {
        position: absolute;
        left: 200px;
        top: 0;
        right: 0;
        bottom: 0;
    }
    

6. grid 布局

  • 父元素设置 grid 布局,然后设置每列元素的宽度
  • .outer {
      display: grid;
      grid-template-columns: 200px 1fr; /* fr 是比例系数, 如果只有一个设置了 fr, 则占满剩余空间 */
    }
    

三栏布局

三栏布局一般指:页面左右两栏宽度固定,中间自适应

实现:

  1. 利用绝对定位

    • 左右两栏设置为绝对定位,中间设置对应方向的 margin 值
    • .outer {
          position: relative;
          height: 100px;
      }
      .left {
          position: absolute;
          width: 100px;
          height: 100px;
      }
      .right {
          position: absolute;
          top: 0;
          right: 0;
          width: 200px;
          height: 100px;
      }
      .center {
          margin-left: 100px;
          margin-right: 200px;
          height: 100px;
      }
      
  2. 利用 flex 局部

    • 左右固定大小,中间设置 flex:1
    • .outer {
          display: flex;
          height: 100px;
      }
      .left {
          width: 100px;
          height: 100px;
      }
      .right {
          width: 200px;
          height: 100px;
      }
      .center {
          flex: 1;
      }
      
  3. 利用浮动

    • 左右两栏设置固定大小,并设置对应方向的浮动

    • 中间一栏在 html 中应该放在左右元素之后,中间一栏设置左右方向的 margin

    • .outer {
          height: 100px;
      }
      .left {
          float: left;
          width: 100px;
          height: 100px;
      }
      .right {
          float: right;
          width: 200px;
          height: 100px;
      }
      .center {
          margin-left: 100px;
          margin-right: 200px;
          height: 100px;
      }
      
    • 如果 html 顺序为

    image.png

    image.png

    原因:浮动的定位元素是上一个未浮动的元素

  4. 圣杯布局,利用浮动和负边距实现

    • 父级元素设置左右的 padding

    • 三列均设置向左浮动,html 中间一列放在最前面,可以先将主要内容渲染

    • 宽度设置未父级元素的宽度,因此后面两列都被挤到了下一行,通过设置 margin 赋值将其移动到上一行,再利用相对定位,定位到两边

    •  <div class="outer">
              <div class="center">C</div>
              <div class="left">L</div>
              <div class="right">R</div>
      </div>
      
      <style>
      .outer {
          height: 100px;
          padding-left: 100px;
          padding-right: 200px;
      }
      .left {
          float: left;
          /* 负margin 让元素的左边外框移动到 center 的左边*/
          margin-left: -100%; /* 百分比的参考是center(上一个元素)的宽度 */
      
          /* 相对定位 让元素向左移自身的宽度 */
          position: relative;
          left: -100px;
      
          width: 100px;
          height: 100px;
      
      }
      .right {
          float: left;  /* 此处也可以右浮动,结果不变 */
          margin-left: -200px; /* 自身的宽度 */
      
          position: relative;
          left: 200px;  /* 向右移自身的宽度 */  
      
          width: 200px;
          height: 100px;
      
      }
      .center {
          float: left;
          width: 100%;
          height: 100px;
          } 
      </style>
      
      
    • 右元素也可以设置为右浮动,解释如下:

      首先,float 是元素会根据设置的属性值向左或者向右浮动,直到它的外边缘碰到包含框另一个浮动框的边框为止。

      本来 outer 的 width 就已经被 center 完全占满(右元素相对于父元素 outer 浮动,无法待在outer那一行)了,元素会溢出,下移一行;margin-left 负值让 float 浮动的起点向左移动,让其可以相对于另一个浮动元素 center 进行浮动,不再溢出,从而可以移到上一行(center 所在的行)

  5. 双飞翼布局

    • 相对于圣杯布局来说,左右位置的保留是通过中间列(需要增加一个 wrapper 包裹)的 margin 值来实现的,而不是父元素的 padding。本质上来说,也是通过浮动和外边距负值来实现的
    • <div class="outer">
              <div class="wrapper">
                  <div class="center">C</div>
              </div>
              <div class="left">L</div>
              <div class="right">R</div>
      </div>
      
      <style>
      .outer {
          height: 100px;
      }
      
      .left {
          float: left;
          margin-left: -100%;
        
          width: 100px;
          height: 100px;
      }
      .right {
          float: left;
          margin-left: 200px;
        
          width: 200px;
          height: 100px;
      }
      
      /* 中间列的外包裹 */
      .wrapper {
          float: left;
          width: 100%;
          height: 100px;
      }
      .center {
          margin-left: 100px;
          margin-right: 200px;
          height: 100px;
      }
      </style>
      

margin 负值的原理

margin的值(正值)是根据参考线向下或向右计算的

  • top 和 left 的参考线是上(左)一个元素的下(右)margin 外框
  • bottom 和 right 的参考线是本元素的下(右)content 外框 image.png

当一个元素的 margin 值是负值时,会向左(上)移动

  • left 和 top 本质是改变了参考线(向左移或向上移)
  • 不同于 position: absolute 的是,其后的元素会跟随移动

margin 负值的用途:

  • 实现水平垂直居中

    <div class="absolute"></div>
    <style>
    .absolute {
        position: absolute;
        top: 50%;
        left: 50%;  /* 通过绝对定位,将元素左上角的点移动到父元素中心点 */
      
        width: 200px;
        height: 100px;
    
        margin-left: -100px;
        margin-top: -50px;  /* 通过负margin,移动本元素宽度或高度的一半 */
      
        /*
        对于不确定本元素宽高的情况,可以用以下代替负 margin
        transform: translate3d(-50%, -50%, 0);  
        */
        background-color: #ccc;
    }
    </style>
    
  • 圣杯布局

  • 双飞翼布局

水平垂直居中的实现

  1. 自身位移法

    利用绝对定位,先将元素的左上角通过 top:50%; left:50%; 定位到父元素的中心,再通过 tanslate 调整元素的中心点到父元素的中心。需要考虑浏览器兼容问题

    .parent {
        position: relative;
    }
    
    .child {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
    
  2. margin 拉开法

    利用绝对定位,设置四个方向的值都是0,然后将 margin 设置为 auto,由于宽高固定,因此可以实现对应方向平分,即水平垂直居中。该方法适合盒子有宽高的情况

    .parent {
        position: relative;
    }
    .child {
        position: absolute;
        top: 0;
        bottom: 0;
        left: 0;
        right: 0;
        margin: auto;
    }
    
  3. 负 margin 位移法

    利用绝对定位,将元素左上角调整到父元素中心,然后通过 负 margin 值调整元素中心到父元素中心。需要已知盒子宽高

    .parent {
        position: relative;
    }
    .child {
        position: absolute;
        top: 50%;
        left: 50%;
    
        width: 100px;
        height: 200px;
    
        margin-top: -100px; /* 自身高度的一半 */
        margin-left: -50px; /* 自身宽度的一半 */
    }
    
  4. flex 布局法

    通过 align-items: center;​​ justify-content: center;​​ 设置水平垂直居中。需要考虑兼容问题,多用于移动端

    .parent {
        display: flex;
        align-items: center;
        justify-content: center;
    }
    

flex 布局

部分图片来源:阮一峰的 flex 笔记

任何一个容器都可以指定 flex 布局,包括行内元素

设置 flex 布局后,

  • 本元素被称为 flex 容器 container,
  • 子元素自动成为容器成员,即项目 item,子元素的 float​​、clear​​ 和 vertical-align​​ 属性将失效。
  • 容器默认存在两根轴,水平的主轴(main axis)和垂直的交叉轴(cross axis),项目默认沿水平主轴排列

设置在容器上的属性

  • flex-direction​​ 决定主轴的方向(交叉轴始终与主轴垂直)

  • flex-wrap​​ 定义如果一条轴线排不下,是否换行

    image.png

  • flex-flow​​ 是 前两个属性 flex-direction 和 flex-wrap 的简写形式,默认值为 row nowrap;

  • justify-content​​ 定义项目在主轴上的对齐方式

    image.png

  • align-items​​ 定义项目在交叉轴的对齐方式

    image.png

  • align-content​​ 定义多跟轴线的对齐方式,如果项目只有一根轴线,则该属性不起作用

    image.png

设置在项目上的属性

  • order​​ ​定义项目的排列顺序,数值越小,排列越靠前,默认为0

    image.png

  • flex-grow​​ 定义项目的占用剩余空间(如果有)的放大比例

    image.png

    • 默认为0,即如果存在剩余空间也不放大
    • 如果所有项目的 flex-grow 属性都为1,则它们等分剩余空间
    • 如果某一个项目为1,其余项目为2,则前者占用剩余空间是其他的2倍
  • flex-shrink​​ 定义项目的在空间不足时的缩小比例

    image.png

    • 默认值为 1,即如果空间不足,该项目将缩小
    • 如果所有项目的值都为1,则等比例缩小
    • 如果有某个项目值为0,则其他项目缩小,该项目不缩小
  • flex-basis​​ 定义在分配多余空间之前,项目占据的主轴空间

    • 浏览器根据这个属性,计算主轴是否有空余空间
    • 默认值为 auto,即项目本来的大小
    • 可以设置跟 width 或 height 属性一样的值(比 width 和 height 优先级更高),则项目将占据固定空间
  • flex​​ 是 flex-grow flex-shrink 和 flex-basis 的缩写

    • 默认值为 0 1 auto,后两个属性可选
    • 快捷值: auto​​ (1 1 auto) 和 none​​ (0 0 auto)
    • 优先使用该属性,而不是单独写三个属性,因为浏览器会推算相关值
  • align-self​​ 允许单个项目于其他项目有不一样的对齐方式,覆盖 align-items 属性

    image.png

    • 默认值为 auto,表示继承父元素的 align-items 属性,如果没有父元素,则等同于 stretch
  • justify-self​​ 允许单个项目不同于其他项目的对齐方式,覆盖 justify-content 属性

flex: 1

意味着

  • flex-grow:1 存在剩余空间,则放大比例为1
  • flex-shrink:1 空间不足,项目缩小比例为1
  • flex-basis: 0% 计算项目是否有空余空间时,项目本身的大小为 0%(相对于容器主轴尺寸)

可以用来自动填充剩余空间(多余的或不足的)

流式布局

百分比布局,常用于移动端开发。

元素可以设置宽高的最值,然后给元素设置百分比宽度。

瀑布流布局

视觉表现为参差不齐的多栏布局。

瀑布流布局的优点

  • 节省空间,外表美观,更有艺术性。
  • 对于触屏设备非常友好,通过向上滑动浏览
  • 用户浏览时的观赏和思维不容易被打断,留存更容易。

瀑布流布局的缺点

  • 用户无法了解内容总长度,对内容没有宏观掌控。
  • 用户无法了解现在所处的具体位置,不知道离终点还有多远。
  • 回溯时不容易定位到之前看到的内容。
  • 容易造成页面加载的负荷。
  • 容易造成用户浏览的疲劳,没有短暂的休息时间。