content-visibility是什么?长列表渲染跳过与CSS隔离的机制实战

content-visibility是什么?长列表渲染跳过与CSS隔离的机制实战
张文保 15 分钟阅读 3,744 阅读
本文目录
  1. content-visibility到底在解决什么问题?浏览器为什么要渲染看不见的东西?
  2. content-visibility有哪几个值?auto、hidden、visible分别干什么?
  3. 只写一个content-visibility:auto会出什么幺蛾子?滚动条为什么乱跳?
  4. contain-intrinsic-size是干什么的?占位尺寸怎么估?
  5. 我那个宠物站的长列表页,怎么把渲染耗时砍掉一大半?
  6. content-visibility和CSS containment(contain属性)是什么关系?
  7. 用了content-visibility会不会影响SEO和可访问性?爬虫读得到吗?
  8. content-visibility会不会引起布局偏移?和CLS什么关系?
  9. 什么时候不该用content-visibility?它的坑在哪?
  10. 常见问题解答
  11. content-visibility:auto加了滚动条乱跳怎么办?
  12. 用了content-visibility,谷歌还能收录里面的内容吗?
  13. content-visibility和懒加载是一回事吗?
  14. contain-intrinsic-size的占位值该设多少?
  15. content-visibility会不会拉高CLS?
  16. 所有浏览器都支持content-visibility吗?
  17. 权威参考资料
摘要:一个几千张卡片的长列表页,浏览器哪怕只显示首屏那一小截,也会老老实实把屏幕外那几千张全部算布局、全部准备好——白白烧掉一大把渲染时间。content-visibility:auto就是给浏览器一句授权:屏幕外的这些先别渲染,等滚到跟前再说。这篇我把它的三个取值、为什么必须配contain-intrinsic-size一起用、和CSS containment什么关系、会不会影响爬虫和布局稳定,一次讲清,再配一个宠物用品站把长列表渲染耗时砍掉六成的实操。

有个现象我见过太多次:页面首屏看着就一屏内容,打开却卡顿、滚动还发涩。一查,罪魁往往是那个藏在下面、你根本没往下滚就看不到的超长列表——几千个DOM节点,浏览器全给你实打实渲染了一遍。你看不见,它可没偷懒。

我是保哥,做SEO二十多年,这几年帮出海站做性能调优,长列表页是重灾区里的重灾区。今天专讲content-visibility这个CSS属性:它不删你一个节点,只让浏览器学会跳过看不见的部分,长页面的渲染开销常常就此腰斩。

content-visibility到底在解决什么问题?浏览器为什么要渲染看不见的东西?

先得理解浏览器的一个默认脾气:它是个完美主义的老实人。你给它一个页面,哪怕首屏只露出十张卡片,下面还压着两千张,它也会把这两千张全部算好布局、算好样式、准备好绘制——因为它不敢假设你不会立刻滚下去。

这份老实在短页面上没问题,可一到长列表、长文档、无限滚动的场景,就成了纯浪费。用户可能压根不往下滚,你却为看不见的内容付了全额渲染成本。这笔账在首次加载时最疼,直接拖慢首屏,也拖累后续每一次需要重新计算布局的操作。

content-visibility要解决的就是这个。按 web.dev那篇专门讲content-visibility的文章的说法,它允许浏览器跳过一个元素的渲染工作——包括布局和绘制,直到这个元素真正被需要为止。翻译成人话:看不见的,先不算;等你快滚到了,再算也不迟。

content-visibility有哪几个值?auto、hidden、visible分别干什么?

它有三个取值,各管一摊。

visible 是默认值,等于没设,浏览器该怎么渲染怎么渲染。hidden 比较狠,直接跳过渲染,且内容对用户和查找完全不可见,类似一个更高性能的隐藏方式,适合你要用脚本手动控制显隐的场景。

真正的主角是 auto。给一个元素设上content-visibility:auto,它会自动获得布局、样式、绘制三重隔离;一旦这个元素在屏幕外、又没被用户以别的方式关注(比如焦点或选区落在里面),它还会额外获得尺寸隔离,浏览器就此跳过它内部的渲染和命中测试。MDN对content-visibility属性的说明把这套行为写得很规整——关键就在这个auto:它足够聪明,屏幕外省着算,滚进视口再补上,全自动,不用你写一行JS去监听滚动。

只写一个content-visibility:auto会出什么幺蛾子?滚动条为什么乱跳?

这是新手用它必踩的第一个坑,我得重点讲。你兴冲冲给长列表的每个卡片都加上content-visibility:auto,一刷新,渲染是快了,但滚动条开始抽风——你往下拉,它一会儿变长一会儿变短,滚动位置乱跳,体验比不加还糟。

