当前位置: 首页 > news >正文

给浏览器画个圈:CSS contain 如何让页面从“卡成PPT”变“丝滑如德芙”

引言

“这个页面滚动怎么像在泥潭里走路?”

去年双十一前夕,我们团队接到了一个紧急优化任务:商品详情页在低端机上滚动卡顿,帧率掉到 20 以下,用户投诉满天飞。

我打开 Performance 面板,发现每次滚动,浏览器都在疯狂地计算一个离屏广告位的布局和样式。那个广告位在页面最底部,用户可能根本不会翻到那里,但浏览器依然在每一帧都兢兢业业地重新计算它的位置、大小,甚至重绘它的阴影和圆角。

我当时对着屏幕大喊:“大哥,你算它干嘛?它又不在屏幕上!”

后来我才知道,原来 CSS 里有两个低调但强大的属性,可以告诉浏览器:“这个元素你别管了,它的内部变化不会影响外面,你爱咋咋地。”它们就是containcontent-visibility

今天,我们就来认识一下这两位“性能救星”。

一、问题:浏览器为什么要“管闲事”?

在渲染引擎的眼里,页面上的每一个元素都可能与其他元素产生“瓜葛”:

  • 一个元素尺寸变化,可能导致父元素、兄弟元素甚至整个文档流都重新布局(回流)。
  • 一个元素背景色变化,可能触发它所在层的重绘。
  • 即使元素在屏幕外,浏览器也不知道它将来会不会突然出现在视野里,所以依然会参与全局的布局和绘制计算

这种“过度负责”的精神,在元素数量爆炸的今天,成了性能杀手。

二、contain:给元素画一个“结界”

contain属性允许你声明一个元素独立于文档的其余部分,它的内部变化不会“越界”影响到外部。这就像给元素画了一个魔法结界,结界里面怎么折腾,外面都不受影响。

2.1 contain 的几个“法术”

你可以给contain指定一个或多个值,告诉浏览器该限制哪些方面:

作用效果
layout限制布局内部元素的布局不会影响外部,外部也不会影响内部。浏览器可以独立处理该元素的布局。
paint限制绘制内部元素永远不会超出元素边界绘制(相当于overflow: hidden但更强),且内部的重绘不会扩散到外部。
size限制尺寸元素的尺寸不依赖其子元素。你必须手动设置宽高,否则尺寸会按 0×0 计算。这能让浏览器跳过子元素的布局计算来确认父元素尺寸。
style限制样式内部元素的计数器、@counter-style等不会影响外部。这个值较少用。
strict等同于layout paint size最严格的隔离。
content等同于layout paint常用组合,相当于隔离布局和绘制,但不隔离尺寸。

2.2 实战:给离屏广告加结界

回到开头那个离屏广告位:

.ad-banner{contain:layout paint;/* 广告位内部布局和绘制不会影响到页面其他部分 */}

加上这行 CSS 后,浏览器在计算滚动时的布局时,会把这个广告位看作一个“黑盒”。只要它的整体位置没变(比如固定在底部),内部的任何变化都不会触发外部重排。滚动帧率瞬间从 20 飙到 60。

注意:如果使用了contain: size,你必须给元素明确设置宽高,否则它会被压缩成 0×0,里面的内容可能看不见。一般用contain: layout paint就足够了。

三、content-visibility:让浏览器“偷懒”更彻底

如果说contain是“结界”,那content-visibility就是“隐身术”。它直接告诉浏览器:这个元素如果不在屏幕上,你就别渲染它内部的东西

3.1 三个值

  • visible:默认行为,正常渲染。
  • hidden:元素不可见,且不占位(类似display: none),但内部内容不会被渲染。
  • auto智能模式,当元素接近视口时开始渲染,离开视口时停止渲染。这是最常用的值。

3.2 效果有多夸张?

假设你有一个包含 1000 条评论的长列表,每条评论结构复杂。用content-visibility: auto后,初始渲染时只会渲染前几条(在视口内和附近的),其余的直接跳过,渲染时间从几百毫秒降到几十毫秒。

.comment-item{content-visibility:auto;contain-intrinsic-size:0 100px;/* 给一个预估高度,避免滚动条跳动 */}

contain-intrinsic-size是为了在元素未渲染时给浏览器一个占位尺寸,防止滚动条忽大忽小。

3.3 与 contain 的关系

content-visibility: auto自动应用contain: layout paint style(即content组合)。所以它本身就是一种强隔离 + 按需渲染。

四、真实案例:让一个“万人直播列表”起死回生

曾经有个需求:页面左侧是一个实时更新的万人直播列表,每个直播间卡片都有封面图、标题、观众数、礼物动画等。不加优化时,页面初始渲染要 2 秒,滚动掉帧严重。

