用 CSS 實現 AirDrop 動效

語言: CN / TW / HK

我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第8篇文章,點選檢視活動詳情

AirDrop 效果介紹

用過 Mac 電腦的同學都知道 AirDrop 可以在不同電腦和手機裝置之間共享檔案,功能非常強大,如下圖所示:

我們今天來研究一下 AirDrop 視覺效果,帶領大家一步步在網頁中實現它。整個背景是一圈圈的圓形軌道,類似於行星圍繞著太陽旋轉,當發現新裝置後,就會在軌道上展示該裝置,並附加波紋擴散動效:

AirDrop 效果的本質

如果把上面的圖中的文案和圖片全部去掉之後,你會發現剩下的全都是同心圓,所以要做 AirDrop 效果,只要能做到以下三點即可:

  • 實現同心圓
  • 實現切角同心圓
  • 實現同心圓擴散效果

從零寫一個AirDrop效果

實現同心圓

最簡單的實現思路就是:有多少個圓我就寫多少個 div,然後把它們給疊加起來。這種方式也沒毛病,假設有 4 個同心圓,最裡面的圓形半徑是 100px,我們直接看程式碼,其中 HTML 結構很簡單:

```html

```

CSS 程式碼如下:

```css .circle-center { --radius: 100px; --diameter: calc(2 * var(--radius)); position: fixed; bottom: calc(20px + var(--radius)); left: 50%; width: 0; height: 0; }

.circle { position: absolute; top: 0; left: 0; transform: translateX(-50%) translateY(-50%); border: 1px solid #ddd; border-radius: 50%; box-sizing: border-box; }

.circle:nth-child(1) { width: var(--diameter); height: var(--diameter); }

.circle:nth-child(2) { width: calc(2 * var(--diameter)); height: calc(2 *var(--diameter)); }

.circle:nth-child(3) { width: calc(3var(--diameter)); height: calc(3var(--diameter)); }

.circle:nth-child(4) { width: calc(4var(--diameter)); height: calc(4var(--diameter)); } ```

這裡用到了 CSS 變數,可以非常方便的修改半徑來調整同心圓間距。我們看下效果:

是不是有那麼一點感覺了?

實現切角同心圓

在 airdrop 的中心有一個缺角的紅藍相間的同心圓,然後把底部大約30度的扇形區塊給切掉即可。接下來我們就來實現它。

有了第一步的基礎,畫一個紅藍相間的同心圓已經非常簡單了,只需要去掉 border,新增 background-color 即可,大家可以自己嘗試一下。

但是這裡介紹另外一種利用 box-shadow 畫同心圓的辦法,只需要一個 div 即可。我們在 circle-center 裡面增加 circle-ring 和 circle-text 兩個節點分別用於建立切角同心圓和下面的文字:

```html

”隔空投送“可讓您與附近的使用者立即共享
允許這些人發現我:所有人

```

CSS 程式碼如下:

