linux Firefox wordpress google nginx java Windows Android mysql 程序员 Ubuntu 编程 微软 centos php 开源 shell Python 云计算 apache

【H5疑難雜癥】脫離文檔流時的渲染BUG

BUG重現

最近機票團隊在一個頁面布局復雜的地方發現一個BUG,非常奇怪並且不好定位,這類問題一般最後都會到我這裏,這個問題是,改變dom結構,頁面卻不渲染!!!

如圖所示,我動態的改變了dom結構,結果頁面那一坨變得什麽都沒有,相當奇怪!!!在PC模擬iPhone就可以重現,iPhone、note4等手機上也可重現,由於這種BUG我不是第一次碰到,很快便引起了註意,總結起來可以歸結於:

js代碼改變fixed元素的html結構(一般是動畫後並且布局相對復雜),頁面不會渲染
問題定位-分離法

本著發現問題,定位問題,解決問題的步驟,我開始了定位,這裏的難點是,這類問題往往非常難以定位,因為他的dom tree相當復雜,首先我做了一個事情,直接將其htmlcss分離出來,擺脫js的原因,直接顯示該dom。

於是問題不在了,這個很令人費解,難道是js對其造成了影響?經過一輪糾纏,定位失敗開始二輪定位。

問題定位-最小化問題

這種問題確實不好處理的時候,光靠看頁面可能不能處理了,這個時候便把機票的代碼拿到本地,部署起來,做了幾件事情:

① 去掉該頁多余的業務代碼,基本上不完成任何功能

② 去掉多余的dom結構(由於我們是單頁應用,dom可能相對比較復雜)

打開對應業務代碼一看,洋洋灑灑3000行,立馬想吐:

這個時候一行行去讀代碼就是2B的行為了,直接找到那個顯示日歷的代碼:

然後稍作改動,把其它業務邏輯全部搞掉,事件綁定也搞掉,只留下顯示日歷的事件,直接一來點擊顯示日歷,這個時候形成的dom結構由4000多行變成了1000多行,但是依舊有BUG

問題定位-CSS重置

由於機票對日歷的樣式,做了重置,所以有理由懷疑是他們自己的css導致的問題,於是想去掉他們的css引用試了試,雖然樣式難看了點,但是問題依舊存在......

問題定位-js邏輯

這個時候便有理由懷疑其日歷顯示後,本身有一定邏輯功能導致出錯,於是看到了日歷show後面幹的事情,並且為了防止dom結構過大,將月份顯示設置為1月。

都這個樣子了,他居然還是渲染不處理,有點傷害自尊!!!

因為這個日歷顯示時候有一個從右到左的動畫,這個時候將其動畫關掉,卻發現問題解決了!!!其中的代碼為zepto的實現,不是關鍵

復制代碼
$el.css({
      '-webkit-transform': prepareCss,
      transform: prepareCss
})
  .show()
  .animate({
    '-webkit-transform': 'translate(0, 0)',
    transform: 'translate(0, 0)'
  }, 500, 'ease-in-out', function() {
    $el.css({
      '-webkit-transform': '',
      transform: ''
    });
  });
復制代碼
問題定位成功-脫離文檔流的渲染

最後問題定位成功,至少從表現和處理來說是定位成功的,簡單來說:

動畫執行結束後,如果我改變的是fixed元素中的一個子單元的html,不會有反應,但是我們同時改變static元素便會引起一次渲染,尼瑪這是神馬鬼!!!

問題探索-渲染的差異

為了弄懂這個原因,我們得看到渲染的細節,這裏做了一個對比:

不引起static dom變化

引起static dom變化

這裏註意觀察最後一次paint便可以看見渲染出來的東西不一樣,導致這種的差異是什麽呢,我們一次次的對比幾次不同

這裏做一個差異對比,因為這裏的static元素與fixed元素還有一些管理,我們這裏操作與之完全無關的元素試試。事實證明沒有什麽影響,所以這類問題的解決方案是:

移動端過多定位元素布局時,偶爾操作fixed元素html不會渲染,解決方案是同步改變與之相關的static元素,便會引導渲染
剛剛使用的是設置html,這裏完全可以使用這種做法:

el.html(el.html())
可以達到相同的功能,但是問題導致原因依舊不可知......不可說不是一種遺憾!!!如果您知道這個問題的答案,請您留言。

延伸阅读

    评论