固定头尾、中间滚动?用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出现“闪一下”的窘境。
解决方案后面会讲,先留个伏笔,让你舍不得走。
打造经典三段式布局:头部固定、底部贴底、中间自适应滚动
需求拆解
- header、footer固定高度(或者由内容撑高,但不随滚动溜走)。
- 中间区域占满剩余空间,内容溢出时出现滚动条。
- 纯 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 print把height改成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等工具 |
吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!