facebook首頁的這個載入效果是怎麼實現的?

如題,就是這些條紋,並且它還會有動畫效果。

比較疑問的是,它可以提前知道有多少個整個框框。


我猜測這是使用了bigpipe技術,灰色框框是其中的佔位符。

facebook在幾年前搞了一個bigpipe技術,將頁面的下載解析等過程分解為八個步驟,其中幾個步驟可以並行執行,整體採用pipe思路,目的是為了減少頁面的訪問時間。

傳統的網頁渲染方法是

  1. 向伺服器發送HTTP請求
  2. 伺服器解析請求,讀取存儲層,制定出HTML頁面,返還給瀏覽器
  3. HTTP響應傳送到瀏覽器
  4. 瀏覽器解析web伺服器的響應,使用HTML文件構建一個DOM樹,並下載CSS和javascript
  5. CSS資源下載好後,解析CSS,並應用到DOM樹中
  6. javascript資源下載好後,解析javascript,並應用到DOM樹中

而BigPipe使用瀏覽器和伺服器並行的方法,將網頁的內容分為多個pagelet,每個pagelet的渲染過程如下

  1. 請求解析:web伺服器解析HTTP請求,並對其進行全面檢查
  2. 數據獲取:web伺服器從存儲層獲取數據
  3. 標記生成:web伺服器生成的響應的HTML標記(DOM token)
  4. 網路傳輸:響應從伺服器傳送到瀏覽器
  5. css的下載:瀏覽器下載網頁中的css
  6. 渲染DOM:瀏覽器根據html標記生成DOM樹,並應用CSS
  7. javascript下載:瀏覽器下載網頁中的javascript引用的資源
  8. 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 |