pointer-events:none提高頁面滾動時候的繪制性能?
一、故事是這么發生的
很久很久以前……還沒有 pointer-events , 因此故事不是發生在很久很久以前,而是就發生前前個月。那是個懶散的下午,溫暖的陽光透過落地窗悠然地灑在辦公桌上,就在這個愜意的時候,我瞅見了這么一條微博:

喲,轉發蹭蹭蹭上了3位數,不錯哦!此tip源自thecssninja.com上 60fps scrolling using pointer-events: none 一文。
這種結論直接,通俗好記的奇淫技巧似乎頗受大家喜歡。知道即GET! 無需動腦,無需深入思考,自然大家都喜歡。還有國人翻譯了這篇文章: [譯]使用pointer-events:none實現60fps滾動 。
故事似乎挺美好,白雪公主和王子相遇,從此幸福地在一起!然后,眾粉紛紛效仿采用,也希望得到幸福……
如果故事就此happy ending結束,似乎皆大歡喜。但是,抱歉,只有童話故事才會這樣。代碼若江湖,血雨與腥風,活脫脫現實世界。因此,白雪公主和王子相遇之后的故事不能不提,比方說王子一直奇怪“為何自己子女都很矮”這樣的場景。
我希望那百來個轉發的童鞋能看到本文,否則,就不會興致勃勃以為新技能get,幸福生活coming呢!
二、懷疑與真理的探究
哈佛的校訓簡單而不簡單: 真理 !
說簡單是因為就一個單詞,兩個漢字。比背魯迅的文章簡單 value = PM2.5 倍。說不簡單,是因為要做到很難。
真理這東西是需要不斷探究的,是要不斷質疑與論證的。
小學應該學過“兩個鐵球”的故事:超著名哲學家亞里士多德認為,10斤的鐵球和1斤的鐵球同時往下落,10斤的那個球速度要快10倍。結果伽利略在著名的比薩斜塔一實驗,證實兩個鐵球同時落地,這就是真理的探究。
首先,要敢于懷疑權威;其次要自己大膽試驗認證;最后要勇于提出自己的觀點。
這有點類似于我們常說的“ 科研精神 ”!
但是,人各有志。很多同學就想混口飯吃,很多同學希望的是來錢多,來錢快。“探求真理”這種看不到短期利益的事情著實不是他們喜歡的。
哈佛校訓20條——get it!
反復煮沸的水不能喝——get it!
維C不能和蝦一起吃,會中毒——get it!
pointer-events:none提高滾動繪制性能——get it!
類似上面這些快餐式的論點,往往這些同學樂于接受,并甚至作為真理。當然,不影響正常的生存。不過似乎就是幾十億人口中那蕓蕓眾生中的一個。在上帝看來,似乎沒有什么特別的區分度,可有可無。不過,這些同學本身就是希望平平凡凡、默默無聞過一生,因此,我覺得挺好的。雖然,上面4條基本上都是假的!
thecssninja那篇文章的視頻真真切切顯示了繪制性能提高了哈,貌似有同行親自測試,那條微博Gif截圖就能說明問題啊!這些都是活脫脫的證據啊,怎么可能“pointer-events:none提高滾動繪制性能”是假的呢!
那我要反問下諸位了:
1. 所有的測試似乎都是Chrome瀏覽器,FireFox瀏覽器測試了沒,IE呢?移動設備呢?
2. 所有測試都是較新版本的Chrome瀏覽器,舊版本的也是這樣嗎?
3. 測試頁面 box-shadow 盒陰影效果為主,如果是其他UI效果,也會是這個結果嗎?
4. pointer-events:none 樣式應用本身就涉及重繪,這個性能影響有沒有考慮進去?
5. 該方法經過實際場景的驗證了嗎,能否應對各種應用場景?
6. 有沒有相關其他方法增強性能,例如覆蓋一個div層?
如果最后的結論是,只有最新PC版本的Chrome瀏覽器才有此性能提高,您還會如此興奮,以為輕輕松松撿了個寶嗎?
三、pointer-events:none知識快補
早在2011年的時候,我就著重介紹了 pointer-events:none 這個聲明,可參考之前的文章“ CSS3 pointer-events:none應用舉例及擴展 ”。其中不僅有實例應用,以及其他不支持瀏覽器的兼容方案。推薦看下。
我個人將 pointer-events:none 理解為“幻影特性”。原話如下:
pointer-events:none的作用是讓元素實體“虛化”。例如一個應用pointer-events:none的按鈕元素,則我們在頁面上看到的這個按鈕,只是一個虛幻的影子而已,您可以理解為海市蜃樓,幽靈的軀體。當我們用手觸碰它的時候可以輕易地沒有任何感覺地從中穿過去。一切都是幻影!
我從維基上找到的解釋是: 用戶發起的光標移動或對象選擇等
如果我們在 body 標簽上應用該CSS聲明,則整個頁面(如果內部沒有其他 pointer-events 設置)就像是一個背景圖片的存在。不能選不能點不能相應 hover ,幻影而已。
四、評論中的集體智慧
一個微博要想成為經典,必須要有神最右的支持。一個知識體系需要完善,也需要百家之言。
新技能tip的出現,如果只看文章主體介紹,似乎又霧里看花水中望月之感。點評網為什么很多人去看,是因為商家的介紹嗎?顯然是因為出彩有價值的點評。
thecssninja這篇文章顯然也是如此。
如果您單純看文章的結論,那你可就錯過了很多精彩的內容。
我們從上往下(時間順序)一條一條過一下(版式很考究,如果您發現布局shit一般,請訪問原出處):
Ekrem Buyukkaya says:
November 26, 2013 at 3:06 am
Brilliant.
Ekrem Buyukkaya 說:
2013-11-26 3:06
聰明。
//zxx: 醬油評論!
Chris says:
November 26, 2013 at 6:04 am
Wonder if there are any side effects…BTW, the demo works nicely in IE11 too, Shows the same difference in the Performance tab in the new F12 Tools.
Chris 說:
2013-11-26 6:04
不知道有沒有其他副作用…順便說一句,在IE11瀏覽器下,通過F12打開性能測試選項卡進行性能測試,出現了同樣的差異。
//zxx: 很贊的同行。第一句提出疑問,懷疑其副作用;第二句自己實踐,在IE11瀏覽器下測試。親自驗證方法的可行性。完全符合我上面提到的對“真理的探究”。對比下自己,如果你遇到這樣的狀況,會懷疑嗎?會自己測試嗎?如果沒有,可能需要反思下了。
這里評論說IE11下測試結果一致,你是相信呢還是懷疑呢?你是直接接受了這個觀點呢?還是會自己在IE11下測試一遍?是真是假,是對是錯,咱接著往下看!
Benz says:
November 26, 2013 at 6:54 am
Jesuz so simple and so powerful – thx!
Benz 說:
2013-11-26 6:54
好簡單好強大 – 多謝!
//zxx: 典型的拿來主義者。快餐速食者。但至少人家還會評論以表示感謝。
Tyler says:
November 26, 2013 at 8:01 am
Just a note, this won’t work with fullscreen applications that rely on content panels using `overflow: auto`, as `pointer-events: none` on the body element won’t register the scroll events. It appears the pointer-events property needs to be applied to a container within the scrollable area.
Tyler 說:
2013-11-26 8:01
這里要注意下,這個對于內容面板需要使用 overflow: auto 全屏應用不適用,因為 pointer-events: none 應用在 body 元素上的時候不會注冊滾動事件。似乎 pointer-events 屬性需要應用在有滾動區域的容器上。
//zxx: 這個算是一個補充tip. 哪個滾動哪個應用 pointer-events: none . 是不是應該自己測試下?沒錯,后面會展示我的測試結果。
Malte Ubl says:
November 26, 2013 at 9:14 am
Simple, but doesn’t work as well as you think because this approach makes the document unclickable for up to 500ms after scrolling end. Here is an explanation how to fix it https://plus.google.com/+MalteUbl/posts/NsyYKenqYNP
Malte Ubl 說:
2013-11-26 9:14
很明顯,這廝不會如你所想那般工作。因此,它會讓頁面在滾動結束后500毫秒內沒法點擊。這顯然會有問題,下面這個可以修復這個問題
https://plus.google.com/+MalteUbl/posts/NsyYKenqYNP .
//zxx: 該評論給出的鏈接似乎要爬梯子的干活。我司天然KX上網,于是截個圖給大家看看:

