一、三栏布局

问题:假设高度默认100px ,请写出三栏布局,其中左栏、右栏各为300px,中间自适应。
初学者想到的答案有两种:

  • 方法1:浮动
  • 方法2:绝对定位

    但要求你能至少写出三四种方法,才算及格。剩下的方法如下:

  • 方法3:flexbox。移动开发里经常用到。

  • 方法4:表格布局table。虽然已经淘汰了,但也应该了解。
  • 方法5:网格布局 grid

image.png

浮动

使用 calc

左侧设置左浮动,右侧设置右浮动,中间宽度设置为用 100% 减 左右栏的宽度

  1. <head>
  2. <style>
  3. div {
  4. height: 100px;
  5. background-color: red;
  6. }
  7. .mid {
  8. float: left;
  9. width: calc(100% - 600px);
  10. background-color: aqua;
  11. }
  12. .left {
  13. float: left;
  14. width: 300px;
  15. }
  16. .right {
  17. float: right;
  18. width: 300px;
  19. }
  20. </style>
  21. </head>
  22. <body>
  23. <div class="left"></div>
  24. <div class="mid"></div>
  25. <div class="right"></div>
  26. </body>

使用 margin —— 双飞翼布局

利用浮动以及外边距负值。 一个 container 包裹 middle、left、right。 middle 放在第一个,然后 left、right 通过 margin 将自身偏移到对应左右位置。 这样做 middle 会占整一行,需要在 middle 中添加一个 content,设置 content 的 margin

也就是实际上,middle 的内容都应该放在 content 中。

  1. <head>
  2. <style>
  3. body {
  4. margin: 0;
  5. }
  6. .container {
  7. height: 100px;
  8. }
  9. .container>div {
  10. float: left;
  11. height: 100px;
  12. }
  13. .left,
  14. .right {
  15. background-color: red;
  16. width: 200px;
  17. }
  18. .left {
  19. margin-left: -100%;
  20. }
  21. .right {
  22. margin-left: -200px;
  23. }
  24. .middle {
  25. width: 100%;
  26. background-color: aqua;
  27. }
  28. .content {
  29. margin-left: 200px;
  30. margin-right: 200px;
  31. }
  32. </style>
  33. </head>
  34. <body>
  35. <div class="container">
  36. <div class="middle">
  37. <div class="content">456</div>
  38. </div>
  39. <div class="left"></div>
  40. <div class="right"></div>
  41. </div>
  42. </body>

使用 padding —— 圣杯布局

利用浮动以及内边距。 一个 container 包裹 middle、left、right。给 container 设置左右 padding。 middle 放在第一个,然后 left、right 通过 left/right 属性将自身偏移到对应左右位置。

为什么 left、right 需要偏移呢? 因为 container 设置 padding 后,缩小了 width,不是占一整行。 left 通过 margin-left: 100%偏移值是 container 的 width,不占一整行。

  1. <head>
  2. <style>
  3. body {
  4. margin: 0;
  5. }
  6. .container {
  7. height: 100px;
  8. padding-right: 200px;
  9. padding-left: 200px;
  10. }
  11. .container>div {
  12. float: left;
  13. height: 100px;
  14. }
  15. .left,
  16. .right {
  17. background-color: red;
  18. width: 200px;
  19. }
  20. .left {
  21. margin-left: -100%;
  22. position: relative;
  23. left: -200px;
  24. }
  25. .right {
  26. margin-left: -200px;
  27. position: relative;
  28. right: -200px;
  29. }
  30. .middle {
  31. width: 100%;
  32. background-color: aqua;
  33. }
  34. </style>
  35. </head>
  36. <body>
  37. <div class="container">
  38. <div class="middle"></div>
  39. <div class="left"></div>
  40. <div class="right"></div>
  41. </div>
  42. </body>

绝对定位

使用 div 标签作为容器,包裹左、中、右三个部分。

