解決按鈕移動(dòng)動(dòng)畫伴隨光標(biāo)樣式抖動(dòng)的問題

問題描述

最近在工作中遇到了一個(gè)很奇怪的問題盖喷,網(wǎng)站的頁面大部分按鈕和卡片都有一個(gè)向上移動(dòng)的過渡動(dòng)畫夯秃,當(dāng)鼠標(biāo)懸浮在這些元素上的時(shí)候愤惰,動(dòng)畫會(huì)觸發(fā)并在一定時(shí)間內(nèi)緩緩?fù)瓿砂椤⑼瑫r(shí)鼠標(biāo)樣式變成 pointer锨推,。

但是問題在于這個(gè)效果的實(shí)現(xiàn)并不理想公壤。鼠標(biāo)要是從左右兩邊和上邊移入按鈕或者卡片的話這個(gè)效果是看不出啥問題的换可,要是鼠標(biāo)是從下往上緩緩進(jìn)入,或者停留在上移的距離內(nèi)厦幅,這個(gè)特效會(huì)導(dǎo)致鼠標(biāo)和按鈕/卡片樣式不斷抖動(dòng)沾鳄,非常鬼畜。具體效果不便直接截圖給大家展示确憨,但是我在下面給出了解決方案后會(huì)給出一個(gè)模擬的效果 gif 和代碼(gif制作中)洞渔。

問題解決

雖然這個(gè)問題不在我的工作職責(zé)范圍內(nèi),但是作為一個(gè)“前端”工程師缚态,這個(gè)問題真的喚醒了我的強(qiáng)迫癥,不能忍暗塘觥玫芦!有沒有。

但是又因?yàn)楸救耸且粋€(gè)真實(shí)菜雞前端本辐,css方面急需惡補(bǔ)那種桥帆。医增。。剛遇到這個(gè)問題連怎么實(shí)現(xiàn)元素上移都不知道T.T老虫。所以一時(shí)間對(duì)這個(gè)問題實(shí)在想不出啥解決方法叶骨。然而在幾天之后,我在休息的時(shí)候解決了這個(gè)問題祈匙。

其實(shí)解決方法很簡單忽刽,其實(shí)就是原本代碼實(shí)現(xiàn)移動(dòng)效果使用的是css的top屬性結(jié)合position: relative;要解決這個(gè)問題只需要把實(shí)現(xiàn)方式更換成transform并使用相應(yīng)的transform函數(shù)即可夺欲,無需結(jié)合relative布局跪帝。

下面給出情景模擬的代碼,大家可以拷貝到一個(gè) html 文件里看看是啥效果些阅。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<style>
body {
    text-align: center;
}
#head {
    height: 100px;
    width: 100%;
}
#middle {
    margin: 0 auto;
}
#top-button {
    top: 0;
    position: relative;
    transition: .5s;
    -moz-transition: .5s;
    -webkit-transition: .5s;
    -o-transition: .5s;
    -ms-transition: .5s;
    cursor: pointer;
}
#top-button:hover {
    top: -8px;
}

#transform-button {
    margin-left: 100px;
    transition: .5s;
    -moz-transition: .5s;
    -webkit-transition: .5s;
    -o-transition: .5s;
    -ms-transition: .5s;
    cursor: pointer;
}

#transform-button:hover {
    transform: translateY(-20%);
}
</style>
<body>
    <div id="head"></div>
    <div id="middle">
        <button id="top-button">top 實(shí)現(xiàn)</button>
        <button id="transform-button">transform 實(shí)現(xiàn)</button>
    </div>
    
</body>
</html>

問題深究

為啥使用不同的 css 屬性會(huì)導(dǎo)致如此巨大的效果差異呢伞剑?

我突然意識(shí)到 css 其實(shí)是在網(wǎng)頁中其實(shí)屬于較高層次的抽象,出現(xiàn)問題后難以糾錯(cuò)主要是在于使用者對(duì) css 的了解太過于淺薄市埋,往往知其然不知其所以然黎泣,僅僅停留在使用的層次。因此出現(xiàn)問題和解決問題的過程宛如魔法一般缤谎。

所以這次我們就借著遇到的這個(gè)問題抒倚,來探討一下css渲染web畫面的一些底層原理:


瀏覽器如何繪制 dom 元素?

