CSS理论实践之《布局》

214 阅读7分钟

基础知识

盒模型

模型定义了盒的每个部分 —— margin, border, padding, 和 content —— 合在一起就可以创建我们在页面上看到的内容。

  • 标准盒模型:元素的width和height仅指content区域,不包括 border 与 padding。如下图1
  • IE盒模型:元素的width和height = content区域 + border + padding组成。如下图2

标准盒模型
IE盒模型

注意:margin 不计入实际大小 —— 当然,它会影响盒子在页面所占空间,但是影响的是盒子外部空间。盒子的范围到边框为止 —— 不会延伸到margin。

box-sizing属性

  • context-box:默认值,即标准盒模型,只计算内容区域。
  • border-box:IE盒模型,即 border和padding也计算入宽度或高度之内。

BFC

块级格式化上下文,规定了内部的 Block-level Box 如何布局,并且与这个区域外部毫不相干。 BFC布局规则 BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

  • BFC 这个元素的垂直方向的边距会发生重叠,垂直方向的距离由margin决定,取最大值。
  • BFC 可以包含浮动的元素(用来清除浮动)。
  • BFC 可以阻止元素被浮动元素覆盖。

哪些元素会生成 BFC:

  • 根元素body
  • float 属性不为 none
  • position 为 absolute 或 fixed
  • display 为 inline-block, table-cell, table-caption, flex, inline-flex
  • overflow 不为 visible

正常布局流

块元素独占一行,行内元素共享一行。

浮动

元素脱离文档流,同时让内容环绕其展示。

清除浮动的方法有:

  1. 最常见的方案是:在容器内添加一个CSS伪元素,并将其属性设置为clear:both
  2. 在容器内创建BFC。overflow设置为visible以外的属性或者设置display:flow-root

定位

元素从正常流中移除,或者改变其在正常文档流中的位置。共有static(默认)relativeabsolutefixedsticky(粘性)五种定位方式。

弹性布局

在弹性布局中,分为容器和轴,所有的属性都是围绕容器和轴设置的。 其中,容器分为父容器子容器。轴分为主轴交叉轴(主轴默认为水平方向,方向向右,交叉轴为主轴顺时针旋转 90°)

父容器属性

父容器上的6个属性:

  • flex-direction:主轴方向。值有:rowcolumnrow-reversecolumn-reverse
  • flex-wrap:超出父容器后子容器的排列样式。值有:nowrapwrapwrap-reverse
  • flex-flow:flex-direction与flex-wrap的简写。
  • justify-content: 子容器主轴的排列方向。值有:flex-start(默认)、flex-endcenterspace-betweenspace-around
  • align-items: 子容器在交叉轴的排列方向。值有flex-startflex-endcenterbaseline(按第一行文字基线对齐)、stretch默认
  • align-content:"多条主轴,即子容器行"的对齐方向。对单行弹性盒子模型无效。

align-itemsalign-content区别:

  1. align-items属性是针对单独的每一个flex子项起作用,它的基本单位是每一个子项,在所有情况下都有效果。
  2. align-content属性是将flex子项行作为一个整体起作用,它的基本单位是子项构成的行。 且只在两种情况下有效果:
  • 子项多行,flex容器高度固定
  • 子项单行,flex容器高度固定且设置了flex-wrap:wrap

子容器属性

子容器也有6个属性:

  • order:子容器的排列顺序。数值越小,排列越靠前,默认为0。
  • flex-grow:子容器剩余空间的拉伸比例。默认0,即如果存在剩余空间,也不拉伸放大。
  • flex-shrink:子容器超出空间的压缩比例。默认1,即如果空间不足,将被缩小。
  • flex-basis:子容器在不拉伸情况下的原始尺寸。默认auto。
  • flex:是flex-grow、flex-shrink、flex-basis三者的简写。默认为 flex: 0 1 auto
  • align-self:设置单独对齐方式,可覆盖align-items。值为:autoflex-startflex-endcenterbaselinestretch

网格布局

CSS网格布局是一种用来进行二维布局的技术。二维意味着你希望按照行和列来排布你的内容。

