初版
用css3來實現彈幕確實比較簡單,只需要設置動畫讓彈幕從屏幕右側移動到屏幕左側即可,一開始是這樣實現的
.danmu { position: fixed; left: 100%; animation: danmu 5s linear 0s 1; } @keyframes danmu { from { left: 100%; transform: translateX(0); } to { left: 0; transform: translateX(-100%); } }
在pc端測試挺流暢,效果不錯,但是一拿到移動端上試,就發現這個動畫不流暢,有卡頓,ios稍好,android的話即使是配置高的機器也是有卡頓,配置低的機器就更是明顯。
緣由
一番研究,發現是因為keyframes中使用left,這樣的話left的改變會在渲染的過程中導致reflow,從而造成卡頓。那么改進的思路就比較明確了,移除left,只使用translate。
reflow(回流):例如某個子元素樣式發生改變,直接影響到了其父元素以及往上追溯很多祖先元素(包括兄弟元素),這個時候瀏覽器要重新去渲染這個子元素相關聯的所有元素。
repaint(重繪):如果只是改變某個元素的背景色、文 字顏色、邊框顏色等等不影響它周圍或內部布局的屬性,將只會引起瀏覽器 repaint(重繪)
回流的成本比重繪高得多
下面情況會導致reflow發生
1:改變窗口大小 resize事件發生時
2:改變文字大小
3:內容的改變,如用戶在輸入框中敲字
4:激活偽類,如:hover
5:操作class屬性
6:腳本操作DOM
7:計算offsetWidth和offsetHeight
8:設置style屬性
新問題
但是全部使用translate又有新的問題,使用left:100%可以達到讓彈幕從屏幕右側開始出現,但是translate使用的百分比單位是相對於自身的,我們需要明確的給出屏幕寬度來translate,而屏幕寬度只有運行時用js才能獲取到。這樣一來,動畫的keyframes看來是需要使用js來動態生成了。
解決方案
在需要展示動畫前,動態生成一個style,根據當前屏幕寬度定義好keyframes。
// css
.danmu { position: fixed; left: 0; visibility: hidden; animation: danmu 5s linear 0s 1; } // js代碼
let style = document.createElement('style'); document.head.appendChild(style); let width = window.innerWidth; let from = `from { visibility: visible; -webkit-transform: translateX(${width}px); }`; let to = `to { visibility: visible; -webkit-transform: translateX(-100%); }`; style.sheet.insertRule(`@-webkit-keyframes danmu { ${from} ${to} }`, 0);
注意,這里.danmu里設置了visibility為隱藏,不然彈幕會堆積顯示在屏幕左側,而keyframes里則設置visibility為顯示,這樣就使得彈幕只在動畫過程中才能被看見。
這么做的原因是彈幕的初始位置為left: 0才能方便的設置彈幕頭部從屏幕右側出現然后從右向左移動到彈幕尾部消失在屏幕左側為止。
再講解一下let ,ES6 新增命令,用來聲明變量。
let
聲明的變量擁有塊級作用域let
聲明的全局變量不是全局對象的屬性- 形如
for (let x...)
的循環在每次迭代時都為x創建新的綁定。 - 用
let
重定義變量會拋出一個語法錯誤(SyntaxError)。 - 不存在變量提升,聲明的變量直到控制流到達該變量被定義的代碼行時才會被裝載,所以在到達之前使用該變量會觸發錯誤,稱為“暫時性死區”(TDZ)
ES6引入了一種新型的字符串字面量語法,我們稱之為模板字符串
- 提供了簡單的字符串插值功能 ${變量名}
- 模板字符串可以多行書寫 模板字符串中所有的空格、新行、縮進,都會原樣輸出在生成的字符串中。