注意我們討論的是繪制的步驟弓千,在繪制之前衡便,還會(huì)經(jīng)過css計(jì)算、布局等步驟洋访。

  1. 獲取 DOM 并將其分割為多個(gè)層(layer)
  2. 將每個(gè)層獨(dú)立地繪制進(jìn)位圖(bitmap)中
  3. 將層作為紋理(texture)上傳至 GPU镣陕, GPU 會(huì)復(fù)合(composite)多個(gè)層來生成最終的屏幕圖像,然后將其顯示在屏幕上姻政。

具體的細(xì)節(jié)有可能因?yàn)?webkit 的不同而產(chǎn)生區(qū)別呆抑。

top 和 transform 的根本區(qū)別?

top 是一個(gè)布局屬性汁展,而 transform 是一個(gè)觸發(fā)合成層的屬性鹊碍,它并不會(huì)在布局階段被使用。

所以現(xiàn)在明白了食绿,為啥使用top實(shí)現(xiàn)的動(dòng)畫要配合relative實(shí)現(xiàn)侈咕?因?yàn)樗且粋€(gè)布局屬性,一旦它處于文檔流中器紧,還能夠?qū)ζ渌卦斐捎绊懸@樣會(huì)造成整個(gè)頁面回流(reflow)和重繪。

所以使用top的動(dòng)畫功能的時(shí)候需要配合 relative铲汪、absolute 這些屬性熊尉。

但是無論如何罐柳,使用top做動(dòng)畫特效實(shí)際上都會(huì)觸發(fā)布局計(jì)算和重繪過程,生成新的幀畫面后狰住,交給 GPU 去合成圖像张吉,這樣實(shí)際上造成了額外的性能開銷和不必要的動(dòng)作;而transform只是會(huì)額外地生成一個(gè)合成層催植,動(dòng)畫元素會(huì)在一個(gè)獨(dú)立的層次中動(dòng)畫肮蛹,并直接交由 GPU 處理,沒有經(jīng)過重繪來生成新的幀查邢。

還有什么屬性會(huì)觸發(fā)合成層蔗崎?

  • 3D 或透視變換 CSS 屬性
  • 使用加速視頻解碼的 <video> 元素
  • 擁有 3D (WebGL) 上下文或加速的 2D 上下文的 <canvas> 元素
  • 復(fù)合插件(如 Flash)
  • 進(jìn)行 opacity/transform 動(dòng)畫的元素
  • 擁有加速 CSS filters 的元素
  • 元素有一個(gè)包含復(fù)合層的后代節(jié)點(diǎn)(換句話說,就是一個(gè)元素?fù)碛幸粋€(gè)子元素扰藕,該子元素在自己的層里)
  • 元素有一個(gè) z-index 較低且包含一個(gè)復(fù)合層的兄弟元素(換句話說就是該元素在復(fù)合層上面渲染)

總結(jié)一下

  1. 對(duì)布局屬性進(jìn)行動(dòng)畫缓苛,瀏覽器需要為每一幀進(jìn)行重繪并上傳到 GPU 處理。
  2. 對(duì)合成屬性進(jìn)行動(dòng)畫邓深,瀏覽器會(huì)為元素創(chuàng)建一個(gè)獨(dú)立的復(fù)合層未桥,該層不會(huì)被重繪,直接交由 GPU 計(jì)算圖像芥备。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冬耿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子萌壳,更是在濱河造成了極大的恐慌亦镶,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件袱瓮,死亡現(xiàn)場離奇詭異缤骨,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)尺借,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門绊起,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人燎斩,你說我怎么就攤上這事虱歪。” “怎么了栅表?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵笋鄙,是天一觀的道長。 經(jīng)常有香客問我怪瓶,道長局装,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮铐尚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哆姻。我一直安慰自己宣增,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布矛缨。 她就那樣靜靜地躺著爹脾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪箕昭。 梳的紋絲不亂的頭發(fā)上灵妨,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音落竹,去河邊找鬼泌霍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛述召,可吹牛的內(nèi)容都是我干的朱转。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼积暖,長吁一口氣:“原來是場噩夢啊……” “哼藤为!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起夺刑,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤缅疟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后遍愿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體存淫,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年错览,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纫雁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡倾哺,死狀恐怖轧邪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情羞海,我是刑警寧澤忌愚,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站却邓,受9級(jí)特大地震影響硕糊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一简十、第九天 我趴在偏房一處隱蔽的房頂上張望檬某。 院中可真熱鬧,春花似錦螟蝙、人聲如沸恢恼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽场斑。三九已至,卻和暖如春牵署,著一層夾襖步出監(jiān)牢的瞬間漏隐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工奴迅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留青责,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓半沽,卻偏偏與公主長得像爽柒,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子者填,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345