其解決問題的關鍵技術點與我11年關于 pointer-events 那篇文章給出的兼容解決方案的技術點一致。
Chip says:
November 26, 2013 at 11:38 am
Really nice – solves a specific issue we we’re having with hover events firing off while scrolling! The only issue I’m still seeing is the recalcute style (purple) event jumping to 30 fps each time the class is added to the body. I didn’t see the same thing in your video so I’m wondering if I’m doing something wrong.
https://www.dropbox.com/s/jant444jwgo2jep/recalculate%20jump.png
Chip 說:
2013-11-26 11:38
真的很贊!解決了我們滾動時候觸發hover事件這個問題。現在我仍不解的唯一問題就是,每次往 body 添加類名的時候,計算樣式(粉色那個)事件立馬跳到30幀頻。但是,我在你的視頻上沒有看到同樣的現象。我在想是不是我哪里做錯了。一張需要爬墻同時可能被刪除的圖片地址。
//zxx: 哈,這一部分對話很精彩的,注意下面作者的回復~
Ryan Seddon says:
November 26, 2013 at 12:53 pm
<p>@Chip – Yep @derSchepp has said to set document.body.style directly rather than adding/removing a class to avoid a reflow. I’ll update the article real soon.Also I’d say it’s way less noticable in my video as my DOM structure is a lot simpler than your app you’re trying this in.</p>
Ryan Seddon 說:
2013-11-26 12:53
<p>@Chip – 嗯哪,根據@derSchepp的說法,直接在 document.body.style 上設置相比添加/刪除類名可以避免回流。我待會就更新下文章。</p>另外,您可能沒注意到,我視頻中DOM結構要比你嘗試的app要簡單多。
//zxx: 繼續精彩的對話~
Chip says:
November 26, 2013 at 2:20 pm
I tested Malte’s idea of adding / removing a cover div and that is working the best for me. Changing the document.body.style still causing a 30fps recalculate, but simply adding / removing a cover div with the following css worked perfect and keeps us at 60fps:
.scroll-cover {
top: 0;
left: 0;
bottom: 0;
right: 0;
position: fixed;
pointer-events: auto !important;
z-index: 10000;
}
var body = document.body,
cover = document.createElement('div');
cover.setAttribute('class','scroll-cover');
window.addEventListener('scroll', function() {
clearTimeout(timer);
body.appendChild(cover);
timer = setTimeout(function(){
body.removeChild(cover);
},500);
}, false);</pre>
I was able to change the setTimeout to 100 to make clicks more responsive and still keep perf
Chip 說:
2013-11-26 14:20
我試驗了Malte關于“添加/移除一個覆蓋div”的想法,貌似效果最好。改變 document.body.style
依舊會導致30fps的重計算,但是很單純地“添加/移除一個覆蓋div”同時使用下面的CSS效果完美,依然保持60fps.
代碼略…
我把 setTimeout 時間改成 100 毫秒依然效果很贊哦。
//zxx: 是不是又新技能get啦!到底是新技能還是新雞肋?面對這個疑問我們該怎么辦?很簡單,按照上面的真理步驟,1. 懷疑; 2.自己試驗。這個后面我們一起實踐一番。
Matt Stuehler says:
November 26, 2013 at 3:17 pm
How does this apply to mobile devices (iOS in particular)? Is it at all relevant?
And if it is… what are the implications of using -webkit-overflow-scrolling: touch? That seems to complicate the issue of knowing when the scroll event begins and ends…
Matt Stuehler 說:
2013-11-26 15:17
這個在移動設備上咋整啊(尤其iOS設備)?這個是一方通行的嗎?
如果……使用了 -webkit-overflow-scrolling: touch 又該如何實現?似乎當滾動事件開始于結束的時候,問題變得更復雜了……
//zxx: iOS等移動設備上副作用開始有人提出……
Peter says:
November 27, 2013 at 5:58 pm
This looks great! However there’s one thing I don’t understand – you disable pointer events and immediately after show that the hover states still work, before scrolling down the page at 60fps. How did the hover states still work? Were you enabling the JS version not just applying the CSS class? Thanks!
Peter 說:
2013-11-27 17:58
看上去很不錯!但我有一事不明——你禁用了 pointer events 但 hover 狀態在滾動結束后又立即顯示出來了。怎么辦到的?你是不是JS里面搗騰了葫蘆藥而不僅僅是應用CSS類名啊?多謝!
//zxx: 沒好好看文章的小白來問問題了。
sam says:
November 28, 2013 at 5:36 am
Blown away. This is simply brilliant.
sam 說:
2013-11-28 5:36
走起。簡直超神了。
//zxx: 馬屁黨。
Aurelien Foutoyet says:
November 28, 2013 at 8:33 am
Really clever sir.Thanks for sharing !
Aurelien Foutoyet 說:
2013-11-28 8:33
太聰明了。多謝分享!
//zxx: 馬屁黨, again!
Ryan Seddon says:
November 28, 2013 at 9:07 am
<p>@Peter –</p>
The hover effects are only disabled once you start to scroll so it won’t interfere with hover until then, so that’s why hover still works in the video after I click the disable button.
Ryan Seddon 說:
2012-11-28 9:07
<p>@Peter –</p>
hover 效果只在開始滾動的時候禁用,所以此時沒有 hover 相關交互,直到滾動停止。這就是為什么視頻中我點擊了禁用按鈕, hover 效果仍然有效的原因。
//zxx: 小白輔導中……
Ryan Seddon says:
November 28, 2013 at 9:14 am
<p>@Matt – Hover on scroll isn’t really relevant to non mouse based devices as you can’t really trigger a hover. You should really avoid the use of :hover on touch based devices all together as it causes issues.</p>
Ryan Seddon 說:
2013-11-28 9:14
<p>@Matt – 對于無鼠標設備而言,scroll上面的hover實際沒有關聯的。因為你沒法真正觸發 hover . 如果這導致了某些問題,你應該試著避免在觸摸式設備上使用 :hover .</p>
//zxx: 有推脫之嫌……
Sam Jarvis says:
November 28, 2013 at 7:21 pm
Amazing.
Sam Jarvis 說:
2013-11-28 19:21
震精。
//zxx: 馬屁黨,again’s again.
Manumanu says:
November 28, 2013 at 10:42 pm
Great idea. Just wanted to say : IE11 naturally disable pointer events when scrolling. Dunno since which version, ’cause i wasn’t aware of this issue.
Manumanu 說:
2013-11-28 22:42
想法不錯。我只想說:IE11在滾動的時候天然禁用 pointer events . 但不知道從哪個版本開始,因此這里的探討的問題我一點也不在意。
//zxx: 喲,注意啦!問題來了!前面有測試說IE11下結果跟Chrome是一樣的,這位兄弟說IE11天然滾動禁用鼠標事件。孰對孰錯?還得自己測試~~
Ben Knight says:
November 29, 2013 at 2:57 pm
Great minds think alike!
https://推ter.com/benjamin_knight/status/401829093055791104
Ben Knight 說:
2013-11-29 14:57
英雄所見略同!
https://推ter.com/benjamin_knight/status/401829093055791104
//zxx: 有想法要通過更好的渠道呈現告知。否則,你就不是首創者。這位兄弟推ter發布于17號,見下圖:

