使用 CSS 繪製帶有動畫效果的 React Logo

林小志發表於2022-04-27

準備工作

原本想著是不是寫“用一個 div 繪製 React Logo”,最後想想,就算用一個 div 實現了,那麼對於後面可能要新增的效果就會有很大的侷限性,於是就放棄了這樣的標題。至於 HTML 結構中,div 的使用也不是很多,就下面這樣的結構而已。

<div class="react">
    <div class="logo"></div>
</div>

先看一下簡單的,參考 react 官網上的 Logo 展示效果。

整個實現的過程也很簡單,畢竟這個不是複雜的圖形,同時在繪製的過程中也並沒有完全 100% 一模一樣去克隆,只不過是在形體上看著相似而已。比如以下幾點就是比較隨性去處理的:

  • 橢圓部分的旋轉角度;
  • 中心圓點大小;
  • 各個橢圓的大小;

開始繪製

React 的 Logo 中那三個橢圓部分大小假設是相同的,那麼就只要繪製了橫向的橢圓之後,再通過 ::before::after 去旋轉,改變一下角度就好了。

構思好關鍵的部分,那麼就開始著手寫 CSS 程式碼吧。

.react {
    position: relative;
    width: 250px;
    height: 250px;
    color: rgb(1, 216, 255);
}

通過取色器獲取 React Logo 圖片上的顏色值,然後限定一個寬高給外圍。✏️這裡需要注意一點,把顏色值寫入到 color 中的主要目的。

?在 CSS 中有一個 currentColor 屬性值,是可以直接獲取到當前所繼承的顏色值,而 color 是可繼承的,並且個別屬性如果沒有寫顏色值的話,是直接繼承 color 的值。所以,當我們在父級元素上寫了 color 值,後面很多地方的顏色值就可以省略了。

接著繪製橢圓部分。

.logo,
.logo::after,
.logo::before {
    position: absolute;
    top: 50%;
    left: 0;
    width: 250px;
    height: 100px;
    border: 10px solid;
    border-radius: 50%;
    box-sizing: border-box;
    transform: translateY(-50%);
    z-index: 1;
}

注意:這裡的高度是目測猜想的高度值,寬度是為了撐滿容器,不用 100% 作為寬度值,因為這裡還有 ::after::before 這兩個偽元素。如果用了 100% 的話,這兩個偽元素寬度就要比橫向的要小一些了,因為偽元素是 .logo 的子元素。

因為使用了 absolute 定位,所以,這個時候可以在頁面上看到“一個”橢圓。現在要對偽元素進行旋轉的操作了。

.logo::after,
.logo::before {
    content: '';
    left: -12px;
    transform: rotate(58deg) translate3d(-50px, -25px, 0);
}
.logo::after {
    transform: rotate(-58deg) translate3d(50px, -25px, 0);
}

就可以得到這樣的一個圖形了。

這裡需要注意的是,當我們旋轉的時候,雖然中心圓點是 center center,但旋轉後會有位置的偏移,因此需要再對 X 軸和 Y 軸做偏移調整 translate3d(50px, -25px, 0)。這裡的偏移以及旋轉的角度都是目測而已。

完成繪製

有了基本的輪廓,剩下還有中心那個圓點。這個就簡單了,直接用 .react 的偽元素畫一個圓,然後定位到中間就好了。

.react::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 42px;
    height: 42px;
    background-color: currentcolor;
    border-radius: 50%;
    transform: translate3d(-50%, -50%, 0);
    z-index: 2;
}

然後就可以得到這個最終的 Logo 圖形了。

在這個圓形的時候,可以看到使用了 background-color: currentcolor;,而在畫橢圓使用邊框時則是 border: 10px solid;。因為 background-color 不會繼承 color 的顏色值,而 border-color 在未定義的時候,是使用 color 顏色值的。

改變一下

基礎款的 React Logo 用 CSS 繪製好了,接著改變一下,把 border 換成 box-shadow,通過陰影來實現一個線條不均勻的 Logo。

醜不醜呢,好像是挺醜的,但感覺是不一樣了?……