和弹性盒子类似,网格布局也需要设置一个display值。你可以为容器元素设置display: grid,并且使用grid-template-columnsgrid-template-rows属性来控制网格中的行与列。 fr是一种弹性单位。grid-gap来保证元素间的间距。repeat() 属性可以创建重复的网格轨道,比如repeat(2,100px)

  • 一个被设置为display: grid的元素就是所谓的网格容器
  • 在网格容器中会有网格线,网格线就是你在指定grid-template-columnsgrid-template-rows时网格中行列所生成的。
  • 网格中的最小单位(也就是被四条网格线截取生成的区域)被成为网格单元格
  • 由若干个单元格组成的矩形区域被成为网格区域

网络布局中定位元素有两种方法:基于行/列与通过命名区域

  1. 基于行/列:比如一个2*2的网格区域,指定元素从第一行开始到第三行、从第一列开始到第三列,这样就可以覆盖到四个单元格。
.item {
    grid-column-start: 1;
    grid-column-end: 3;
    grid-row-start: 1;
    grid-row-end: 3;
}

也可以缩写成:

.item {
    grid-column: 1 / 3;
    grid-row: 1 / 3;
}
  1. 通过命名区域:需要给每个元素一个名字,然后通过grid-template-areas属性的值来描述布局方式。合并单元格时需要重复元素的名字,留空时需要使用.这个值。
.container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    grid-template-areas: 
     "a a b b"
     "a a c .";
}

假如要绘制出如下布局

网络布局

采用行/列定位方式时,实现如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            box-sizing: border-box;
        }

        .container {
            width: 500px;
            border: 1px solid grey;
            padding: 5px;
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            grid-gap: 20px;
        }

        .container > div {
            background-color: rgba(111, 41, 97, .3);
            text-align: center;
        }

        .one {
            grid-column: 1 / 4;
            grid-row: 1;
        }

        .two {
            grid-column: 1;
            grid-row: 2;
        }

        .three {
            grid-column: 2 / 4;
            grid-row: 2;
        }

        .four {
            grid-column: 3 / 4;
            grid-row: 3 / 5;
        }

        .five {
            grid-column: 1 / 3;
            grid-row: 4;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="one">1</div>
    <div class="two">2</div>
    <div class="three">3</div>
    <div class="four">4</div>
    <div class="five">5</div>
</div>
</body>
</html>

换成命名区域方式时,实现如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        * {
            box-sizing: border-box;
        }

        .container {
            width: 500px;
            border: 1px solid grey;
            padding: 5px;
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            grid-gap: 20px;
            grid-template-areas: "a a a" "b c c" ". . d" "e e d"
        }

        .container > div {
            background-color: rgba(111, 41, 97, .3);
            text-align: center;
        }

        .one {
            grid-area: a;
        }

        .two {
            grid-area: b;
        }

        .three {
            grid-area: c;
        }

        .four {
            grid-area: d;
        }

        .five {
            grid-area: e;
        }


    </style>
</head>
<body>
<div class="container">
    <div class="one">1</div>
    <div class="two">2</div>
    <div class="three">3</div>
    <div class="four">4</div>
    <div class="five">5</div>
</div>
</body>
</html>

应用

水平居中

  • 行内元素:对父元素设置text-align:center
  • 定宽块状元素: 设置左右margin: 0 auto
  • 不定宽块状元素: absolute+translateX方式
.item{
    position: absolute;
    left: 50%;
    transform: translateX(-50%)
}
  • 通用方案: flex布局,对父元素设置 display:flex; justify-content:center

垂直居中

  • 行内元素:设置父元素的display:table-cell或inline-block,再设置vertical-align:middle;
  • 块状元素: 父元素要设置定位为static以外的值,子元素position:absolute 并设置top、bottom为0,margin:auto;
.item{
    position: absolute; 
    top: 0;
    bottom: 0;
    margin: auto;
}
  • 不定高块状元素:absolute+translateY方式
.item{
    position: absolute;
    top: 50%;
    transform: translateY(-50%)
}
  • 通用方案: flex布局,给父元素设置display:flex; align-items:center