我们做了两步:

  1. 给每个卡片加上content-visibility: auto
  2. 配合contain-intrinsic-size: 0 120px给卡片一个预估高度。

结果:首屏渲染时间降到 300ms,滚动流畅度接近原生。用户不知道我们在背后做了手脚,只知道“这个页面好快”。

五、注意事项:别乱用,否则会“翻车”

5.1 兼容性

  • contain:所有现代浏览器都支持(包括 Safari 15.4+),IE 不支持。
  • content-visibility:Chrome/Edge 85+、Firefox 90+、Safari 15.4+ 支持。对旧浏览器可以用 JavaScript 降级或直接忽略(不影响功能)。

5.2 小心“过度隔离”

如果一个元素内部有弹出层(比如下拉菜单),并且这个弹出层使用了position: absolute定位到元素外部,contain可能会限制它超出边界(因为paint会裁剪超出部分)。这时你需要避免使用paint,或者把弹出层移到contain容器外部。

5.3 不要滥用 content-visibility

给所有元素都加上auto并不明智。它主要用于长列表、离屏组件等。对于已经在视口内的小组件,反而可能增加额外开销。

5.4 别忘了预估尺寸

如果没有contain-intrinsic-sizecontent-visibility: auto的元素在未渲染时高度为 0,滚动条会随着你滚动不断跳动,体验极差。务必给一个合理的占位高度。

六、总结:学会给浏览器“减负”

浏览器很努力,但它的努力有时候是徒劳的。作为开发者,我们应该用containcontent-visibility告诉它:“这些元素不用管,那些元素等用户看到了再管。”

这两个属性,就像给页面装上了“节能模式”,让性能提升肉眼可见。下次当你遇到长列表或复杂离屏组件卡顿时,不妨试试它们。

最后留一道思考题:如果一个元素既设置了content-visibility: auto,又设置了overflow: auto,内部滚动条的行为会有什么不同?为什么?


每日一问:你在项目里用过content-visibility吗?有没有遇到过奇怪的 bug?评论区聊聊你的“偷懒”经验!

http://www.jsqmd.com/news/538519/

相关文章:

  • 2026年企业管理软件深度解析:从用友、金蝶到小管家的差异化选择 - 深度智识库
  • 如何快速部署缠论可视化平台:基于TradingView本地SDK的终极解决方案
  • 浏览器3D模型查看器完整指南:免费在线查看CAD、STL、GLB文件
  • AI算法Excel可视化终极指南:如何用电子表格深度解析人工智能原理
  • OpenClaw+GLM-4.7-Flash:技术面试题自动生成与评估系统
  • 避开这些坑!TextMeshPro竖排文字的正确姿势(含EnableRTLEditor详解)
  • Janus-Pro-7B国产适配:支持麒麟/UOS系统+昇腾/海光平台部署路径
  • kubenetes从入门到上天系列第二十四篇:Kubernetes Pod的自动扩缩容
  • 豆包AI生成 —— 强化学习 —— TRPO算法
  • Llama-3.2V-11B-cot开源大模型实战教程:双卡4090环境下11B视觉模型快速调用
  • 基于Python的宠物商城网站毕业设计
  • 从Win10到Copilot:一文搞懂系统更新、硬件要求及AI助手完整配置流程
  • 测试行业“内卷”报告:哪些岗位还在涨薪?
  • 合肥金融雨桥 个人/企业融资顾问介绍: - 野榜精选
  • 别再到处找教程了!手把手教你用艾可API密钥配置Sider,5分钟搞定GPT-4o模型接入
  • CardEditor:3MB小工具解决桌游卡牌批量制作大难题
  • 在Ubuntu 20.04上为工业机器人搭建实时内核与EtherCAT主站:我的踩坑与避坑全记录
  • 排序算法---(一)
  • Universal-IFR-Extractor:UEFI固件分析工具的终极实战指南
  • 抖音无水印视频批量采集开源工具:3大突破实现内容获取全流程效率提升90%
  • STM32板级支持包实战:从GPIO配置到LED控制全流程解析
  • 3个实战技巧快速掌握英雄联盟智能工具集League Akari
  • C# 实现 Modern Standby 模式下的电源事件精准监听(Sleep 状态)
  • Aider Repo Map 功能实战:如何一键生成并保存整个项目的代码地图(附常见问题排查)
  • FanControl:实现散热智能化的全面解决方案
  • Wan2.2-I2V-A14B部署教程:多用户隔离+权限控制+日志监控配置
  • ArduPilot自定义参数实战:手把手教你让飞控向地面站“说话”(打印参数值)
  • RS485项目翻车实录:我是这样用FIFO解决多设备通信卡顿的
  • TikTok爆火:C语言代码让电脑无硬件发无线电,靠谱吗?
  • AXI非对齐访问实战指南:从WSTRB信号到DMA数据搬运的避坑细节