固定头尾、中间滚动?用Flex + vh轻松搞定三栏布局
2026/4/4 14:10:06 网站建设 项目流程


固定头尾、中间滚动?用Flex + vh轻松搞定三栏布局

  • 固定头尾、中间滚动?用Flex + vh轻松搞定三栏布局
    • 引言:为什么页面头尾固定这么让人头疼
    • CSS Flex 布局快速上手指南——从“ Flex 是谁”到“ Flex 是我兄弟”
      • 1. 激活 Flex 模式
      • 2. 主轴与交叉轴——别被术语吓到
      • 3. 关键属性备忘录(背不下来就收藏)
    • vh 单位到底有多香?别再只用百分比了
      • 百分比的问题
      • vh 的直球告白
      • 但是——vh 也有“渣”的时候
    • 打造经典三段式布局:头部固定、底部贴底、中间自适应滚动
      • 需求拆解
      • HTML 骨架
      • CSS 核心代码(注释比代码多,怕你看不懂)
      • 一行行拆解
      • 完整可运行 Demo(直接复制到本地可玩)
    • Flex 与 vh 联手的那些细节陷阱
      • 陷阱 1:Safari 的“折叠地址栏”导致 vh 抖动
      • 陷阱 2:flex-shrink: 0 忘记写,footer 被中间踹飞
      • 陷阱 3:中间区域 `padding` 导致滚动条“穿模”
    • 实际项目中常见的“滚动失效”或“内容溢出”问题排查手册
      • 1. 滚动条死活不出来
      • 2. 安卓微信下键盘弹起,footer 飘到头顶
      • 3. 嵌套子项也想要滚动,结果父子一起滚
    • 让布局更健壮:开发者私藏的 Flex + vh 组合技巧
      • 技巧 1:header 高度不固定,由内容撑高,照样玩
      • 技巧 2:中间分左右两栏,左侧固定宽,右侧自适应
      • 技巧 3:Sticky 表头 + Flex 剩余高度
      • 技巧 4:CSS 变量 + calc() 做“顶部 banner 可关闭”场景
    • 你以为这就完了?这些边界情况你可能还没遇到过
      • 1. 横屏 + 工具栏折叠,vh 再次抽风
      • 2. 系统缩放导致 1vh 不是 1px 整数倍
      • 3. 打印样式把 vh 当成废纸
      • 4. 无障碍访问:键盘用户切到 footer 要按多久?
    • 结语:把代码复制走,把头发留下来

固定头尾、中间滚动?用Flex + vh轻松搞定三栏布局

友情提示:阅读本文前请自备咖啡,因为看完你会忍不住把公司祖传position: fixed代码全删了。


引言:为什么页面头尾固定这么让人头疼

如果你曾经接过“整个页面不许动,只有中间能滑”这种需求,你一定体验过那种——

“明明设置了height: 100%,却像前任一样说变就变”
“给 footer 加了position: fixed,结果键盘弹起时 footer 直接蹦到月球”
“测试妹子说 iPhone 12 没问题,iPhone 13 就炸,我怀疑苹果针对我”

这种痛,只有前端懂。
更惨的是,Stack Overflow 上高赞答案清一色position: fixed + js 动态算高度,复制粘贴一时爽,维护火葬场。

其实,Flexbox + vh这对 CP 早就偷偷领了证,只是很多人还在相亲角发“征婚启事”——本文就来当一次红娘,让你一次性把三栏布局的户口本办下来,顺带送 20 斤代码当彩礼。


CSS Flex 布局快速上手指南——从“ Flex 是谁”到“ Flex 是我兄弟”

先把 Flex 当成一个超级保姆
只要你告诉它“谁是主角、谁是配角”,它就能自动把盒子排得比高铁座位还整齐。

1. 激活 Flex 模式

/* 给父元素一句暗号,Flex 保姆上线 */.container{display:flex;/* 块级 Flex 容器 *//* inline-flex 也行,但本文不讲,免得你分心 */}

2. 主轴与交叉轴——别被术语吓到

想象你在烤串:

  • 主轴 (flex-direction):铁签子方向。row横着串,column竖着串。
  • 交叉轴:垂直于铁签子的方向。翻串的时候撒辣椒面就靠它。
flex-direction:column;/* 竖着串,本文主角 */

3. 关键属性备忘录(背不下来就收藏)

属性一句人话常用值
flex-grow剩余空间怎么分赃1 表示“我全都要”
flex-shrink空间不够谁瘦身0 表示“打死不减”
flex-basis项目打底尺寸0 或auto
justify-content主轴对齐space-between像地铁扶手
align-items交叉轴对齐stretch默认拉满

背完口诀,立刻进入实战——别让保姆等太久。


vh 单位到底有多香?别再只用百分比了

百分比的问题

height: 100%像渣男,层层继承才生效:
父元素没高度?那它就摆烂给你看。

vh 的直球告白

1vh = 1% 视口高度跟父元素无关,像单身狗自己买房,硬气!

/* 一句话让盒子占满整个屏幕 */.fullscreen{height:100vh;}

但是——vh 也有“渣”的时候

