如何使用 CSS 让你的浏览器卡死
chokcoco opened this issue · 8 comments
本文写作中,未完成...
使用 CSS 让你的浏览器卡死,听起来好像很奇怪。这里的卡死包括但不局限于浏览器crash崩溃、浏览器无响应、内存不足等等浏览器已经失去响应,用户已经卡到无法进行操作的行为。
能造成卡死无响应的,前端而言,通常都是 JavaScript 脚本的问题,死循环、内存泄漏、堆栈溢出等等导致的。
今天,我们就来聊聊不涉及 JS,仅仅是使用 CSS 的情况下,有没有可能让浏览器崩溃或者卡死。当然,使用 CSS 让浏览器卡死不是说页面同时渲染几千万个 div,给它们加上各种耗性能样式,那谁顶得住。
这里说的使用 CSS 让浏览器卡死,应该是局限在只使用少量几个标签,用特定 CSS 代码让 webview 在极短时间内卡死或者崩溃。
CraSSh
第一个方法,额,源自 CraSSh,巧妙的使用 calc()
以及CSS变量 var(--xx)
。
原理就是通过将一个指数级递增长的对 calc()
以及 var(--xx)
调用的表达式,赋给一个具体的元素样式。现代浏览器在短时间内进行大量的运算,将导致内存不足而使浏览器崩溃。
额,描述很费力,具体看一下代码,我们只有一个简单的 div:
<div></div>
CSS 样式如下:
div {
--initial-level-0: calc(1vh + 1% + 1px + 1em + 1vw + 1cm);
--level-1: calc(var(--initial-level-0) + var(--initial-level-0));
--level-2: calc(var(--level-1) + var(--level-1));
--level-3: calc(var(--level-2) + var(--level-2));
--level-4: calc(var(--level-3) + var(--level-3));
--level-5: calc(var(--level-4) + var(--level-4));
--level-6: calc(var(--level-5) + var(--level-5));
--level-7: calc(var(--level-6) + var(--level-6));
--level-8: calc(var(--level-7) + var(--level-7));
--level-9: calc(var(--level-8) + var(--level-8));
--level-10: calc(var(--level-9) + var(--level-9));
--level-11: calc(var(--level-10) + var(--level-10));
--level-12: calc(var(--level-11) + var(--level-11));
--level-13: calc(var(--level-12) + var(--level-12));
--level-14: calc(var(--level-13) + var(--level-13));
--level-15: calc(var(--level-14) + var(--level-14));
--level-16: calc(var(--level-15) + var(--level-15));
--level-17: calc(var(--level-16) + var(--level-16));
--level-18: calc(var(--level-17) + var(--level-17));
--level-19: calc(var(--level-18) + var(--level-18));
--level-20: calc(var(--level-19) + var(--level-19));
--level-21: calc(var(--level-20) + var(--level-20));
--level-22: calc(var(--level-21) + var(--level-21));
--level-23: calc(var(--level-22) + var(--level-22));
--level-24: calc(var(--level-23) + var(--level-23));
--level-25: calc(var(--level-24) + var(--level-24));
--level-26: calc(var(--level-25) + var(--level-25));
--level-27: calc(var(--level-26) + var(--level-26));
--level-28: calc(var(--level-27) + var(--level-27));
--level-29: calc(var(--level-28) + var(--level-28));
--level-30: calc(var(--level-29) + var(--level-29));
--level-final: calc(var(--level-30) + 1px);
border-width: var(--level-final);
border-style: solid;
}
可以看到,从 --level-1
到 --level-30
,每次的运算量都是成倍的增长,最终到 --level-final
变量,展开将有 2^30 = 1073741824 个 --initial-level-0
表达式的内容。
并且,每个 --initial-level-0
表达式的内容 -- calc(1vh + 1% + 1px + 1em + 1vw + 1cm)
,在浏览器解析的时候,也已经足够复杂。
混合在一起,就导致了浏览器的 BOOM,为了能看到效果,我们将上述样式赋给某个元素被 hover 的时候,得到如下效果:
你可以点下面的链接 Demo 尝试一下,更详细的原理介绍可以戳原文链接:
box-shadow
box-shadow
,在众多 CSS 属性中属于耗性能样式。
同时,box-shadow
有个特点,单个元素可以叠加多重阴影。所以即便只有一个 <div>
标签,通过填充 N 重阴影,当 N 足够大时,即可以轻易让浏览器卡死。
当然,为了有趣一点。我们希望填充的多重阴影有意义而不是毫无章法。有一个小技巧很多同学都知道,就是使用阴影去模拟一张图片。
理论上任意一张图片,每一个像素点都可以由一重 1px*1px 的 box-shadow 来表示。
为了完成这个任务, canvas
刚好提供了一个方法 CanvasRenderingContext2D.getImageData
可以获取到图片每一个像素点的 rgba 值,那么图片转为一个完全由 box-shadow 表示的图片是完全可行的。
下面这个小插件可以实现图片向单div标签的转换:
我尝试转换了一张 1920*1080 的图片,也就是相当于给单个标签 2073600 重阴影,在等待的过程中 JavaScript 运算已经接近崩溃。转换完成后,图片正确被渲染,但是整个页面卡到无法操作,感兴趣的可以自行尝试下。:)
mix-blend-mod
mix-blend-mod
混合模式,另外一个性能杀手。
filter
最后,新开通的公众号求关注,形式希望是更短的篇幅,质量更高一些的技巧类文章,包括但不局限于 CSS:
知道一个js的,蛤蛤
var total = "";
for (var i = 0; i < 10000; i++) {
total = total + i.toString();
history.pushState(0, 0, total);
}
chrome更新了好像崩不了了
的确 会抛异常不会导致真的卡死
@nanachiOwQ 啊哈哈 是的,文章还没写完,bug 已经被修复了~
我偏不信,我2w 买的电脑会卡死
n年后又一次见到这个话题
n年后又一次见到这个话题
活捉智爷
mac m2芯片毫无影响,运行丝滑