为什么?因为屏幕外的元素被跳过渲染时,浏览器根本不知道它到底多高。它只能先当它高度为零,等你滚到跟前才现算真实高度。于是每滚过一个元素,页面总高度就突变一次,滚动条自然跟着乱蹦。

这不是content-visibility的bug,是它缺了另一半信息:你没告诉浏览器这些没渲染的元素大概多高。补上这半块信息的,就是下一节要讲的contain-intrinsic-size。所以记住一条铁律:content-visibility:auto几乎从不单独用,它和contain-intrinsic-size是一对,拆开用必出问题。

contain-intrinsic-size是干什么的?占位尺寸怎么估?

contain-intrinsic-size的作用一句话就能说清:给那些被跳过渲染的元素,先垫一个假的尺寸,让浏览器按这个尺寸去算总高度。这样滚动条就有了稳定的依据,不会再乱跳。

用法也简单,比如你估计每张卡片大约300像素高,就写 content-visibility: auto; contain-intrinsic-size: auto 300px;。前面那个auto是个很贴心的设计:12 Days of Web那篇讲content-visibility的文章解释得好——它让浏览器记住这个元素上一次真实渲染出来的高度,之后就用真实值替代你给的占位值。也就是说,你给的300px只是个初始猜测,渲染过一次之后浏览器会自己校准,越滚越准。

占位值怎么估?不用太纠结精确,取一个接近平均高度的值就行。估得偏一点,代价只是滚动条初期稍微跳一下,等元素渲染过后就自动修正了。宁可略大也别设成零,设零就等于没设,滚动条照样乱跳。

我那个宠物站的长列表页,怎么把渲染耗时砍掉一大半?

去年一个卖宠物用品的独立站找到我,问题是他们的品类聚合页奇卡。那种页面一屏下去两三千个商品卡,图文混排,用户往下滚一段就卡一下,移动端尤其明显,跳出率高得吓人。

我用Performance面板抓了一次,渲染阶段的耗时长得离谱——浏览器在为那两三千张卡片一次性算布局,而用户首屏能看到的不过十几张。典型的为看不见的内容买单。

改法很克制:给每个商品卡的容器加上content-visibility:auto,再配一个contain-intrinsic-size,占位高度按卡片平均高度设。没删任何内容,没改任何图,没动任何脚本,纯CSS两行。

改完复测,首次渲染阶段的耗时砍掉了大约六成,滚动重新变顺,移动端那种一顿一顿的感觉基本没了。客户最直观的反馈是——终于不像在拖一块砖了。

这里我要提醒一句:效果这么明显,恰恰因为它是超长列表。要是你的页面本身就短,首屏之外没多少可跳过的内容,加了几乎看不出差别,别指望它包治百病。它的收益和页面长度是绑死的,越长越划算。

content-visibility和CSS containment(contain属性)是什么关系?

这两个经常一起出现,得理清。CSS containment是个更早、更底层的概念,核心思路是把一棵DOM子树和页面其余部分做可预测的隔离,告诉浏览器这块内容是自成一体的,算它的时候不用管外面、算外面也不用管它。有了这层隔离,浏览器就能大胆地做局部优化。

content-visibility其实是站在containment这套地基上的一个高层封装。你设content-visibility:auto,浏览器背后就自动帮你打开了布局、样式、绘制乃至尺寸的隔离——这些正是containment提供的能力。CSS Containment规范把contain属性和content-visibility放在同一套体系里定义,就是这个道理。

所以你可以把content-visibility理解成containment的傻瓜式入口。早年想拿隔离的性能红利,你得自己去研究contain属性那几个值怎么组合、哪个场景配哪套,门槛不低。现在一个content-visibility:auto,等于帮你把最常用的那套隔离组合一键配好,还多附赠了屏幕外自动跳过渲染的能力。对绝大多数长列表场景,直接用它就够,不必再去手搓contain。

用了content-visibility会不会影响SEO和可访问性?爬虫读得到吗?

这是我被问最多的问题,也是最该讲清楚的。答案是:content-visibility:auto里的内容,对搜索引擎和可访问性都是可见的、可被读取的,你尽管放心。

关键区别在于,它跳过的是渲染,不是存在。那些内容一直老老实实待在DOM里,只是暂时没被画上屏而已。爬虫解析DOM、屏幕阅读器遍历文档结构,走的都不是像素渲染那条路,所以它们照样能读到全部内容。想弄明白爬虫到底怎么一步步处理DOM、哪种情况才真会丢内容,可以看我那篇专讲搜索引擎抓取与渲染DOM分几步的文章——content-visibility影响的是渲染那一步的性能,动不到内容在DOM里的存在。

