整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          3行css實現循環動畫,順便說說瀏覽器兼容性

          前端開發來說,通過動畫來提升交互效果是很常見的。在很早以前,做web動畫主要通過javascript或者jquery或者flash這樣的手段,非常麻煩,自打有了ccs3,做動畫就太方便了,只需幾行css代碼就可以搞定。

          這里我們就演示一個常見的循環滾動效果,任務是這樣:先準備一個圖片,平鋪到頁面上充滿整個屏幕,然后就讓畫面一直向上循環滾動,形成無邊無際的感覺。

          雖然可以從網上搜到一些類似的代碼,但是魚龍混雜,無關緊要的代碼非常多,不夠純粹。如果要弄明白動畫的原理,只有自己動手做一遍才能真正消化吃透。所以我們來一步步原創這個代碼,排除所有不必要的基礎樣式,只說要點,3個步驟你就可以完全掌握其精髓!

          第一步:布局

          首先,滾動的圖片需要放在一個容器里,一行html代碼即可完成:

          第二步:把圖片放進容器

          css中body的邊界設為0,把容器設高度100%以充滿屏幕,再調用背景圖pic.png

          第三部:讓畫面動起來

          咱不做標題黨,循環滾動靠的就是3行css動起來的。

          先是1行 -webkit-animation屬性:4個參數分別表示:動畫名稱scroll,1秒時長,移動速度為線性的,無限循環。

          然后是對應的關鍵幀 @-webkit-keyframes 屬性,這是自己定義的動畫規則,只需寫2行規則即可:

          原理:動畫就是畫從一個地方動到另一個地方。對普通滾動效果來說,有起點和終點這兩個節點的位置就夠了。所以我們用0%和100%分別表示起點和終點,指定2個背景圖的xy位置坐標即可。圖片會在規定時間內從起點移動到終點,并循環下去,數值是負表示是向上移動。320px正好是圖片的高度,這樣循環的時候是無縫銜接的。

          好了,最終完整的代碼如下,是不是很精練呢?保存成 index.html 即可

          代碼寫完了,還要記得在當前目錄要有pic.png這個圖片哦,我隨便畫了幾筆,絕無觀賞性,建議自己找個好看點的圖片來代替。

          現在用瀏覽器打開index.html即可看到效果,比較魔性的地方在于,如果你盯著看久了,關閉窗口以后會出現幻覺,仿佛整個顯示器都在向上飛,哈哈!

          最后我們來說說瀏覽器兼容性問題:

          大家可能注意到了,前面那2個古怪的 -webkit-animation, @-webkit-keyframes 這里的-webkit-其實是一個前綴,animation和@keyframes才是CSS的標準屬性。

          當加上-webkit-后,就形成了一個針對特殊瀏覽器的專有屬性,表示用在谷歌的chrome和蘋果的safari瀏覽器上。此外還有-moz前綴代表針對firefox瀏覽器的私有屬性。

          所以我們在用到css3的一些特性的時候,經常使用一大堆的重復性的代碼,比如我們今天的這個代碼,有人會寫成這個樣子:

          一個簡單的動畫就要寫這么多冗余的代碼,為的只是支持一些舊的瀏覽器,有必要嗎?為什么在這個例子中我們僅僅采用了-webkit-而沒有使用其它專有屬性呢?

          因為現在已經是2019年了!谷歌蘋果的瀏覽器是主流,占據了絕大部分,而其它小眾瀏覽器也大多能夠兼容他們,在版本上,大部分人安裝瀏覽器是直接下載新版本安裝使用,而非找出家里陳年的老軟盤、老光盤去安裝,家中的老電腦也早已升級不知多少回了,所以也幾乎沒有機會使用低版本的瀏覽器了!

          至于微軟的IE,就更別提了,IE9以前不支持動畫的,只能用js或者jquery來寫動畫,直到IE10才支持css動畫,隨后IE被放棄,主推Edge,搞了幾天越來越頭大干脆也放棄,現在直接使用chrome內核了,所以針對ie的兼容性除非有特殊要求已經無需考慮。

          你在網上能看到的范例代碼,如果有寫成那么復雜臃腫的,估計也都是3-5年前發的老文,或者抄來抄去不做思考的搬磚工留下的“初學者”筆記。

          我們不仿測試一下幾款主流瀏覽器的情況看看,結論:

          測試結果表明,-webkit-的寫法在4款不同內核的瀏覽器上都能正常使用,所以我們的代碼因此能得以簡化。

          當然,這個例子也有局限性,比如你看,只有蘋果safari不支持標準寫法,萬一將來他改邪歸正了呢?畢竟標準寫法才是眾望所歸不是?使用針對個別瀏覽器的私有屬性寫法,雖可用但畢竟有些怪怪的,將來怎么樣還很難說呢。這樣看來,如果使用古老的處理辦法,重復N次為每個專屬瀏覽器各寫一份代碼,除了辣眼睛也真沒什么錯。

          瀏覽器的兼容問題涉及面實在是非常廣,三言兩語還真說不完,以后會專門來講。

          覽器內核中有一個渲染進程,又名Renderer進程,我們頁面的渲染,js的執行,事件的循環都在這一進程內進行,也就是說,該進程下面擁有著多個線程,靠著這些現成共同完成渲染任務。這個進程里面主要有一下幾個線程:

          1、 圖形用戶界面GUI渲染線程

          • 負責渲染瀏覽器界面,包括解析HTML、CSS、構建DOM樹、Render樹、布局與繪制等
          • 當界面需要重繪(Repaint)或由于某種操作引發回流(reflow)時,該線程就會執行
          • 與JS執行線程互斥。瀏覽器為了保持render樹結構的穩定,當JS執行時會停止頁面的渲染。

          2、JS引擎執行線程

          • JS內核,也稱JS引擎,負責處理執行javascript腳本
          • 等待任務隊列的任務的到來,然后加以處理,瀏覽器無論什么時候都只有一個JS引擎在運行JS程序,因為是單線程的。

          3、定時觸發器線程

          • setInterval與setTimeout所在線程
          • 定時計時器并不是由JS引擎計時的,因為如果JS引擎是單線程的,如果JS引擎處于堵塞狀態,那會影響到計時的準確
          • 當計時完成被觸發,事件會被添加到事件隊列,等待JS引擎空閑了執行
          • 注意:W3C的HTML標準中規定,setTimeout中低于4ms的時間間隔算為4ms

          4、異步HTTP請求線程

          • 在XMLHttpRequest在連接后新啟動的一個線程
          • 線程如果檢測到請求的狀態變更,如果設置有回調函數,該線程會把回調函數添加到事件隊列,同理,等待JS引擎空閑了執行

          5、事件觸發線程

          • 聽起來像JS的執行,但是其實歸屬于瀏覽器,而不是JS引擎,用來控制時間循環(可以理解,JS引擎自己都忙不過來,需要瀏覽器另開線程協助)
          • 當JS引擎執行代碼塊如setTimeout時(也可來自瀏覽器內核的其他線程,如鼠標點擊、AJAX異步請求等),會將對應任務添加到事件線程中
          • 當對應的事件符合觸發條件被觸發時,該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理
          • 注意:由于JS的單線程關系,所以這些待處理隊列中的事件都得排隊等待JS引擎處理(當JS引擎空閑時才會去執行)

          瀏覽器Event Loop圖:

          示例代碼:

          1. 初始化狀態都為空,瀏覽器控制臺是空的的,調用堆棧也是空的

          2. console.log(‘Hi’)添加到調用堆棧中

          3. 執行console.log(‘Hi’)

          4. console.log(‘Hi’)從調用堆棧中移除。

          5. setTimeout(function cb1() { … }) 添加到調用堆棧。

          6. setTimeout(function cb1() { … }) 執行,瀏覽器創建一個計時器計時,這個作為Web api的一部分。

          7. setTimeout(function cb1() { … })本身執行完成,并從調用堆棧中刪除。

          8. console.log(‘Bye’) 添加到調用堆棧

          9. 執行 console.log(‘Bye’)

          10. console.log(‘Bye’) 從調用調用堆棧移除

          11. 至少在5秒之后,計時器完成并將cb1回調推到回調隊列。

          12. 事件循環從回調隊列中獲取cb1并將其推入調用堆棧。

          13. 執行cb1并將console.log(‘cb1’)添加到調用堆棧。

          14. 執行 console.log(‘cb1’)

          15. console.log(‘cb1’) 從調用堆棧中移除

          16. cb1 從調用堆棧中移除

          快速回顧:

          宏任務和微任務

          在JavaScript中,任務被分為Task(又稱為MacroTask,宏任務)和MicroTask(微任務)兩種。它們分別包含以下內容:

          MacroTask: script(整體代碼), setTimeout, setInterval, setImmediate(node獨有), I/O, UI rendering

          MicroTask: process.nextTick(node獨有), Promises, Object.observe(廢棄), MutationObserver

          需要注意的一點是:

          在同一個上下文中,總的執行順序為同步代碼—>microTask—>macroTask

          具體來說,瀏覽器會不斷從task隊列中按順序取task執行,每執行完一個task都會檢查microtask隊列是否為空(執行完一個task的具體標志是函數執行棧為空),如果不為空則會一次性執行完所有microtask。然后再進入下一個循環去task隊列中取下一個task執行,以此類推。

          示例代碼:

          主程序和和settimeout都是宏任務,兩個promise是微任務

          第一個宏任務(主程序)執行完,執行全部的微任務(兩個promise),再執行下一個宏任務(settimeout),所以結果為:

          正確答案是

          script start, script end, promise1, promise2, setTimeout

          件循環機制:


          多進程和多線程

          1. 進程:程序的一次執行, 它占有一片獨有的內存空間

          2. 線程: CPU的基本調度單位, 是程序執行的一個完整流程

          3. 進程與線程

          * 一個進程中一般至少有一個運行的線程: 主線程

          * 一個進程中也可以同時運行多個線程, 我們會說程序是多線程運行的

          * 一個進程內的數據可以供其中的多個線程直接共享

          * 多個進程之間的數據是不能直接共享的


          4. 瀏覽器運行是單進程還是多進程?

          * 有的是單進程

          * firefox

          * 老版IE

          * 有的是多進程

          * chrome

          * 新版IE

          5. 如何查看瀏覽器是否是多進程運行的呢?

          * 任務管理器==>進程


          6. 瀏覽器運行是單線程還是多線程?

          * 都是多線程運行的


          js是單線程的

          1. 如何證明js執行是單線程的?

          * setTimeout()的回調函數是在主線程執行的

          * 定時器回調函數只有在運行棧中的代碼全部執行完后才有可能執行

          2. 為什么js要用單線程模式, 而不用多線程模式?

          * JavaScript的單線程,與它的用途有關。

          * 作為瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。

          * 這決定了它只能是單線程,否則會帶來很復雜的同步問題


          3. 代碼的分類:

          * 初始化代碼(同步代碼)

          * 回調代碼


          4. js引擎執行代碼的基本流程

          * 先執行初始化代碼: 包含一些特別的代碼

          * 設置定時器

          * 綁定監聽

          * 發送ajax請求

          * 后面在某個時刻才會執行回調代碼


          同步 異步執行順序:

          同步 同步執行完成才會去執行異步

          異步 只要是異步的任務都會有自己的管理模塊進行托管


          異步任務: (分為:微任務 、宏任務)

          回調

          事件

          定時器

          ajax

          生命周期回調函數


          常見的微任務有:

          1. Promise的.then.catch等方法
          2. Promise.resolve().then()以及其他通過Promise.resolve()創建的Promise的.then()方法、
          3. Object.observe回調

          常見的宏任務有:

          1. 定時器,比如setTimeout、setInterval、setImmediate等
          2. 調用DOM API時的回調函數,比如addEventListener中的回調函數
          3. requestAnimationFrame
          4. I/O 操作


          注意:在微任務執行之后再執行宏任務。


          事件循環模型

          1. 所有代碼分類

          * 初始化執行代碼(同步代碼): 包含綁定dom事件監聽, 設置定時器, 發送ajax請求的代碼

          * 回調執行代碼(異步代碼): 處理回調邏輯

          2. js引擎執行代碼的基本流程:

          * 初始化代碼===>回調代碼

          3. 模型的2個重要組成部分:

          * 事件管理模塊

          * 回調隊列

          4. 模型的運轉流程

          * 執行初始化代碼, 將事件回調函數交給對應模塊管理

          * 當事件發生時, 管理模塊會將回調函數及其數據添加到回調列隊中

          * 只有當初始化代碼執行完后(可能要一定時間), 才會遍歷讀取回調隊列中的回調函數執行


          事件循環的理解:


          理解:JavaScript事件執行隊列:

          將所有js事件依次放在一個執行隊列里:

          1.首先放入同步(事件)

          2.再放入異步微任務(事件) 如:.then .catch 里的回調

          3.再放入異步宏任務(事件) 如: 點擊事件、setTimeout定時器

          4.執行完以上事件 會進行一次GUI渲染。

          GUI渲染線程負責渲染瀏覽器界面HTML元素,當界面需要重繪(Repaint)或由于某種操作引發回流(reflow)時,該線程就會執行。


          5.事件循環:

          執行到異步微任務的時候 里面的回調一樣會按順序執行:

          1.同步(事件)

          2.異步微任務(事件)

          3.再異步宏任務

          4.再進行一次GUI渲染。

          再執行到異步宏任務的時候 里面的回調一樣會按順序執行

          1.同步(事件)

          2.異步微任務(事件)

          3.再異步宏任務

          4.再進行一次GUI渲染。


          最終完成事件的循環。


          代碼示例說明執行機制:

          setTimeout(() => {
            // 異步宏任務代碼
            console.log(`執行定時器setTimeout`);
          }, 0)
          
          new Promise(resolve => {
            console.log(`執行Promise的resolve`); // 同步代碼1
            resolve(1)
          }).then((val) => {
            // 異步微任務代碼
            console.log(`執行Promise的then-${val}`);
          })
          
          for (let index = 0; index < 10; index++) {
            // 同步代碼2
            console.log(`執行for循環${index}`);
          }

          打印結果:



          最終執行結果:

          1 Promise的resolve 同步代碼1 先執行

          2 for循環 同步代碼2 再執行 (無論循環多少次 都是同步代碼就會比異步先執行)

          3 then的回調 再執行 異步微任務代碼 (異步中微任務 比 宏任務 先執行)

          4 setTimeout 再執行 異步宏任務代碼


          歡迎關注我的原創文章:小伙伴們!我是一名熱衷于前端開發的作者,致力于分享我的知識和經驗,幫助其他學習前端的小伙伴們。在我的文章中,你將會找到大量關于前端開發的精彩內容。

          學習前端技術是現代互聯網時代中非常重要的一項技能。無論你是想成為一名專業的前端工程師,還是僅僅對前端開發感興趣,我的文章將能為你提供寶貴的指導和知識。

          在我的文章中,你將會學到如何使用HTML、CSS和JavaScript創建精美的網頁。我將深入講解每個語言的基礎知識,并提供一些實用技巧和最佳實踐。無論你是初學者還是有一定經驗的開發者,我的文章都能夠滿足你的學習需求。

          此外,我還會分享一些關于前端開發的最新動態和行業趨勢?;ヂ摼W技術在不斷發展,新的框架和工具層出不窮。通過我的文章,你將會了解到最新的前端技術趨勢,并了解如何應對這些變化。

          我深知學習前端不易,因此我將盡力以簡潔明了的方式解釋復雜的概念,并提供一些易于理解的實例和案例。我希望我的文章能夠幫助你更快地理解前端開發,并提升你的技能。

          如果你想了解更多關于前端開發的內容,不妨關注我的原創文章。我會不定期更新,為你帶來最新的前端技術和知識。感謝你的關注和支持,我們一起探討交流技術共同進步,期待與你一同探索前端開發的奇妙世界!

          #2023年度創作挑戰#


          主站蜘蛛池模板: 99久久综合狠狠综合久久一区| 中文字幕亚洲乱码熟女一区二区| 中文字幕一区二区三区乱码| 久久福利一区二区| 狠狠色综合一区二区| 亚洲熟妇无码一区二区三区导航| 成人h动漫精品一区二区无码| 日韩精品一区二区三区中文版| 一区二区三区免费精品视频| 国产在线不卡一区二区三区 | 国产一区二区三区露脸| 久久影院亚洲一区| 日韩免费无码一区二区三区 | 99久久人妻精品免费一区| 国产精品合集一区二区三区| 国产在线精品一区二区| 真实国产乱子伦精品一区二区三区 | 在线视频国产一区| 激情综合一区二区三区| 无码中文字幕人妻在线一区二区三区 | 亚洲一区免费视频| 人成精品视频三区二区一区| 国产精品毛片一区二区三区| 另类国产精品一区二区| 国精产品一区二区三区糖心| 久久久久人妻精品一区三寸| 三上悠亚一区二区观看| 国产精品无码一区二区三区毛片| 日本一区二区三区高清| 人妻互换精品一区二区| 色妞色视频一区二区三区四区| 波多野结衣中文字幕一区| 亚洲国产日韩在线一区| 香蕉在线精品一区二区| 国产精品美女一区二区三区| 一区二区视频在线观看| 91福利国产在线观看一区二区| 成人h动漫精品一区二区无码| 无码人妻视频一区二区三区| 一区二区国产精品| 国产精品综合一区二区三区|