實現的方式也簡單,就是把邊框 border 啥的都去掉,直接用 box-shadow 就好了。

.logo,
.logo::after,
.logo::before {
    position: absolute;
    top: 50%;
    left: 0;
    width: 250px;
    height: 100px;
    /* border: 10px solid; */
    border-radius: 50%;
    /* box-sizing: border-box; */
    transform: translateY(-50%);
    box-shadow: 10px -2px 2px 7px;
    z-index: 1;
}
.logo::after,
.logo::before {
    content: '';
    /* left: -12px; */
    transform: rotate(58deg) translate3d(-50px, -25px, 0);
    box-shadow: 7px -4px 2px 6px;
}
.logo::after {
    transform: rotate(-58deg) translate3d(50px, -25px, 0);
    box-shadow: -4px -8px 2px 8px;
}

去掉 left: -12px; 是因為邊框沒了,盒模型的寬度就變化了。

這裡需要注意,box-shadow 中並沒有加上顏色值,原因在上面介紹過,同理。

動起來

要想動起來,那就是加上一個 animation 動畫就好了,效果大概就是這樣了。

看著好像是弧形的效果在動,其實只是改變了陰影了位置而已。在動畫的過程中,順便把陰影的值也修改了一下。

@keyframes runLogoPseudo {
    0%, 100% {
        box-shadow: 10px -4px 2px 1px;
    }
    25% {
        box-shadow: 10px 4px 2px 1px;
    }
    50% {
        box-shadow: -10px 4px 2px 1px;
    }
    75% {
        box-shadow: -10px -4px 2px 1px;
    }
}
@keyframes runLogo {
    0%, 100% {
        box-shadow: 7px -2px 5px;
    }
    25% {
        box-shadow: 7px 2px 5px;
    }
    50% {
        box-shadow: -7px 2px 5px;
    }
    75% {
        box-shadow: -7px -2px 5px;
    }
}

現在能看到的效果,中間的圓形是不會有任何變化的,所以,稍微再加一點動畫幀。

@keyframes blink {
    0%, 100% {
        transform: scale(1) translate3d(-50%, -50%, 0);
        box-shadow: 0 0 15px;
        opacity: 1;
    }
    60% {
        transform: scale(1.05) translate3d(-50%, -50%, 0);
        box-shadow: none;
        opacity: .8;
    }
}

這樣,小圓圈也就有一個類似“呼吸”的感覺了,應該有的吧。無所謂了,反正是有動畫效果了。

最後關鍵的部分來了,就是要讓動畫動起來。

.react::after {
    animation: blink 1.5s 0s infinite ease-in-out;
}

靠感覺把閃動的效果加在小圓點上。

.logo,
.logo::after,
.logo::before {
    /* box-shadow: 10px -2px 2px 7px; */
    animation: runLogo 1s 0s infinite linear;
}
.logo::after,
.logo::before {
    /* box-shadow: 10px -4px 2px 1px; */
    animation-name: runLogoPseudo;
}
.logo::after {
    /* box-shadow: -4px -8px 2px 8px; */
    animation-direction: alternate;
}
  • 首先通過 animation: runLogo 1s 0s infinite linear; 讓三個橢圓都有相同的動畫效果;
  • 接著改變偽元素中的動畫幀名稱 animation-name: runLogoPseudo;,去選擇對應的動畫效果;
  • 最後改變其中一個偽元素的動畫方向,讓兩個傾斜的橢圓運動方向是相反的 animation-direction: alternate;,形成不同的視差感覺;
  • 最後的最後,既然這個動畫是 infinite 無限運動,那麼就去掉 box-shadow 的值吧,在 @keyframes 中有對應的 box-shadow 屬性了;

還有嗎?

我這邊現在是沒有了,如果有興趣的話,可以考慮結合漸變色實現邊框,然後滾動起來,也可以結合 mix-blend-mode 混合模式玩一些好玩的。這些就是看具體的創意想法了……

效果預覽

https://codepen.io/linxz/pen/...

首發於個人公眾號「志語自樂」,https://mp.weixin.qq.com/s/83...

相關文章