页面内查找(Ctrl+F)、锚点跳转、Tab键焦点导航,这些也都能正常穿透content-visibility:auto的元素——浏览器发现你要访问里面的内容时,会自动把它渲染出来。这也是auto比hidden好用的地方:它不会把内容真的藏死。

content-visibility会不会引起布局偏移?和CLS什么关系?

这是最需要小心的一环,和累积布局偏移直接相关。前面说过,占位尺寸估不准,元素渲染时真实高度和占位值对不上,就会产生一次布局偏移。如果这偏移发生在用户视野里,就会被计入CLS,反而拖累你的视觉稳定性。

但这不是content-visibility的原罪,是用法问题。诀窍就俩:一是contain-intrinsic-size尽量估准,让占位值贴近真实高度;二是善用前面提到的auto关键字,让浏览器渲染过一次后记住真实尺寸、自动校准。做到这两点,偏移只会零星发生在屏幕外,几乎碰不到CLS。

DebugBear那篇实测content-visibility的文章也提醒了同一件事:占位尺寸没配好,是这个属性唯一真正容易翻车的地方,别的坑都好绕,就这个得认真估。CLS本身怎么算、图片广告字体这五大元凶从哪来,我在专讲累积布局偏移的那篇里拆得很细,content-visibility只是可能贡献偏移的其中一路,把占位尺寸这道关守住,它就不会成为你CLS报表上的麻烦。

什么时候不该用content-visibility?它的坑在哪?

好东西也有边界。第一,短页面别用,首屏就那么点内容,浏览器本来也没多少可跳过的,加了纯属自找维护成本。它的价值和页面长度、DOM规模正相关,越长越值。

第二,别给首屏可见的元素加content-visibility:auto。首屏内容本来就要立刻渲染,加了不省反而多一层判断,还可能引入不必要的偏移。它应该只戴在屏幕外、要滚动才看得到的那些区块上。

第三,它省的是渲染开销,不是主线程上的脚本开销。如果你的卡顿是JS执行太重造成的,那是另一路问题,content-visibility帮不上忙,得往交互性能那边查——这类和主线程较劲的活儿,我在讲INP交互到下一次绘制怎么优化的文章里专门拆过。至于渲染这条链本身还有哪些环节能提速,可以顺着关键渲染路径那篇再往上游看,content-visibility治的是渲染量,关键渲染路径治的是渲染的阻塞,两者互补。分清各自的战场,才不会拿错药。

常见问题解答

content-visibility:auto加了滚动条乱跳怎么办?

八成是没配contain-intrinsic-size,或者占位值设得离真实高度太远。给同一个元素补上contain-intrinsic-size,用接近平均高度的值,并加上auto关键字让浏览器记住真实尺寸自动校准。这俩几乎从不单独用,content-visibility:auto配contain-intrinsic-size才是完整用法。

用了content-visibility,谷歌还能收录里面的内容吗?

能。content-visibility跳过的是像素渲染,不影响内容在DOM里的存在。爬虫解析DOM拿的是文档结构,不走渲染上屏那条路,所以屏幕外的内容照样被读取和收录。可访问性工具也一样能遍历到,不必担心。

content-visibility和懒加载是一回事吗?

不是。懒加载(loading=lazy)针对的是图片、iframe这类具体资源,推迟它们的下载。content-visibility针对的是任意DOM子树的渲染,推迟浏览器算布局和绘制的时机。一个省下载流量,一个省渲染算力,可以叠加使用,管的是不同环节。

contain-intrinsic-size的占位值该设多少?

取接近元素平均高度的值就行,不用追求精确。加上auto关键字(比如auto 300px),浏览器会在元素首次渲染后记住真实高度并自动替换你的占位值,越用越准。宁可略大也别设成零,设零等于没占位,滚动条照样会跳。

content-visibility会不会拉高CLS?

用错才会。占位尺寸和真实高度差太多,元素渲染时会产生偏移,落在视野里就计入CLS。把contain-intrinsic-size估准、用上auto自动校准,偏移基本只发生在屏幕外,几乎不影响CLS。守住占位尺寸这道关是关键。

所有浏览器都支持content-visibility吗?

主流浏览器已经普遍支持,Safari也在较新版本跟进,具体版本可查 caniuse上content-visibility的兼容性表。不支持的浏览器会直接忽略这个属性,页面照常完整渲染,只是少了这层优化,不会出错也不会漏内容。它是典型的渐进增强,可以放心先用起来,支持的浏览器享受提速,不支持的也毫发无伤。

权威参考资料

分享到
标签
版权声明

本文标题:《content-visibility是什么?长列表渲染跳过与CSS隔离的机制实战》

本文链接:https://zhangwenbao.com/content-visibility-css-containment-render-skipping.html

版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交