使用CSS自定義屬性構建骨架屏

寫在前面

幾天前看到薄荷前端團隊分享的《前端骨架屏方案小結》,忽然回想起一年前看到的max bock寫的《Building Skeleton Screens with CSS Custom Properties》,翻譯整理寫下出此文,分享一下使用CSS自定義屬性構建骨架屏的技巧,先看骨架屏demo效果吧css


設計Web上的加載狀態經常被忽略或被認爲是過後考慮。性能不只是前端開發人員的職責,構建與慢速鏈接一塊兒工做的體驗也是設計挑戰。 雖然前端開發人員須要注意一些事情,好比壓縮和緩存,可是設計人員必須考慮UI處於「加載」或「離線」狀態時的外觀和行爲。前端


速度幻覺

隨着咱們對移動體驗的指望發生變化,咱們對性能的理解也在變化。咱們指望網絡應用程序感受像本機應用程序同樣快速響應,不管其當前的網絡覆蓋範圍如何。

感知性能是衡量用戶感受速度的尺度。這個想法是用戶更有耐心,而且若是他們知道正在發生什麼,而且在內容實際存在以前可以預測內容,那麼他們會認爲系統更快。這在很大程度上與管理指望和保持用戶知情有關。
git

對於Web應用程序,這個概念可能包括顯示文本,圖像或其餘內容元素的「模型」 - 稱爲
骨架屏💀。能夠在網上能夠看到,Facebook,Google,Slack等公司使用:


(Facebook的骨架屏)
github


(Slack的骨架屏)瀏覽器

例子

假設你正在構建一個Web應用程序,這是一種旅行建議類型的東西,人們能夠分享他們的旅行和推薦地點,因此你的主要內容可能看起來像這樣:


您能夠將該卡片縮小到其基本視覺形狀(UI組件的骨架)


每當有人從服務器請求新內容時,您能夠當即開始顯示骨架,同時在後臺加載數據。內容準備就緒後,只需將骨架換成實際卡便可。這可使用普通的JavaScript或使用像Vue/React這樣的庫來完成。

如今咱們可使用圖像來顯示骨架,但這會引入額外的請求和數據開銷。咱們已經在這裏加載了東西,因此等待另外一個圖像首先加載並非一個好方式。此外,它沒有響應,若是咱們決定調整一些內容卡的樣式,咱們將不得不復制骨架圖像的更改,以便它們再次匹配。😒

一個更好的解決方案是隻用CSS建立整個東西。沒有額外的請求,最小的開銷,甚至沒有任何額外的標記。咱們能夠用下面的方式來構建它,使之後更改設計變得更容易。

經過CSS繪製骨架

首先,咱們須要繪製構成卡片骨架的基本形狀。咱們能夠經過background-image屬性添加不一樣的漸變來實現這一點。默認狀況下,線性漸變從上到下運行,有不一樣的顏色中止過渡。若是咱們只定義一個顏色中止,並使其他顏色保持透明,咱們能夠繪製形狀。

請記住,在這塊,多個背景圖像堆疊在一塊兒,所以順序很是重要。最後一個漸變定義在後面,第一個位於前面。

.skeleton {
  background-repeat: no-repeat;
  background-image:
    radial-gradient(circle 16px, white 99%, transparent 0), /* 第3層 頭像 */
    linear-gradient(white 40px, transparent 0), /* 第2層 標題 */
    linear-gradient(gray 100%, transparent 0); /* 第1層 卡片背景 */
}

這些形狀拉伸來填充整個空間,就像常規的塊級元素同樣。若是咱們想要改變它,咱們必須爲它們定義明確的尺寸。 background-size的值來設置每一個圖層的寬度和高度,保持咱們使用的相同順序 background-image

.skeleton {
  background-size:
    32px 32px,  /* 頭像 */
    200px 40px,  /* 標題 */
    100% 100%; /* 卡片背景 */
}

最後一步是將元素放在卡片上。這與position:absolute相似,表示left和top屬性的值同樣。例如,例如:咱們能夠給頭像和標題 模擬24px的填充,以匹配真實內容卡的外觀。
緩存

.skeleton {
  background-position:
    24px 24px,  /* 頭像 */
    24px 200px, /* 標題 */
    0 0;        /* 卡片背景 */
}


使用自定義屬性將其分解

這在一個簡單的例子中效果很好, 可是若是咱們想要構建一些稍微複雜的東西,那麼CSS會很快變得混亂而且很難閱讀。若是代碼交接給另一個前端開發人員,他們就不知道全部這些神奇的數字來是從哪裏來的,顯然這是不易難維護的。

因而乎,這裏提出用自定義CSS屬性,以更加簡潔,更有利於前端開發人員的方式編寫骨架樣式 ,甚至能夠考慮不一樣值之間的關係:

.skeleton {
  /*
    定義單獨的屬性
  */
  --card-height: 340px;
  --card-padding:24px;
  --card-skeleton: linear-gradient(gray var(--card-height), transparent 0);

  --title-height: 32px;
  --title-width: 200px;
  --title-position: var(--card-padding) 180px;
  --title-skeleton: linear-gradient(white var(--title-height), transparent 0);

  --avatar-size: 32px;
  --avatar-position: var(--card-padding) var(--card-padding);
  --avatar-skeleton: radial-gradient(
    circle calc(var(--avatar-size) / 2), 
    white 99%, 
    transparent 0
  );

  /* 
    如今咱們能夠把背景分解成單獨的形狀
  */
  background-image: 
    var(--avatar-skeleton),
    var(--title-skeleton),
    var(--card-skeleton);

  background-size:
    var(--avatar-size),
    var(--title-width) var(--title-height),
    100% 100%;

  background-position:
    var(--avatar-position),
    var(--title-position),
    0 0;
}

這不只可讀性更好,並且之後更改一些值也更容易。另外,咱們還可使用一些變量(好比頭像大小、卡片填充)來定義實際卡片的樣式,並始終使其與骨架版本保持同步。添加一個媒體查詢來調整不一樣斷點的骨架部分如今也很是簡單:bash

@media screen and (min-width: 47em) {
  :root {
    --card-padding: 32px;
    --card-height: 360px;
  }
}

ps:瀏覽器對自定義屬性的支持很好,但不是100%。基本上,全部現代瀏覽器都有支持,IE / Edge有點晚了。對於這個特定用例,使用Sass變量很容易添加回退。服務器

添加動畫

爲了使這更好,咱們能夠爲咱們的骨架設置動畫,並使其看起來更像是一個加載指示器。
咱們須要作的就是在頂層放置一個新的漸變,而後使用它來設置其位置的動畫 @keyframes
如下是成品骨架卡外觀的完整 骨架屏-demo


固然你可使用:empty選擇器和僞元素來繪製骨架,所以它只適用於空卡片元素,一旦注入了內容,框架屏幕就會自動消失
網絡

最後,感興趣的同窗可去我github下載這個骨架屏-demo源碼傳送門框架

相關文章
相關標籤/搜索