Mathias Bynens says:
November 29, 2013 at 6:09 pm
Instead of document.body , consider applying this to the root element ( document.documentElement ). That way, it will still work if you use <html> and <body> as a free <div> — e.g. if you apply margin: 0 auto; max-width: 30em; box-shadow: …; to <body> .
Mathias Bynens 說:
2013-11-29 18:09
可不可以應用在根元素上( document.documentElement ),而不是 document.body . 這樣,即使你把 <html> 和 <body> 作為普通的 <div> 使喚也是可以的。——例如,應用 margin: 0 auto; max-width: 30em; box-shadow: …; 到 <body> 上。
//zxx: 看上去又是一個不錯的建議。是否OK,還需要我們的親自測試,而不是別人說什么就信什么。
newable says:
November 30, 2013 at 12:31 am
Great!
newable 說:
2013-11-30 0:31
贊!
//zxx: 又見馬屁黨!
Richard Ayotte says:
November 30, 2013 at 1:30 am
It would be nice if this behaviour was the default in browsers.
Richard Ayotte 說:
2013-11-30 1:30
如果瀏覽器的默認行為就是這樣那就帥氣了。
//zxx: 我說兄弟,你何來結論認為瀏覽器的默認行為不是如此?
Thierry Koblentz says:
November 30, 2013 at 3:26 am
Hey Ryan,In my opinion, this is something browsers should be smart enough to do themselves. So it would make sense to me if one already did; IE11 may be? As @Manumanu suggests.
Thierry Koblentz 說:
2013-11-30 3:26
那個,Ryan,在我看來,這種事情應該讓瀏覽器自己解決。如果有那個瀏覽器已經做了這件事,對我而言是極好的;可能IE11? 正如@Manumanu提到的。
//zxx: 好吧,其實我也是這個觀點。后面的一些實驗數據和現象會說明,瀏覽器不是傻子。
JosiahS says:
November 30, 2013 at 5:59 am
Interesting idea, but it seems to have the side effect of disabling multi-touch page scrolling on Chrome in Windows 8. (I haven’t tested it anywhere else.)
JosiahS 說:
2013-11-30 5:59
很有意思的想法,但是貌似在Windows 8的Chrome瀏覽器中有副作用,頁面的觸屏滾動被禁用掉了(我還沒有測試其他任何地方)。
//zxx: 哦哦哦,出大簍子了,如果這個屬實,此方法又中了一刀致命傷。
Ron says:
November 30, 2013 at 7:54 am
Any reason why this shouldn’t just be built into Chrome?
Ron 說:
2013-11-30 7:54
有什么理由這不應該被內置到Chrome瀏覽器?
//zxx: 我只想說,我們深受喜愛的Chrome瀏覽器不是傻子。
RS says:
November 30, 2013 at 9:28 am
Echoing poster above, yes brilliant indeed. I’ve got to say, one thing I personally find just annoying is hover effects on images–you know like those with an overlay and some icon–something, anything–showing that it’s a video post, or image post or whatever. But alas, every client wants this garbg! And of course when you’re scrolling down the page, and mouse pointer hits the images/elements then it can be a very unsatisfactory experience.
Thanks for the post!
RS 說:
2013-11-30 9:28
我很贊同上面的文藝,確實很贊。我不得不說,關于 hover 效果,我一直有件事情耿耿于懷,那就是圖片的 hover
效果,你懂的,經常會出現一個覆蓋層,上面有圖標以及其他什么東西,告訴你這是個含視頻的文章,或者含圖片的文章等。但是不幸的是每個客戶端都會觸發之,試想下,當你向下滾動頁面的時候,鼠標觸碰了這些圖片或元素,會是一個不好的體驗。
感謝這篇文章!
//zxx: 怎么感覺是個腦殘粉,或者專門調停的老好人。兄弟,你說的那出戲不是我們這場,好吧。你嫌棄鼠標 hover 晃瞎自己的研究,使用鼠標 hover 延遲技術啊,與這里提高繪制呈現性能不搭噶的,好吧。哪邊涼快哪邊待去~求你了,你那凌亂不通的語句讓我很辛苦的~
Jake says:
December 1, 2013 at 7:55 am
I tried this a while ago on a project and it does trigger a layout when pointer-events: none; is applied to the body (It does in your demo as well). I came up with a different solution but it was more complicated. It basically involves moving a 100x100px fixed position div under the mouse using translate3d() while scrolling, then moving it back out of the window when scrolling is done. That stops the hover effects and doesn’t trigger a layout. This was on a really complicated page, so that forced layout was more of an issue.
Jake 說:
2013-12-1 7:55
不久前在一個項目中我嘗試了這個,當 pointer-events: none; 應用在 body 上的時候(正如demo做的那樣)觸發了布局。我就想了一個不同的解決方法,但是要更復雜些。我創建了一個 100x100px fixed 定位的元素,通過 translate3d() 讓其在滾動的時候移動在鼠標的小面,當滾動停止的時候再移動到窗體外面。這下子阻止了 hover 效果同時不觸發布局。因為這是一個非常復雜的頁面,因此觸發布局(layout)是個比較嚴重的問題。
//zxx: 復雜頁面的重布局確實可能會有明顯的性能損耗。但是,這位同學的做法,我個人覺得是不是應該治本而不是治標。
Greg says:
December 2, 2013 at 8:18 am
Thank you!!!
I used this technique to solve a different problem which should also be worth mentioning.
On my site I am using the Google Maps API and when I scroll down the page (using the scroll-wheel) the page suddenly stops once my mouse hovers over the map. The scroll-wheel would then start to re-scale the map which was annoying, I could disable the scroll wheel in the API but that would disable it permanently.
Using this method the user can now scroll past the map using the scroll wheel AND re-scale the map if they so desire using the scroll wheel. Two worlds in harmony 
Greg 說:
2013-12-2 8:18
多謝!!!
我使用這個技術解決了另外一個問題,我覺得值得一提。
我的站點上使用了Google地圖API當我使用滾輪滾動頁面的時候,當我鼠標經過這個地圖的時候,滾動就會停止,變成地圖大小的縮放了。我可以利用API禁止地圖的滾輪縮放,但是這種禁用是永久的。
使用這個方法用戶就能夠自如地從地圖上面滾過去,同時不影響地圖的縮放。兩個世界都和諧了 
//zxx: 這倒是一個不錯的應用場景。只是我疑惑的是,難道這位兄弟不要關心IE9, IE10瀏覽器嗎?實際上,你使用一個小小 div 覆蓋在地圖上,也可以到達一樣的效果。且兼容性更好。
d43m says:
December 3, 2013 at 7:11 pm
Looks like it doesn’t change anything with firefox, at least on the demo site, the hover effect doesn’t trigger either way while scrolling.
However, good tip for scrolling on the map Greg !
d43m 說:
2013-12-03 19:11
似乎firefox下沒有任何改變,至少本文的demo頁面如此,滾動時候不會觸發任何hover效果。
不過,Greg的那個地圖處理技巧很贊!
//zxx: 大家可以自己在FireFox瀏覽器下測試下,滾動的時候是不會有hover效果觸發的,停下來才會有,也就是從肉眼所見來看,似乎FireFox天然對滾動與 hover 呈現做了優化處理。
Schalk Neethling says:
December 3, 2013 at 11:02 pm
Thanks for this awesome article! Here is how I ended up implementing it and it works great ~ https://gist.github.com/ossreleasefeed/7768761
Schalk Neethling 說:
2013-12-03 23:02
多謝分享如此精彩的文章。這里是我的實現,效果很贊~ https://gist.github.com/ossreleasefeed/7768761
//zxx: 這就是上面一位兄弟提的 pointer-events:none 應用在 document.documentElement 上。
/**
- Disable and enable event on scroll begin and scroll end.
- @see http://www.thecssninja.com/javascript/pointer-events-60fps */ var root = document.documentElement; var timer;
window.addEventListener('scroll', function() { // 用戶滾動停止timeout clearTimeout(timer); // Pointer events 已被禁用 if (!root.style.pointerEvents) { root.style.pointerEvents = 'none'; }
timer = setTimeout(function() {
root.style.pointerEvents = '';
}, 500);
}, false);</pre>
egiova says:
December 4, 2013 at 2:48 am
Excellent little trick to avoid “light pollution”. What about side effects on touch screens?However, it remains to be tested at large scale. But good clue to follow…
egiova 說:
2013-12-04 2:48
避免“光污染”不錯的小伎倆。觸摸屏幕的副作用怎么辦呢?顯然,這還需要大規模的測試。但是值得跟進……
//zxx: 有疑問,沒有實踐~
Greg Whitworth says:
December 6, 2013 at 3:50 am
<p>@Manumanu @RyanSeddon He is somewhat correct in regards to how IE11 handles :hover on scroll. To keep the explanation simple (we may post a blog post for more detail on the matter), we turn off hit testing if the mouse isn’t moving so you won’t get any un-necessary paints, however, there are some caveats to this for compatibility reasons. Even when using your suggested CSS+JS trick you won’t get too much perf increase in IE11 due to the fact that we use independent rendering (we’re rendering on a separate thread from the UI thread) but it would free up some CPU cycles for any script you might be running. Hope that helps!</p>
Greg Whitworth 說:
2013-12-6 3:50
<p>@Manumanu @RyanSeddon 他對IE11的 :hover 在滾動上的認識或多或少是正確的。為了解釋簡單(關于此話題的細節我們可以發表一篇博文),我們可以簡單理解為,如果鼠標不移動,我們關閉 hit testing , 這樣就不會有無所謂的繪制,但考慮到兼容原因,還需要一些注意事項。即使使用你提出的CSS+JS技巧,在IE11中也不會得到很完美的性能提升。因為我們使用了獨立渲染(使用分離的UI線程進度渲染),它會為你運行的任何腳本進行周期性的CPU釋放。希望這個有所幫助!</p>//zxx: “hit testing”在 維基上的解釋 是:在計算機圖形編程中, hit-testing
是一個確定用戶的光標(如鼠標光標,接觸點或觸摸屏界面)是否與屏幕上繪制的給定圖形對象(如形狀,線和曲線)相交接的過程。Hit-testing可以在鼠標或其他指針設備移動或啟動執行。
在Web編程語言(如CSS, HTML, SVG)中,這是與 pointer-events (如用戶發起的光標移動或對象選擇)的概念相關聯的。
聽口氣,這位兄弟是在IE干活的嗎?似乎總是把IE11稱為我們~~不解~~
Yuanyan says:
December 9, 2013 at 6:37 pm
If u do it, it will make scrolling not work on mobile device.Test on mobile that “pointer-events: none” will disable the touch events. It’s seems not a good hack for mobile web.
Yuanyan 說:
2013-12-9 18:37
如果你砍了這一刀,移動設備的滾動直接斃命。經測試, pointer-events: none 會干掉 touch 事件。貌似此技巧對移動web不適用啊!
//zxx: 貌似是國人啊,還貌似是我廠的同行。微博是@元彥,大家加粉的時候記得補上一刀,說是我推薦的,(*^__^*)
Alex says:
December 9, 2013 at 8:17 pm
Firefox also turns off hit testing while scrolling, and from a quick test of the test page this trick would probably slow it down (Changing the pointer-events causes it to repaint whatever the mouse was hovering over when the scroll started, which it doesn’t do otherwise)
Alex 說:
2013-12-9 20:17
Firefox滾動時候也會關閉 hit testing , 面對本文的測試頁面的快速測試,這種處理可能會降低頁面速度(但是,如果瀏覽器不這么做,那在滾動開始的時候改變 pointer-events 會導致無論鼠標移到哪里都會重繪)
//zxx: 尼瑪,我盡力了。我實在不知道這位兄弟要講的是什么意思。不是他說的不懂,而是我被頭像嚇住了。歡迎大家幫忙糾正!
五、實踐出真知
上面的評論為我們打開看很多天窗。
我們看到了很多需要我們自己動手去試驗的東西,比如IE11的繪制呈現幀測試, div 層覆蓋測試,FireFox天然滾動體驗,Chrome瀏覽器下親自測試等。
為了得到更廣泛更具有價值的測試結果,我們使用自己設計的測試頁面,含半透明,投影以及紋理背景。
您可以狠狠地點擊這里: 滾動與hover繪制時間測試demo
進度demo,會看到一排排張含韻的上面有如下圖所示的幾個按鈕:

