由「两栏布局」引发的对「元素浮动/flex布局/绝对定位」 的思考
背景
笔者在工作中遇到不少管理平台类
的项目,这些项目往往具有侧边栏
加内容区
这样的布局方式。
笔者遇到这样的需求
时,往往通过团队选择的 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
套方案利用浮动
来实现。
左边栏向左浮动
,右边栏设置外左边距
为左边栏的宽度
,这样左右布局
就做好了,但是左边栏浮动使得父元素不能将左边栏的高度计算进来,造成了经典的高度塌陷
问题。
这时候就需要清除浮动
,清除浮动
有多种方式,比如:
- 给父元素创建一个
BFC
,如设置display: flow-root
,overflow: hidden
等,BFC
元素的高度
会把浮动子元素
的高度
计算进来。 - 增加一个末尾元素, 设置
clear:both
。 - 给
父元素
添加一个::after
伪元素, 设置content:''; display:block; clear:both;
。 - 给
父元素
定义height
属性,撑开高度不影响后面的元素。
这里笔者给父元素
设置了一个 display: flow-root;
的样式,掘友们也可以尝试其他方法来实现,只要让父元素
把左边栏的高度计算进来即可,这样就解决了高度塌陷
问题。
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
,这样左右就排成一行了。
但是,左边栏因为绝对定位
脱离了文档流
,造成重叠
了,左边栏
压在右边栏
之上:
这时,设置右边栏
的外左边距
为左边栏
宽度,让右边栏
被撑出来即可。
.right {
margin-left: 100px;
background-color: lightgreen;
}
但是,由于绝对定位
,此时的父元素高度是不包含左边栏
高度的,这时就得手动设置高度了(父元素
和右边栏
都要设置),因为这不是浮动
产生的高度塌陷
,而是左边栏
完全脱离了文档流
,不对父元素
产生影响了。
.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