固定宽度的侧边栏配合自适应的中间内容区,是后台管理系统、文档站点、博客页面里出现频率最高的布局之一。很多人上来就写width: 200px和width: 100%,结果发现侧边栏被挤扁、内容区溢出滚动条、窗口缩小后整个版面错乱。这篇文章把实现这种布局的主流方案梳理一遍,重点讲清楚flex布局里固定列加弹性列的正确写法,以及每种方案容易踩的坑。

一、用flex布局实现固定列加弹性列
flex布局是当前最推荐的方案,思路非常直观:父容器设置display: flex,侧边栏给固定宽度,内容区不给宽度而是设置为可伸缩。关键在于理解flex属性背后的三个分量:flex-grow控制放大比例,flex-shrink控制缩小比例,flex-basis控制初始尺寸。
固定列加弹性列的标准写法是:侧边栏写flex: 0 0 240px,意思是放大系数为0、缩小系数为0、基准尺寸240px,也就是无论容器多宽多窄,侧边栏始终保持240px;内容区写flex: 1,等价于flex: 1 1 0%,基准尺寸为0,把全部剩余空间都分给它。这样内容区就会自动撑满除侧边栏之外的所有宽度。
<style>
.layout {
display: flex;
height: 100vh;
}
.sidebar {
flex: 0 0 240px; /* 不放大、不缩小、固定240px */
background: #2f3542;
color: #fff;
}
.main {
flex: 1; /* 弹性列,占满剩余空间 */
background: #f1f2f6;
overflow-y: auto;
}
</style>
<div class="layout">
<aside class="sidebar">侧边栏</aside>
<main class="main">中间自适应内容</main>
</div>这里有个高频踩坑点要提醒:很多人给侧边栏只写width: 240px而不设置flex属性,当容器空间不足时,flex容器默认的flex-shrink: 1会让侧边栏跟着一起被压缩,出现侧边栏宽度不固定的假象。解决办法就是显式写上flex-shrink: 0,或者直接用flex: 0 0 240px这种简写把三个值都锁死。另外,如果内容区里有长英文单词或不换行的行内元素,建议给弹性列加上min-width: 0,因为flex项目的min-width默认值是auto,内容本身的最小宽度会阻止项目收缩,导致溢出。
二、grid网格布局:一行代码解决两栏结构
grid布局解决这类问题更简洁,直接在父容器上用grid-template-columns定义列模板:固定列写具体像素值,弹性列用fr单位。fr是fraction(分数)的缩写,表示占剩余空间的比例份额。
<style>
.layout {
display: grid;
grid-template-columns: 240px 1fr; /* 第一列固定240px,第二列占剩余 */
height: 100vh;
}
.sidebar {
background: #2f3542;
color: #fff;
}
.main {
background: #f1f2f6;
overflow-y: auto;
min-width: 0;
}
</style>grid方案的语义更清晰,列结构一眼可见,扩展成三栏也只需要改成200px 1fr 300px这种形式,左栏200px、右栏300px、中间自适应。需要注意的是grid内部项目同样可能因为内容过宽而不收缩,给自适应列加min-width: 0或overflow: hidden是稳妥的做法。
flex和grid怎么选?简单说:一维方向上的排列用flex更灵活,二维结构(既有行又有列的复杂网格)用grid更省事。侧边栏加内容区这种简单两栏,两者都能胜任;如果页面还涉及顶部导航、底部工具栏与主区域的组合,grid的grid-template-areas区域命名写法会让结构清晰很多。
三、传统方案回顾:浮动与绝对定位还能用吗
在flex普及之前,主流做法是浮动加负边距,或者绝对定位。浮动方案的思路是侧边栏浮动到左边,内容区利用margin-left留出侧边栏的宽度,父元素通过伪元素清除浮动。
<style>
.layout::after {
content: "";
display: block;
clear: both;
}
.sidebar {
float: left;
width: 240px;
background: #2f3542;
}
.main {
margin-left: 240px; /* 留出侧边栏空间 */
background: #f1f2f6;
}
</style>绝对定位方案则是父元素position: relative,侧边栏position: absolute; left: 0; width: 240px,内容区同样用margin撑开。这两种方案在维护老项目时还会见到,但新项目不建议采用:浮动方案要处理清除浮动的细节,绝对定位脱离文档流后高度塌陷问题麻烦,代码量和心智负担都比flex高出一截。它们唯一的价值是帮助你理解自适应布局的历史演进,以及在面试中应对考察布局基础的场景。
最后总结一下实践建议:新项目优先flex或grid,侧边栏固定列务必显式声明flex-shrink: 0或使用flex: 0 0 240px简写,弹性列记得加min-width: 0防止内容撑破容器。如果侧边栏需要支持用户拖拽调宽,可以在两列之间加一个几像素宽的拖拽把手元素,通过JS动态修改固定列的像素值,grid方案则可以直接操作grid-template-columns的行内样式,实现起来相当方便。