點擊第一個按鈕會給 body 添加 pointer-events:none ;點擊第二個按鈕會有一個層覆蓋在頁面上。通過ESC鍵可以取消之前任意兩個禁用 hit testing 操作。
測試的方法是,鼠標位置不變(避免不必要的重繪),上下 快速滾動 鼠標。由于鼠標要去點擊停止記錄按鈕,也會有重繪出現。因此,末尾的數據不可信,主要看截圖的中間主體部分。關注fps等幀頻信息。
分別測試了如下三種狀態: 1. 默認滾動; 2. pointer-events:none下的滾動; 3. div fixed定位層覆蓋后的滾動
以下數個測試截圖都是按照這三個狀態下拉的。
1.下面三張圖是自己在 最新版IE11瀏覽器下 的連續三個測試截圖:
默認滾動:

pointer-events:none繪制:

div元素覆蓋繪制:

2.這是我 本機Chrome26測試的結果 :
默認滾動:

pointer-events:none繪制:

div元素覆蓋繪制:

3.下面三張圖是 公司機Chrome31下測試結果 :
默認滾動:

pointer-events:none繪制:

div元素覆蓋繪制:

都是純手工的測試,因此,測試結果截圖長得不是很整理,但是,足夠說明一些問題了,我覺得是很有意思的一些問題,尤其結合眾老外的一些精彩評論。
- 首先,對比IE11, Chrome26以及Chrome31的測試結果,可以發現,div層覆蓋的方法絕對是呈現性能最差的,基本上要奔30幀/秒的頻率去了。但是,第8條評論中Chip對 div 覆蓋方法贊不絕口,說是最佳實踐, 60fps
.
怎么回事?細細閱讀會發現,其關注的是“重計算”,也就是 recalculate . 見下圖高亮:
而不是我們這里著重探討的呈現 – paint.
至于 div 層覆蓋法對fps的影響,根據我在Chrome26下不太專業的測試,似乎是相反的結論。精力原因,我就不深入測試,您有興趣可以稍稍研究下,發個博文或者微博什么的。
- IE11自身縱向對比。肉眼觀察來看, pointer-events:none 似乎要比默認態滾動的呈現要快那么一點點,但是,真的并不明顯。這似乎正如編號為30的評論所說,本文的CSS+JS技巧不會在IE11下得到完美的性能提升。因為IE11本身的渲染以及CPU回收等都有自己的 優化機制。
- 再從Chrome26瀏覽器的縱向對比來看,似乎 pointer-events:none 有還是沒有沒什么區別啊。這個是不是出乎意料了!我拿老外的那個測試頁面測試,發現,確實沒有什么差異!
- 我們再拿Chrome26橫向對比Chrome31瀏覽器,會發現Chrome31瀏覽器下,瀏覽器的繪制呈現時間基本上就沒有了!而 div 覆蓋時間類似。說明差異不是系統造成的,只可能是,Chrome隨著版本的升級,在渲染呈現性能上也有了提升。
- Chrome31默認狀態和 pointer-events:none 狀態對比,您會發現,似乎差別不大,默認態除了幾個冒尖的柱狀圖,其他基本上和 pointer-events:none
類似。咋回事?
Chrome31的這三張圖實際上是最先測試的,并未注意到鼠標不能移動這一細節。我沒估計錯的話,冒尖的幾個小綠柱子應該是鼠標移動造成的。如果我的這個推論正確的話,那豈不是如果鼠標不移動,單純滾動的話, pointer-events:none 加與不加是沒有任何區別的?!
沒錯!我就是要告訴你們, pointer-events:none提高頁面滾動時候的繪制性能 是不準確的 !
您可能會疑惑,哎呀,原作者視頻都出來了,確實繪制柱狀圖差異明顯啊!我自己去demo頁面測試,也是如此啊!兄弟,實際上,原作者變了個魔術而已,一個近景魔術!
你有沒有想過這么一個問題:為何作者的定時器間隔要設置成 500 毫秒這么久?當滾動結束,我們想點擊一個東西,只要速度一快,豈不是根本就沒效果!如此大的可用性風險,為何不設置個 100 毫秒呢,正如評論(編號8)中某人說的一樣?
答案很簡單。為了測試結果好看,數據對比明顯,干擾條件減少!
試想下,定時器間隔如果是 100 毫秒,如果滾動稍微慢一點,豈不是 body 就會發生狀態變化,類名移除,頁面重計算,測試數據變成默認態數據,數據污染,柱狀圖從平原變山峰。如果一不小心又滾快了, body 再變化,重計算與重繪就會交替出現。重計算干擾+狀態不穩定,必然導致測試數據不好看。因此,小間隔時間定時器不合適。
但這個原因其實不是主要原因。
如果間隔時間是 100 毫秒,我們要想一直保持 pointer-events:none 狀態,勢必滾動的時候要速度比較快。問題來了,這滾動速度一塊,你就會發現,默認狀態的重繪時間也是60fps的,柱狀條的高度與 pointer-events:none 類似。這不傻逼了嗎?這魔術不久穿幫了嗎?
因此,保險起見,定時器間隔還是 500 毫秒的好!
我在對一干評論的麻辣點評中多次提到:Chrome瀏覽器不是傻子,不會考慮hover重繪與滾動的性能優化?
類似的優化在IE11以及FireFox瀏覽器中均有。其中,FireFox瀏覽器尤其明顯。你現在用FireFox打開demo頁面,鼠標位置放在任意圖片上,不移動,單純滾動鼠標輪子。當你鼠標停止,你會明顯看到一定延遲時間后,hover效果才呈現。這不就是 pointer-events:none 要實現的狀態嗎?
Chrome瀏覽器也是有的,但是,Chrome瀏覽器由于自身渲染性能出眾,因此,這種延遲時間比較短。
因此,如果你的頁面滾動比較迅速,你是完全不要擔心 hover 渲染問題的。如果你滾動比較慢,瀏覽器認為你希望查看 hover 態,這不挺好的。
編號24評論吐槽鼠標經過hover效果閃啊閃的,體驗不好。諸位,這完全是另外一碼事了,就算你應用了這里的 pointer-events:none 方法,解決了滾動,那你鼠標經過該怎么處理呢,還不是閃啊閃?莫非再給 document 綁定 mousemove 事件,要是這樣,你讓 a 鏈接情何以堪。這種狀況還是乖乖使用鼠標 hover 延時執行技術吧,與這里不是一碼事。
簡單總結下就是: div 覆蓋法重繪損耗明顯,直接槍斃;快速滾動下, pointer-events:none 并無或極少繪制性能提升;慢速滾動,提高重繪有沒有意義。
六、我的綜合結論
眾家精彩評論中多次提到 pointer-events:none 影響觸屏設備的滾動,如手機,windows 8等。這個嚴重的性能缺陷顯然制約了此方法的普及。
其次,原文也提到另外一個問題:子元素設置了 pointer-eventes: auto 會導致滾動的時候頁面閃動。需要下面的代碼修正:
.disable-hover,
.disable-hover * {
pointer-events: none !important;
}
好麻煩,低效選擇器,這下頁面的估計重計算要到30fps了。
最后,也是最最重要的。 幾乎所有現代瀏覽器天然具有“快速滾動hover繪制的性能保護” 。何必多此一舉吃力不討好使用問題多多的 pointer-events:none ?
因此,如果您單純想要頁面的繪制速度,沒有任何理由使用 pointer-events:none 技術。如果您是希望禁用某些操作,例如26號評論中地圖縮放的處理等,這個倒是作為參考技術。
pointer-events:none 技術只有頁面在慢滾動的時候,才會有重繪性能提高優勢。不過話說話了,你頁面如果是慢滾動,還需要礙事的 pointer-events:none 嗎?
再退一萬步講,當下Chrome瀏覽器SVG動畫滿天飛也照樣跑得屁顛屁顛的, hover 所造成的重繪對用戶而言根本不足以造成絲毫的影響。
因此,所謂的提高 hover 繪制時間的技術,你就當路邊走過的一個美女吧,看一下,心撲通一下,就讓她過去吧,她不適合你的!
七、故事需要一個結尾
我老婆曾多次替我擔憂:“你把技術都分享出去,別人都學會了你的技術,那你豈不是更有壓力啦?”
我表示我一點都不擔心。
之前知乎上看到 一個贊非常多的問題 :“2013 年高考狀元業余愛好廣泛也看電視打網游,是我們素質教育開花結果了嗎?”