左侧设置为绝对定位, left:0px。 右侧设置为绝对定位, right:0px。 中间设置为绝对定位,leftright 都为300px,即可。中间的宽度会自适应。

  1. <head>
  2. <style>
  3. div {
  4. height: 100px;
  5. }
  6. .container {
  7. position: relative;
  8. }
  9. .left {
  10. position: absolute;
  11. width: 300px;
  12. left: 0;
  13. background: red;
  14. }
  15. .right {
  16. position: absolute;
  17. width: 300px;
  18. right: 0;
  19. background: red;
  20. }
  21. .mid {
  22. position: absolute;
  23. left: 300px;
  24. right: 300px;
  25. background: aqua;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="container">
  31. <div class="left"></div>
  32. <div class="mid"></div>
  33. <div class="right"></div>
  34. </div>
  35. </body>

flex 布局

将左中右所在的容器设置为display:flex,设置两侧的宽度后,然后让中间的flex: 1 0 auto,即可。

  1. <head>
  2. <style>
  3. div {
  4. height: 100px;
  5. }
  6. .container {
  7. display: flex;
  8. }
  9. .left,
  10. .right {
  11. flex: 0 0 300px;
  12. background-color: red;
  13. }
  14. .mid {
  15. flex: 1 0 auto;
  16. background-color: aqua;
  17. }
  18. </style>
  19. </head>
  20. <body>
  21. <div class="container">
  22. <div class="left"></div>
  23. <div class="mid"></div>
  24. <div class="right"></div>
  25. </div>
  26. </body>

table 布局

设置整个容器的宽度为100%,设置三个部分均为表格,然后左边的单元格为 300px,右边的单元格为 300px,即可。中间的单元格会自适应。

  1. <head>
  2. <style>
  3. div {
  4. height: 100px;
  5. }
  6. .container {
  7. display: table;
  8. width: 100%; /* 设置这个,mid 才能自适应宽度 */
  9. }
  10. .left,
  11. .right {
  12. display: table-cell;
  13. width: 300px;
  14. background-color: red;
  15. }
  16. .mid {
  17. display: table-cell;
  18. background-color: aqua;
  19. }
  20. </style>
  21. </head>
  22. <body>
  23. <div class="container">
  24. <div class="left"></div>
  25. <div class="mid"></div>
  26. <div class="right"></div>
  27. </div>
  28. </body>

grid 布局

使用 div 标签作为容器,包裹左、中、右三个部分。 设置 contianer 为 grid 布局,设置 grid-template-rows 和 grid-template-columns

  1. <head>
  2. <style>
  3. .container {
  4. display: grid;
  5. width: 100%;
  6. grid-template-rows: 100px;
  7. grid-template-columns: 300px auto 300px;
  8. }
  9. .left,
  10. .right {
  11. background-color: red;
  12. }
  13. .mid {
  14. background-color: aqua;
  15. }
  16. </style>
  17. </head>
  18. <body>
  19. <div class="container">
  20. <div class="left"></div>
  21. <div class="mid"></div>
  22. <div class="right"></div>
  23. </div>
  24. </body>

扩展

五种方法的优缺点

  • 考虑中间模块的高度问题
  • 兼容性问题:实际开发中,哪个最实用?

方法1:浮动:

  • 优点:兼容性好。
  • 缺点:浮动会脱离标准文档流,因此要清除浮动。我们解决好这个问题即可。

方法:2:绝对定位

  • 优点:快捷。
  • 缺点:导致子元素也脱离了标准文档流,可实用性差。

方法3:flex 布局(CSS3 中出现的)

  • 优点:解决上面两个方法的不足,flex布局比较完美。移动端基本用 flex布局。

方法4:table 布局

  • 优点:表格布局在很多场景中很实用,兼容性非常好。因为IE8不支持 flex,此时可以尝试表格布局
  • 缺点:因为三个部分都当成了单元格来对待,此时,如果中间的部分变高了,其会部分也会被迫调整高度。但是,在很多场景下,我们并不需要两侧的高度增高。

    什么时候用 flex布局 or table 布局,看具体的场景。二者没有绝对的优势,也没有绝对的不足。

方法5:网格布局

  • CSS3中引入的布局,很好用。代码量简化了很多。

PS:面试提到网格布局,说明我们对新技术是有追求的。

延伸:如果题目中去掉高度已知

问题:题目中,如果去掉高度已知,我们往中间的模块里塞很多内容,让中间的模块撑开。会发生什么变化?哪个布局就不能用了?

答案是:flex 布局、table 布局、grid 布局可以通用,其他三个布局都不能用了。

二、居中布局

水平居中

1. 行内元素

实现在块级元素内部的 行内元素水平居中,对 inlineinline-tableinline-blockinline-flex 元素都有效。

.inline-center-parent {
  text-align: center;
}

2. 块级元素

2.1 使用 margin

.block-center {
  margin: 0 auto;
}

2.2 设置为 inline-block,并在父元素添加 text-align:center

.parent {
  text-align: center;
}
.son {
  display: inline-block;
}

2.3 使用 flex 布局

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

2.4 使用绝对定位

  1. left + transform
    .parent {
    position: relative;
    }
    .son {
    position: absolute;
    left: 50%;
    transform: translateX(-50%)
    }
    

    垂直居中

    1. 单行的行内元素(inline-)元素垂直居中

    将行内元素的 line-heightheight高度设置一致
    .vertical-middle {
    display: inline | inline-table | inline-block | inline-flex;
    height: 高度;
    line-height: 高度;
    }
    

    2. 多行元素垂直居中

    2.1 table 布局 + vertical-align

    ```css .parent { display: table; height: 500px; }

.son { display: table-cell; vertical-align: middle; }

<a name="z6i94"></a>
#### 2.2 flex 布局

1. 主轴为水平方向时,使用 `align-items: center`
```css
.parent {
  display: flex;
  align-items: center;
}
  1. 主轴为垂直方向是,使用justify-content: center

    当然,这只是符合垂直居中的概念,但第二种的效果 和 第一种的效果是不一样的。

.parent {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

3. 块级元素居中(利用定位)

3.1 居中元素高度已知(top + margin-top)

由于元素的 margin 如果设置百分比,是相对于元素的包含块的宽高的。
所以需要元素的高度已知,设置为准确值。

.parent {
  position: relative;
  height: 100vh;
}
.son {
  position: absolute;
  height: 100px;
  top: 50%;
  margin: -50px;
}

缺点:父元素空间不够时, 子元素可能不可见(当浏览器窗口缩小时,滚动条不出现时)

3.2 居中元素高度未知(top + transform)

.parent {
  position: relative;
  height: 100vh;
}

.son {
  position: absolute;
  height: 100px;
  top: 50%;
  transform: translateY(-50%);
}

3.3 居中元素高度未知(top & bottom: 0)

.parent {
  position: relative;
  height: 100vh;
}

.son {
  position: absolute;
  height: 100px;
  top: 0;
  bottom: 0;
  margin: auto 0; /* 这个起关键作用 */
}

水平垂直居中

1. 已知宽高的元素(绝对定位 + margin)

.parent {
  position: relative;
  height: 100vh;
}

.son {
  position: absolute;
  width: 200px;
  height: 200px;
  top: 50%;
  left: 50%;
  margin-top: -100px;
  margin-left: -100px;
}

2. 未知宽高的元素(绝对定位 + transform)

.parent {
  position: relative;
  height: 100vh;
}

.son {
  position: absolute;
  width: 200px;
  height: 200px;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%)
}

3. 未知宽高的元素(flex 布局)

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

4. 未知宽高的元素(grid 布局)

.parent {
  display: grid;
  height: 100vh;
}
.son {
  margin: auto;
}