css .circle-ring { --ring-width: 90px; --border-width: 6px; --gutter-width: 7px; --color: #286ad3; position: absolute; width: var(--ring-width); height: var(--ring-width); top: calc(var(--ring-width) / -2); left: calc(var(--ring-width) / -2); box-sizing: border-box; border-radius: 50%; background: var(--color); box-shadow: inset 0 0 0 var(--border-width) var(--color), inset 0 0 0 calc(var(--border-width) + var(--gutter-width)) white, inset 0 0 0 calc(2 * var(--border-width) + var(--gutter-width)) var(--color), inset 0 0 0 calc(2 * var(--border-width) + 2 * var(--gutter-width)) white, inset 0 0 0 calc(3 * var(--border-width) + 2 * var(--gutter-width)) var(--color), inset 0 0 0 calc(3 * var(--border-width) + 3 * var(--gutter-width)) white; }

這裡定義了一個半徑為 100px 的圓,然後利用 box-shadow 新增藍白相間的多個內陰影,其中 --border-width表示藍色邊框的寬度,--gutter-width表示白色間距的寬度,做成 CSS 變數也是方便調整,看下效果吧:

接下來我們得把底部做一個豁口才行,也有兩種實現思路:

  • 利用 clip-path 切割圖形
  • 用一個 div 畫一個白色的扇形遮擋圓形底部

這裡選擇更為強大的 clip-path 來實現,只需要一行程式碼即可:

css clip-path: polygon(45% 60%, 20% 100%, 0% 100%, 0 0, 100% 0, 100% 100%, 80% 100%, 55% 60%);

裁剪後的效果如下:

clip-path 的語法不做詳細介紹,感興趣的讀者可以自行 Google 查詢,它可以裁剪矩形、圓形、橢圓、多邊形甚至指定的路徑:

css .div { clip-path: inset(100px 50px); clip-path: circle(50px at 0 100px); clip-path: ellipse(50px 60px at 0 10% 20%); clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%); clip-path: path('M15,45 A30,30,0,0,1,75,45 A30,30,0,0,1,135,45 Q135,90,75,130 Q15,90,15,45 Z'); clip-path: url(#myPath); }

最常用的使用場景就是裁剪圖片,大家可以前往 css-tricks 網站體驗,裡面提供了一個非常好用的 demo,可以非常直觀的看到 clip-path 屬性的效果:

最後稍作調整,補上文字的樣式:

css .circle-text { position: absolute; top: 70px; left: 0; width: 400px; transform: translateX(-50%); text-align: center; font-size: 13px; }

最終實現的頁面已經跟 Mac 自帶的非常接近了:

實現同心圓擴散效果

當 airdrop 發現裝置的時候,會把裝置放在同心圓的軌道上,也顯示成一個圓形,而且呈現雷達擴散效果,這個應該怎麼實現呢?

首先我們完善一下 HTML 結構,增加 wave 波動容器:

```html

”隔空投送“可讓您與附近的使用者立即共享
允許這些人發現我:所有人
iPhone14

```

其中:

  • wave 是裝置容器
  • wave-avatar 用於放置中間的頭像
  • wave-animation 用於實現波動效果

--wave-size變數來表示裝置容器的寬度,同樣也是參照 circle-center 進行絕對定位,wave 容器的 CSS 程式碼如下:

css .wave { --wave-size: 90px; position: absolute; top: -300px; width: var(--wave-size); height: var(--wave-size); position: relative; text-align: center; overflow: visible; transform: translate(calc(var(--wave-size) / -2), calc(var(--wave-size) / -2)); }

wave-avatar 就非常簡單了,依然採用絕對定位放置頭像:

css .wave-avatar { border-radius: 50%; position: absolute; width: var(--wave-size); height: var(--wave-size); top: 0; left: 0; z-index: 2; display: block; background-image: url(avatar.svg); background-size: cover; }

最難實現的是 wave-animation 向外擴散的效果,我們先把容器準備好,初始狀態是 4 個重疊在一起的 div,預設是沒有動效的,當給 wave 增加 active 屬性之後再讓它動起來:

```css .wave-animation { position: absolute; width: var(--wave-size); height: var(--wave-size); top: 0; left: 0; display: none; }

.wave-animation div { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }

.wave.active .wave-animation { display: block; } ```

最關鍵的一步來了,我們嵌套了 4 個重疊的圓,其中1個是白色背景,剩下3個是灰色背景,並且加了 circleChange 擴散動效,先貼程式碼:

```css .wave-circle, .wave-circle1, .wave-circle2, .wave-circle3 { border-radius: 50%; }

.wave-circle { background-color: white; z-index: 1; }

.wave-circle1, .wave-circle2, .wave-circle3 { background-color: #efefef; animation-name: circleChange; animation-duration: 3s; animation-iteration-count: infinite; animation-timing-function: linear; }

.wave-circle1 { animation-delay: 0s; }

.wave-circle2 { animation-delay: 1s; }

.wave-circle3 { animation-delay: 2s; }

@keyframes circleChange { 0% { transform: scale(1); opacity: 0.95; }

25% { transform: scale(1.4); opacity: 0.75; }

50% { transform: scale(1.8); opacity: 0.5; }

75% { transform: scale(2.2); opacity: 0.25; }

100% { transform: scale(2.6); opacity: 0.05; } } ```

從單個圓的角度來看,是利用 scale 和 opacity 來做一個跟隨時間放大且漸變的效果,如下圖所示:

但是有 3 個圓同時播放這個動畫,並且依次延遲 0 秒、1 秒和 2 秒,最終就形成了向外漸變擴散的效果。最後再補上文案樣式:

css .wave-text { position: absolute; bottom: -30px; width: 100%; }

我們最終的效果就出來啦:

動圖效果如下:

怎麼樣,有沒有一種絲滑的感覺?到此為止,我們的網頁版 AirDrop 就完成啦,歡迎大家點贊、評論、分享!