移动端 Chrome 地址栏收缩会动态改变视口高度,导致100vh出现“闪一下”的窘境。
解决方案后面会讲,先留个伏笔,让你舍不得走。


打造经典三段式布局:头部固定、底部贴底、中间自适应滚动

需求拆解

  1. header、footer固定高度(或者由内容撑高,但不随滚动溜走)。
  2. 中间区域占满剩余空间内容溢出时出现滚动条
  3. 纯 CSS 实现,不依赖 JS 算高度——让后端小哥无槽可吐。

HTML 骨架

<bodyclass="layout"><headerclass="topbar">顶部导航</header><mainclass="content">中间超多内容</main><footerclass="bottombar">底部备案信息</footer></body>

CSS 核心代码(注释比代码多,怕你看不懂)

/* 1. 整个页面当成一个竖着的 Flex 容器 */.layout{display:flex;flex-direction:column;height:100vh;/* 直接占满视口,百分比写法则需要 html,body 100% 继承 */}/* 2. 头部底部不允许被挤压 */.topbar, .bottombar{flex-shrink:0;/* 告诉 Flex:再挤我也不瘦身 */}/* 3. 中间区域贪婪霸占剩余空间 */.content{flex:1;/* 等价于 flex: 1 1 0; 占满剩余 */overflow:auto;/* 内容溢出时自己滚,别连累页面 */}

一行行拆解

  • flex: 1是三个属性的缩写:
    • flex-grow: 1→ 剩余空间全给我
    • flex-shrink: 1→ 空间不够我让步(但父级是 100vh,基本不会)
    • flex-basis: 0→ 打底尺寸为 0,优先听 grow 的
  • overflow: auto让中间自己出现滚动条,不会触发整个页面滚动,完美实现“局部滚动”。

完整可运行 Demo(直接复制到本地可玩)

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"/><title>Flex+vh 三栏布局</title><style>*{margin:0;padding:0;box-sizing:border-box;}.layout{display:flex;flex-direction:column;height:100vh;background:#f5f5f5;}.topbar{height:60px;background:#1890ff;color:#fff;line-height:60px;padding:0 20px;flex-shrink:0;}.content{flex:1;overflow:auto;padding:20px;background:#fff;}.bottombar{height:50px;background:#001529;color:#fff;line-height:50px;text-align:center;flex-shrink:0;}/* 假装内容很多 */.long-list{list-style:none;}.long-list li{padding:15px;border-bottom:1px solid #eee;}</style></head><bodyclass="layout"><headerclass="topbar">Header:我是固定头部</header><mainclass="content"><ulclass="long-list"><!-- 生成 100 条假数据 --><!-- 用 JS 懒人才写,我们直接手写 10 条意思一下 --><li>内容 1</li><li>内容 2</li><li>内容 3</li><li>内容 4</li><li>内容 5</li><li>内容 6</li><li>内容 7</li><li>内容 8</li><li>内容 9</li><li>内容 10</li><!-- 复制十遍,凑 100 条 --><li>内容 11</li><li>内容 12</li><li>内容 13</li><li>内容 14</li><li>内容 15</li><!-- ……以下省略,读者自行脑补 85 条…… --></ul></main><footerclass="bottombar">Footer:备案号京ICP备××××××号</footer></body></html>

打开浏览器,中间滚到飞起,头尾稳如老狗
把代码丢给测试,iPhone 13 也挑不出毛病——除非她故意针对你。


Flex 与 vh 联手的那些细节陷阱

陷阱 1:Safari 的“折叠地址栏”导致 vh 抖动

症状:
页面初始化时 footer 被顶到屏幕外,滑动后地址栏收缩,footer 又回来——用户眼看一次“跳楼机”。

解法 A:-webkit-fill-available老药片

.layout{height:100vh;/* 先给一颗糖 */height:-webkit-fill-available;/* 再喂 Safari 专用药 */}

解法 B:CSS 变量 + JS 动态修正(更稳健)

:root{--real-vh:1vh;}.layout{height:calc(var(--real-vh)* 100);}
// 页面加载 + 窗口变化时都喂一次functionsetRealVh(){constvh=window.innerHeight*0.01;document.documentElement.style.setProperty('--real-vh',`${vh}px`);}window.addEventListener('load',setRealVh);window.addEventListener('resize',setRealVh);

陷阱 2:flex-shrink: 0 忘记写,footer 被中间踹飞

表现:
中间内容超长时,footer 被挤成“负高度”,直接消失。

排查:
打开 DevTools → 选中 footer → 看flex-shrink是不是默认值1
果断flex-shrink: 0打回去。

陷阱 3:中间区域padding导致滚动条“穿模”

.content写了padding,但滚动条紧贴着文字,巨丑。

修复:
用“父子双层”套路,外层负责滚动,内层负责 padding:

.content{overflow:auto;/* 别写 padding */}.content-inner{padding:20px;/* 内层随便玩 */}
<mainclass="content"><divclass="content-inner"><!-- 真正内容 --></div></main>

实际项目中常见的“滚动失效”或“内容溢出”问题排查手册

