likes
comments
collection
share

由「两栏布局」引发的对「元素浮动/flex布局/绝对定位」 的思考

作者站长头像
站长
· 阅读数 58

背景

笔者在工作中遇到不少管理平台类的项目,这些项目往往具有侧边栏内容区这样的布局方式。

笔者遇到这样的需求时,往往通过团队选择的 UI组件库Layout 组件实现效果,这样做的结果是: 需求快速响应了,但失去了锻炼 CSS 的机会。

本着吃透技术的理念,笔者调研了多种CSS实现两栏布局的方案,收获了多种布局知识,现分享出来,希望给掘友们一些启发💡。

两栏布局

需求

两栏布局顾名思义是有2栏目,一个叫左边栏,一个叫右边栏左边栏宽度固定为 100px, 右边栏宽度自适应,所谓自适应就是宽度不固定,它随着屏幕宽度的变化而变化,但始终填满这一行中除去左边栏的剩余空间

初始代码如下:

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>两栏布局</title>
  <style>
    .container {
      background-color: yellowgreen;
    }

    .left {
      width: 100px;
      height: 100px;
      background-color: lightcoral;
    }

    .right {
      background-color: transparent;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="left">左边栏</div>
    <div class="right">右边栏</div>
  </div>
</body>

</html>

实现方案1

1 套方案利用浮动来实现。

左边栏向左浮动,右边栏设置外左边距左边栏的宽度,这样左右布局就做好了,但是左边栏浮动使得父元素不能将左边栏的高度计算进来,造成了经典的高度塌陷问题。

由「两栏布局」引发的对「元素浮动/flex布局/绝对定位」 的思考

这时候就需要清除浮动清除浮动有多种方式,比如:

  1. 给父元素创建一个BFC,如设置 display: flow-root, overflow: hidden 等,BFC 元素的高度会把浮动子元素高度计算进来。
  2. 增加一个末尾元素, 设置 clear:both
  3. 父元素添加一个 ::after 伪元素, 设置 content:''; display:block; clear:both;
  4. 父元素定义height属性,撑开高度不影响后面的元素。

这里笔者给父元素设置了一个 display: flow-root; 的样式,掘友们也可以尝试其他方法来实现,只要让父元素把左边栏的高度计算进来即可,这样就解决了高度塌陷问题。

由「两栏布局」引发的对「元素浮动/flex布局/绝对定位」 的思考

CSS 代码

方案1最终的 CSS 代码如下:

.container {
  /* 可换成其他清除浮动的方式 */
  display: flow-root;
  background-color: yellowgreen;
}

.left {
  float: left;
  width: 100px;
  height: 100px;
  background-color: lightcoral;
}

.right {
  margin-left: 100px;
  background-color: transparent;
}

实现方案2

2 套方案通过 flex 布局来实现。

父元素设置 display: flex 启用 flex 布局,默认 flex-direction 就是 row 的,笔者也把它写出来了(笔者习惯把默认样式写出来,为了更清晰~),这样左右边栏就会排成一行。

然后给右边栏设置 flex: 1,加上以后就实现了右边栏宽度自适应。但是这怎么理解?

flex: 1 是一条简写样式,完整的样式描述是 flex-grow: 1; flex-shrink: 1; flex-basis: 0;

要理解这套样式,首先要理解什么是 flex 布局里的剩余空间

根据MDN的描述,剩余空间是 flex 容器的大小减去所有 flex 项的大小加起来的大小。

理解 flex:1

现在可以来理解 flex:1 了,具体描述是:

flex-grow: 1

flex-grow 这个属性规定了 flex子项flex容器 中分配剩余空间的相对比例。

具体到现在这个场景,由于子项中只有 右边栏 设置了 flex-grow,为 1,所以不需要和别的子项瓜分剩余空间,而是全部占有,正因如此 右边栏 实现了宽度自适应。

flex-shrink: 1

flex-shrink 属性指定了 flex子项 的收缩规则。flex子项 仅在默认宽度之和大于容器的时候才会发生收缩,这里不会发生右边栏宽度超过容器的情况,所以该属性无影响。

flex-basis: 0

flex-basis 属性指定了 flex子项 在主轴方向的初始大小,这里设置为 0 使得剩余空间就是 父元素 减去 左边栏 的宽度,所以 右边栏 能够完全充满剩余空间

CSS 代码

方案2 最终的 CSS代码 如下:

.container {
  display: flex;
  flex-direction: row;
}

.left {
  width: 100px;
  height: 100px;
  background-color: lightcoral;
}

.right {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
  background-color: lightgreen;
}

实现方案3

3 套方案通过 相对/绝对定位 来实现。

首先父元素设置相对定位 position: relative;,然后让左边栏绝对定位 display: absolute,这样左右就排成一行了。

但是,左边栏因为绝对定位脱离了文档流,造成重叠了,左边栏压在右边栏之上:

由「两栏布局」引发的对「元素浮动/flex布局/绝对定位」 的思考

这时,设置右边栏外左边距左边栏宽度,让右边栏被撑出来即可。

.right {
  margin-left: 100px;
  background-color: lightgreen;
}

由「两栏布局」引发的对「元素浮动/flex布局/绝对定位」 的思考

但是,由于绝对定位,此时的父元素高度是不包含左边栏高度的,这时就得手动设置高度了(父元素右边栏都要设置),因为这不是浮动产生的高度塌陷,而是左边栏完全脱离了文档流,不对父元素产生影响了。

.container {
  height: 100px;
  position: relative;
}

.right {
  height: 100%;
  margin-left: 100px;
  background-color: lightgreen;
}

CSS 代码

方案3 最终的 CSS代码 如下:

.container {
  height: 100px;
  position: relative;
}

.left {
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: lightcoral;
}

.right {
  height: 100%;
  margin-left: 100px;
  background-color: lightgreen;
}

总结

本文介绍了「两栏布局」的 3 套解决方案,并简要探讨了每个方案遇到的一些 CSS 知识点,这种遇到问题发散地寻找知识的方式是非常好的学习方法,希望对掘友们有所启发。

(完)

转载自:https://juejin.cn/post/7196227432416264248
评论
请登录