【譯】如何只用CSS製作一個漂亮的載入動畫

原文:How to create a beautiful animated loader with nothing but CSS

作者:Julien Benchetrit

譯者:百度外賣FE - 艾文

這是一篇用來展現偽元素和keyframe動畫有多麼吊炸天的創造力的文章,在這個例子中我們只用CSS來製作一個載入動畫,不含任何JS代碼或者圖片。

為什麼要做這個東西?

我的網站首頁需要載入一段視頻和一些圖片,我不希望當用戶進到頁面以後很快的滾動到下方的時候看到這些東西還沒載入出來,這樣的體驗很糟糕,我希望在這些東西載入出來之前他們能看到一段載入動畫,直到內容載入完成後才能操作。

這就是為什麼我決定做一個能夠儘可能迅速地顯示出來的載入動畫,為了實現這個目的,我決定不用任何額外的圖片或者JS代碼去實現它,只用HTML和嵌入的CSS。

首先要說的是,這類東西的代碼會根據不同的動畫或者樣式設計有不同的實現方法,我會用我的例子來展示一些思路或者通用的部分。

另外這篇文章假定讀者已經熟悉了偽元素、CSS動畫屬性、keyframe動畫等概念,關於這些內容不再贅述。如果你想閱讀更多關於偽元素的內容,戳這裡有你想知道的一切。如果你想了解更多關於CSS動畫屬性和keyframe動畫的知識,戳這裡。

好,正文開始

戳這裡去我的網站可以看到載入動畫,如你所見,這個動畫大體分為四個步驟:

1、邊框一個接一個出現

2、紅色,橙色,白色的矩形滑入

3、矩形們滑出

4、邊框消失

實際上,我們只需要做第一步和第二步的動畫,然後設置一個動畫屬性animation-direction: alternate,這會讓CSS動畫一遍正向一遍逆向的交替播放,這樣第三步和第四步的動畫也就有了。當然我們還要加上animation-iteration-count: infinite這個屬性,來保證動畫會永遠重複下去。

大體的思路就是這樣,下面我們從一個基本的HTML結構開始:

<!doctype html>n<html>n <head>n <!-- <link rel="preload"> for CSS, JS, and font files -->n <style type="text/css">n /*n * All the CSS for the loadern * Minified and vendor prefixedn */n </style>n </head>n <body>n <div class="loader">n <!-- HTML for the loader -->n </div>n <header />n <main />n <footer />n <!-- Tags for CSS and JS files -->n </body>n</html>n

接下來我不會直接就奔向最終目標,我們的第一步是製作一個不包含有動畫的載入logo,也就是這個,首先是它的HTML,代碼如下:

<div class="logo">n <div class="white"></div>n <div class="orange"></div>n <div class="red"></div>n</div>n

div.logo是最外層的正方形,內部每個矩形用div.顏色的形式表示。每個div都是absolute布局,根據他們所在的位置設置topbottomleftright屬性,並設置他們的寬度,代碼如下:

div.logo {n width: 100px;n height: 100px;n border: 4px solid black;n box-sizing: border-box;n position: relative;n background-color: white;n}ndiv.logo > div {n position: absolute;n}ndiv.logo div.white {n border-left: 4px solid black;n top: 0;n bottom: 0;n right: 0;n width: 23%;n}ndiv.logo div.orange {n border-top: 4px solid black;n left: 0;n bottom: 0;n right: 0;n height: 50%;n background-color: #F3B93F;n}ndiv.logo div.red {n border-right: 4px solid black;n top: 0;n bottom: 0;n left: 0;n width: 27%;n background-color: #EA5664;n}n

好的,接下來開始會有一些有趣的部分,因為CSS不允許我們直接給div.logo的邊框加動畫。所以我們不能直接用div.logo的邊框,而要想點別的方法加上這東西,只有這樣才能達到我們的目的。

也許我們可以把邊框變成多個部分後,再分別按順序顯示?我們可以使用兩個透明的偽元素覆蓋在正方形的上面來實現這個效果,每個偽元素的邊框覆蓋正方形四條邊框中的兩條,然後我們做一個動畫將偽元素的寬和高從0%改到100%,這樣分別讓每條邊框動態的顯示出來。

好的,讓我們先創建一個靜態、沒有動畫的版本。

我們用div.logo::before用absolute定位在左上角來代表div.logo的上邊框和右邊框,而div.logo::after定位在右下角來顯示左邊框和下邊框。

代碼如下:

div.logo::before, div.logo::after {n z-index: 1;n box-sizing: border-box;n content: ;n position: absolute;n border: 4px solid transparent;n width: 100%;n height: 100%;n}ndiv.logo::before {n top: 0;n left: 0;n border-top-color: black;n border-right-color: black;n}ndiv.logo::after {n bottom: 0;n right: 0;n border-bottom-color: black;n border-left-color: black;n}n

下一步我們給div.logo::before加上keyframe動畫。

這個keyframe的第一個狀態的width和height都是0,之後用動畫先將width加到100%,然後再將height加到100%。這裡我讓邊框的顏色在正確的時機從透明切換到黑色,這會讓上邊框和右邊框的動畫完全按著我們的希望展示出來。

之後我們給div.logo::after加上類似的動畫,當然不要忘了加上animation-direction: alternate用來做反向動畫,這樣我們就有了完整的邊框動畫。

動畫代碼如下:

div.logo::before, div.logo::after {n z-index: 1;n box-sizing: border-box;n content: ;n position: absolute;n border: 4px solid transparent;n width: 0;n height: 0;n animation-timing-function: linear;n}ndiv.logo::before {n top: 0;n left: 0;n animation: border-before 1.5s infinite;n animation-direction: alternate;n}ndiv.logo::after {n bottom: 0;n right: 0;n animation: border-after 1.5s infinite;n animation-direction: alternate;n}n@keyframes border-before {n 0% {n width: 0;n height: 0;n border-top-color: black;n border-right-color: transparent;n }n 24.99% {n border-right-color: transparent;n }n 25% {n height: 0;n width: 100%;n border-top-color: black;n border-right-color: black;n }n 50%,n 100% {n width: 100%;n height: 100%;n border-top-color: black;n border-right-color: black;n }n}n@keyframes border-after {n 0%,n 49.99% {n width: 0;n height: 0;n border-left-color: transparent;n border-bottom-color: transparent;n }n 50% {n width: 0;n height: 0;n border-left-color: transparent;n border-bottom-color: black;n }n 74.99% {n border-left-color: transparent;n border-bottom-color: black;n }n 75% {n height: 0;n width: 100%;n border-left-color: black;n border-bottom-color: black;n }n 100% {n width: 100%;n height: 100%;n border-left-color: black;n border-bottom-color: black;n }n}n

最後我們給內部的矩形加上動畫。

這塊主要的挑戰在於我們不能直接串起來幀動畫,我們需要在安排每段動畫的時候考慮到其他的動畫步驟,這樣整個動畫才能順序顯示,並且可以逆序顯示。

對於邊框的動畫來講,我們只是簡單給每個邊框25%的時間。我們需要在這期間加上矩形,在一系列的試錯之後,我決定讓動畫總的時長是1.5秒,然後分別在下面這些時間段做這些動作:

1、0% to 25%:上邊框和右邊框出現

2、25% to 50%:下邊框和左邊框出現

3、50% to 65%:紅色矩形出現

4、65% to 80%:橙色矩形出現

5、75% to 90%:白色矩形出現

根據上面這個時間線,我們做出來最終的成品,所有的CSS代碼如下:

html, body {n height: 100%;n width: 100%;n overflow: hidden;n margin: 0;n}ndiv.loader {n position: fixed;n top: 0;n left: 0;n right: 0;n bottom: 0;n background-color: #fff;n display: flex;n flex-direction: column;n justify-content: center;n align-items: center;n z-index: 100;n}ndiv.logo {n width: 100px;n height: 100px;n box-sizing: border-box;n position: relative;n background-color: white;n}ndiv.logo::before, div.logo::after {n z-index: 1;n box-sizing: border-box;n content: ;n position: absolute;n border: 4px solid transparent;n width: 0;n height: 0;n animation-direction: alternate;n animation-timing-function: linear;n}ndiv.logo::before {n top: 0;n left: 0;n animation: border-before 1.5s infinite;n animation-direction: alternate;n}ndiv.logo::after {n bottom: 0;n right: 0;n animation: border-after 1.5s infinite;n animation-direction: alternate;n}ndiv.logo > div {n position: absolute;n opacity: 0;n}ndiv.logo div.white {n border-left: 4px solid black;n top: 0;n bottom: 0;n right: 0;n width: 0;n animation: white 1.5s infinite;n animation-direction: alternate;n}ndiv.logo div.orange {n border-top: 4px solid black;n left: 0;n bottom: 0;n right: 0;n height: 0;n background-color: #F3B93F;n animation: orange 1.5s infinite;n animation-direction: alternate;n}ndiv.logo div.red {n border-right: 4px solid black;n top: 0;n bottom: 0;n left: 0;n width: 0;n background-color: #EA5664;n animation: red 1.5s infinite;n animation-direction: alternate;n}n@keyframes border-before {n 0% {n width: 0;n height: 0;n border-top-color: black;n border-right-color: transparent;n }n 12.49% {n border-right-color: transparent;n }n 12.5% {n height: 0;n width: 100%;n border-top-color: black;n border-right-color: black;n }n 25%,n 100% {n width: 100%;n height: 100%;n border-top-color: black;n border-right-color: black;n }n}n@keyframes border-after {n 0%,n 24.99% {n width: 0;n height: 0;n border-left-color: transparent;n border-bottom-color: transparent;n }n 25% {n width: 0;n height: 0;n border-left-color: transparent;n border-bottom-color: black;n }n 37.49% {n border-left-color: transparent;n border-bottom-color: black;n }n 37.5% {n height: 0;n width: 100%;n border-left-color: black;n border-bottom-color: black;n }n 50%,n 100% {n width: 100%;n height: 100%;n border-left-color: black;n border-bottom-color: black;n }n}n@keyframes red {n 0%,n 50% {n width: 0;n opacity: 0;n }n 50.01% {n opacity: 1;n }n 65%,n 100% {n opacity: 1;n width: 27%;n }n}n@keyframes orange {n 0%,n 65% {n height: 0;n opacity: 0;n }n 65.01% {n opacity: 1;n }n 80%,n 100% {n opacity: 1;n height: 50%;n }n}n@keyframes white {n 0%,n 75% {n width: 0;n opacity: 0;n }n 75.01% {n opacity: 1;n }n 90%,n 100% {n opacity: 1;n width: 23%;n }n}n

這樣整個動畫就完成了。


推薦閱讀:

APP圖標設計小技巧:在iOS上快速獲得APP圖標的真實預覽圖
探究Babel生態
重新設計 React 組件庫

TAG:HTMLCSS | 前端开发 | 网页设计 |