facebook首頁的這個載入效果是怎麼實現的?
01-05
如題,就是這些條紋,並且它還會有動畫效果。 比較疑問的是,它可以提前知道有多少個整個框框。
我猜測這是使用了bigpipe技術,灰色框框是其中的佔位符。
facebook在幾年前搞了一個bigpipe技術,將頁面的下載解析等過程分解為八個步驟,其中幾個步驟可以並行執行,整體採用pipe思路,目的是為了減少頁面的訪問時間。
傳統的網頁渲染方法是
- 向伺服器發送HTTP請求
- 伺服器解析請求,讀取存儲層,制定出HTML頁面,返還給瀏覽器
- HTTP響應傳送到瀏覽器
- 瀏覽器解析web伺服器的響應,使用HTML文件構建一個DOM樹,並下載CSS和javascript
- CSS資源下載好後,解析CSS,並應用到DOM樹中
- javascript資源下載好後,解析javascript,並應用到DOM樹中
而BigPipe使用瀏覽器和伺服器並行的方法,將網頁的內容分為多個pagelet,每個pagelet的渲染過程如下
- 請求解析:web伺服器解析HTTP請求,並對其進行全面檢查
- 數據獲取:web伺服器從存儲層獲取數據
- 標記生成:web伺服器生成的響應的HTML標記(DOM token)
- 網路傳輸:響應從伺服器傳送到瀏覽器
- css的下載:瀏覽器下載網頁中的css
- 渲染DOM:瀏覽器根據html標記生成DOM樹,並應用CSS
- javascript下載:瀏覽器下載網頁中的javascript引用的資源
- javascript執行:瀏覽器執行javascript
BigPipe的執行過程為:瀏覽器向web伺服器發送請求,web伺服器解析請求並進行一次完整的檢查,檢查完畢後立即響應,響應中包含一個HTML的head和body的一部分,其中head中的內容為BigPipe的js和css,js是用來解析之後的http響應,body的一部分內容為頁面的結構(只有DOM沒有內容)和pagelet的佔位符模板(視圖中的灰色框框),css為佔位符模板的css。
在瀏覽器收到響應後,伺服器立即執行數據的查詢,載入,生成。當一個pagelet所需的數據生成好後,立即調用flush()函數,將其返回給瀏覽器,返回的數據為json格式,包括該pagelet需要的css,js和html內容以及元數據,然後head中的js對其進行解析,首先下載css,然後將內容渲染到對應的DOM中,多個pagelet中的css同時下載,先下載完的css先顯示。
這個技術的核心優勢在於:並行執行。幾個pagelet的一些階段可以並行執行,例如可以同時下載兩個css文件,同時瀏覽器渲染另外一個pagelet的內容,同時伺服器在為另外一個pagelet生成源碼。
機緣巧合之下找到了一段比較完美的效果實現:
Facebook/Medium-Like-Loader-animation
效果預覽:
html:
&
&
&
&
&
&
&&
&&
&&
&&
&&
&&
&&
&
&
&
&
&
&
css
.timeline-item {
background: #fff;
border-bottom: 1px solid #f2f2f2;
padding: 25px;
margin: 0 auto;
}
@keyframes placeHolderShimmer {
0% {
background-position: -468px 0
}
100% {
background-position: 468px 0
}
}
.animated-background {
animation-duration: 1s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-name: placeHolderShimmer;
animation-timing-function: linear;
background: #f6f7f8;
background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
background-size: 800px 104px;
height: 40px;
position: relative;
}
.background-masker {
background: #fff;
position: absolute;
}
/* Every thing below this is just positioning */
.background-masker.header-top,
.background-masker.header-bottom,
.background-masker.subheader-bottom {
top: 0;
left: 40px;
right: 0;
height: 10px;
}
.background-masker.header-left,
.background-masker.subheader-left,
.background-masker.header-right,
.background-masker.subheader-right {
top: 10px;
left: 40px;
height: 8px;
width: 10px;
}
.background-masker.header-bottom {
top: 18px;
height: 6px;
}
.background-masker.subheader-left,
.background-masker.subheader-right {
top: 24px;
height: 6px;
}
.background-masker.header-right,
.background-masker.subheader-right {
width: auto;
left: 300px;
right: 0;
}
.background-masker.subheader-right {
left: 230px;
}
.background-masker.subheader-bottom {
top: 30px;
height: 10px;
}
.background-masker.content-top,
.background-masker.content-second-line,
.background-masker.content-third-line,
.background-masker.content-second-end,
.background-masker.content-third-end,
.background-masker.content-first-end {
top: 40px;
left: 0;
right: 0;
height: 6px;
}
.background-masker.content-top {
height: 20px;
}
.background-masker.content-first-end,
.background-masker.content-second-end,
.background-masker.content-third-end {
width: auto;
left: 380px;
right: 0;
top: 60px;
height: 8px;
}
.background-masker.content-second-line {
top: 68px;
}
.background-masker.content-second-end {
left: 420px;
top: 74px;
}
.background-masker.content-third-line {
top: 82px;
}
.background-masker.content-third-end {
left: 300px;
top: 88px;
}
另外非常抱歉暫時無法回答題主比較疑問的是,經過測試
Facebook每次是載入一個
Medium每次是放置3個另外新改版的知乎也是在請求載入完成前放置一個希望拿到題主的截圖來源,看不到代碼沒法做實驗。一個比較合理的猜測是,佔位符不是在請求介面數據前放置,而是在請求介面返回後,圖片等靜態資源載入前按照數據個數放置佔位符,然後在靜態資源載入完成後撤掉佔位符,給人的感覺就好像提前知道個數一樣。
動態效果占點陣圖用gif就行啊。
提前知道多少框框也簡單,你就想像成有一個取列表的介面,返回的列錶帶了一個item_count值。
我記得知乎Android app的某一個版本的首頁也是這種效果
[這個控制項叫:Skeleton Screen ](https://zhuanlan.zhihu.com/p/26014116)
至於實現方式,Google 吧。
話說這種效果有什麼好處嗎?
簡書也有這種效果。
推薦閱讀:
※網站為什麼 JS 調用盡量放到網頁底部?
※可否通過polyfill讓微軟的wscript能運行node.js腳本?
※如果 ES2015 完全普及了,我們還需要 Babel 嗎?
※React-Canvas、React-js、React-Native在用途、語言本質、性能表現等方面,各有什麼異同?
※Vue.js 這個框架怎麼樣評價?
TAG:前端開發 | CSS | JavaScript |