1. 滚动条死活不出来

  • 检查高度是否真正“吃饱”:
    .content上加background: red,看是否撑满剩余空间。
    如果红色没铺满,说明flex: 1被其他属性覆盖,或者父容器没高度。
  • 检查是否overflow: hidden坑爹:
    全局 reset 里经常把*写成overflow: hidden,一刀切死。

2. 安卓微信下键盘弹起,footer 飘到头顶

原因:
微信把视口高度压缩,但100vh不变,导致 footer 跟着上移。

解法:
把 footer 改成非固定,用中间padding-bottom留坑+ JS 检测键盘:

// 监听窗口变化,如果高度变化超 300px,大概率键盘弹出letoriginalHeight=window.innerHeight;window.addEventListener('resize',()=>{constdiff=originalHeight-window.innerHeight;if(diff>300){document.body.classList.add('keyboard-open');}else{document.body.classList.remove('keyboard-open');}});
.keyboard-open .bottombar{position:absolute;bottom:0;}

3. 嵌套子项也想要滚动,结果父子一起滚

给子项加overscroll-behavior: contain;
告诉浏览器:“我滚到头了,别打扰父级。”

.child-scroll{overflow:auto;overscroll-behavior:contain;}

让布局更健壮:开发者私藏的 Flex + vh 组合技巧

技巧 1:header 高度不固定,由内容撑高,照样玩

把 header 的height去掉,交给padding撑开,
依旧保持flex-shrink: 0,其余步骤不变。
Flex 会自动把剩余空间分给中间,无需手动算高度

技巧 2:中间分左右两栏,左侧固定宽,右侧自适应

<mainclass="content"><asideclass="sidebar">左侧菜单</aside><sectionclass="right-panel">右侧超大表格</section></main>
.content{display:flex;flex:1;overflow:hidden;/* 关键:别滚自己,交给子项 */}.sidebar{width:220px;overflow:auto;}.right-panel{flex:1;overflow:auto;}

两层滚动:左侧菜单滚、右侧表格滚,互不干扰。
测试妹子想怎么滑就怎么滑。

技巧 3:Sticky 表头 + Flex 剩余高度

表格想表头固定,内容滚动?
把表头设成position: sticky即可,无需改变布局

table thead th{position:sticky;top:0;background:#fafafa;z-index:1;}

技巧 4:CSS 变量 + calc() 做“顶部 banner 可关闭”场景

:root{--banner-height:80px;}.topbar{height:var(--banner-height);}.banner-close ~ .layout .topbar{--banner-height:0px;}.content{height:calc(100vh -var(--banner-height)- 50px);/* 50px 是 footer */}

配合 JS 切换.banner-close类,纯 CSS 计算高度,性能吊打requestAnimationFrame


你以为这就完了?这些边界情况你可能还没遇到过

1. 横屏 + 工具栏折叠,vh 再次抽风

横屏时,部分安卓浏览器的工具栏高度变化更夸张,
建议横竖屏都触发一次setRealVh(),稳!

2. 系统缩放导致 1vh 不是 1px 整数倍

别用calc(100vh - 60px - 50px)去硬凑,
直接用flex: 1让浏览器算,浮点误差与你无关

3. 打印样式把 vh 当成废纸

打印时100vh会被浏览器当成一页纸高度
可能把你精心排版的表格拦腰斩断。
记得加@media printheight改成auto
或者display: none把固定头尾直接隐藏,节约墨水,绿色地球

4. 无障碍访问:键盘用户切到 footer 要按多久?

固定头尾导致中间区域巨长,键盘用户按Tab要按到地老天荒。
给中间加tabindex="-1"并加aria-label="主要内容"
再配合SkipLink—— 善良比健壮更重要。


结语:把代码复制走,把头发留下来

Flex + vh 就像前端界的“板蓝根”——
看似平平无奇,喝对了症状,药到病除
下次再遇到“头尾固定、中间滚动”的祖传需求,
别再position: fixed一把梭,
把本文的 Demo 直接甩过去,
让产品经理自己滑——
滑得开心,你就早下班;滑得顺畅,你就少掉毛。

祝你键盘常青,Bug 常无,我们下一篇“如何用 Grid 把产品经理画成九宫格”再见!

欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!


专栏系列(点击解锁)学习路线(点击解锁)知识定位
《微信小程序相关博客》持续更新中~结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等
《AIGC相关博客》持续更新中~AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结
《HTML网站开发相关》《前端基础入门三大核心之html相关博客》前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识
《前端基础入门三大核心之JS相关博客》前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。
通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心
《前端基础入门三大核心之CSS相关博客》介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页
《canvas绘图相关博客》Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化
《Vue实战相关博客》持续更新中~详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅
《python相关博客》持续更新中~Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具
《sql数据库相关博客》持续更新中~SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能
《算法系列相关博客》持续更新中~算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维
《IT信息技术相关博客》持续更新中~作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识
《信息化人员基础技能知识相关博客》无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方
《信息化技能面试宝典相关博客》涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面
《前端开发习惯与小技巧相关博客》持续更新中~罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等
《photoshop相关博客》持续更新中~基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结
日常开发&办公&生产【实用工具】分享相关博客》持续更新中~分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具

吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询