我不擔心的原因類似:“ 專注度差太多了! ”
中國的環境好啊,大家浮躁啊,喜歡吃現成飯啊。類似文章讀完就覺得,哦,滅了個boss,升級了。真的升級了嗎?突然想起了句中國古話:是知其然不知其所以然。大家忙著賺錢啊,理財啊,娛樂啊各種事情,能抽時間出來學習已經不錯了,你還讓我要潛心修學,深入思考。啊,我自己想想也確實不容易的。
如何能夠到達超出常人的高度,有個便捷的方法,那就是站在巨人的肩上。但是,如何站在巨人肩上是個頭疼的問題,對于我們最技術的人而言,在我看來,基本上就只有一步一步爬上去這條路,扎扎實實走自己的路。
但是,很多人以為跟巨人照個面,打個招呼,握個手就get的巨人的身高。實際上,啥都沒有。
面對一個技術點,如果你沒有追求“真理”的精神,單純是欣然接受,沒有自己的疑問,沒有自己的佐證,沒有自己的思考。最多只是撿了漏,技能最多照搬80%過去。因此,完全沒有必要擔心這類人會超越自己。但是,如果你敢于質疑與思考,有自己的試驗、實踐、思考與總結,發現未被關注的細節,完成更進一步的創新,恭喜你,你真真切切站在的巨人的肩上。
如果人人都是如此,那我確實要擔心不斷被別人超越的事情。好在中國大環境普遍浮躁,勢利,好大喜功,急功近利。因此,我依然高枕無憂地寫著自己的小文章,分享著自己的所思所想。
讀到這里的你是希望站在巨人的肩上呢?還是繼續撿撿巨人扔下的雞骨頭呢?
如果你要做前者,你應該知道要怎么做的?很簡單,“真理”三部曲: 1. 質疑 ; 2. 試驗實踐 ; 3. 提出自己認為正確的觀點 。
歡迎質疑我在本文提出的技術觀點,并提出你認為的真理!
本文為原創文章,包含腳本行為,會經常更新知識點以及修正一些錯誤,因此轉載請保留原出處,方便溯源,避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
來自: http://www.zhangxinxu.com/wordpress/2014/01/pointer-events-none-avoiding-unnecessary-paints/