準備工作
原本想著是不是寫“用一個 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...