Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何使用 CSS 让你的浏览器卡死 #47

Open
chokcoco opened this issue Mar 7, 2019 · 8 comments
Open

如何使用 CSS 让你的浏览器卡死 #47

chokcoco opened this issue Mar 7, 2019 · 8 comments

Comments

@chokcoco
Copy link
Owner

chokcoco commented Mar 7, 2019

本文写作中,未完成...

使用 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 的时候,得到如下效果:

css-crash

你可以点下面的链接 Demo 尝试一下,更详细的原理介绍可以戳原文链接

CodePen Demo -- CraSSh

box-shadow

box-shadow,在众多 CSS 属性中属于耗性能样式。

同时,box-shadow 有个特点,单个元素可以叠加多重阴影。所以即便只有一个 <div> 标签,通过填充 N 重阴影,当 N 足够大时,即可以轻易让浏览器卡死。

当然,为了有趣一点。我们希望填充的多重阴影有意义而不是毫无章法。有一个小技巧很多同学都知道,就是使用阴影去模拟一张图片。

理论上任意一张图片,每一个像素点都可以由一重 1px*1px 的 box-shadow 来表示。

为了完成这个任务, canvas 刚好提供了一个方法 CanvasRenderingContext2D.getImageData 可以获取到图片每一个像素点的 rgba 值,那么图片转为一个完全由 box-shadow 表示的图片是完全可行的。

下面这个小插件可以实现图片向单div标签的转换:

img2Div

我尝试转换了一张 1920*1080 的图片,也就是相当于给单个标签 2073600 重阴影,在等待的过程中 JavaScript 运算已经接近崩溃。转换完成后,图片正确被渲染,但是整个页面卡到无法操作,感兴趣的可以自行尝试下。:)

mix-blend-mod

mix-blend-mod 混合模式,另外一个性能杀手。

CodePen Demo -- CSS WAVE MOVE

filter


最后,新开通的公众号求关注,形式希望是更短的篇幅,质量更高一些的技巧类文章,包括但不局限于 CSS:

image

@xiaowiba
Copy link

xiaowiba commented Mar 8, 2019

知道一个js的,蛤蛤

var total = "";
for (var i = 0; i < 10000; i++) { 
    total = total + i.toString(); 
    history.pushState(0, 0, total);
 }

@nanachiOwQ
Copy link

chrome更新了好像崩不了了

@lstoryc
Copy link

lstoryc commented Nov 22, 2020

的确 会抛异常不会导致真的卡死

@chokcoco
Copy link
Owner Author

@nanachiOwQ 啊哈哈 是的,文章还没写完,bug 已经被修复了~

@Angel-fund
Copy link

我偏不信,我2w 买的电脑会卡死

@linxz
Copy link

linxz commented Aug 7, 2021

n年后又一次见到这个话题

@lzm0x219
Copy link

lzm0x219 commented Aug 7, 2021

n年后又一次见到这个话题

活捉智爷

@LeePiaPia
Copy link

mac m2芯片毫无影响,运行丝滑

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants