大家好,我是零一,今天給大家表演 僅用一個HTML標籤實現帶動畫的抖音LOGO,涉及了很多知識點,歡迎交流討論
先上結果,最終實現效果如下:
還原度應該還可以吧?
抖音Logo結構
想要用CSS來畫抖音的Logo,前提要先了解它的構造,一定是一些幾何圖形的拼接組合,因為之前很多業界大佬已經扒過抖音的Logo的結構了,我就拿來借用一下:
好的,有點複雜,簡化一下,其實就是 4
個部分
每個顏色劃出來的區域代表一個部分,所以最後是:1/4圓環
+ 半圓
+ 長條矩形
+ 半徑略大一些的1/4圓環
製作思路
回到本文標題,有人要說我標題黨了,這 logo
都劃分成四個部分了,你怎麼用一個標籤搞定呢?就算你用 ::before
和 ::after
,也加上標籤本體一共也就三個部分
而且!抖音的 logo
是有兩層的:
可以看到,是一個青色的音符和一個紅色的音符疊加的
所以! 這麼多元素,你怎麼用一個標籤完成呢?而且還說帶動畫,是不是逗我們玩呢?
好了,別急,我們們先捋一下思路哈:
先從元素的大方向開始思考:
- 需要實現一個黑色背景(需要一個標籤)
- 兩個音符疊加("黑色背景"已經是一個標籤了,那兩個音符只能是兩個偽元素)
再從元素的小細節著手突破:
- 需要在一個偽元素中一筆畫出整個音符圖案(容我思考一下...)
如何在一個偽元素中一筆畫出整個音符圖案呢?
? 想到辦法了,超級簡單,給大家演示一下
<style>
/* 為了保證文章整潔,省略一些程式碼... */
.douyin::before {
background: url('青色的音符.png')
}
.douyin::affter {
background: url('紅色的音符.png')
}
</style>
<div class="douyin"/>
好了,輕鬆搞定,本文結束!鼓掌?? 大家 點贊、收藏、轉發 走起~
別罵了,別罵了,剛剛跟大家開了個小玩笑,正文走起!
我們肯定是要用到 background
屬性的,不然哪來的色塊啊,去扒一下 MDN 文件:
都不用想了,只有一個 background-image
有用,那再具體看看:
劃重點了!同學們,background-image
支援為一個元素設定一個或多個影像,來看一下其支援哪些影像型別:
看了語法,發現基本上 <image>
型別支援的都是直接設定圖片的,唯獨有一個支援漸變函式的,例如:linear-gradient
、repeating-linear-gradient
、radial-gradient
、conic-gradient
...
如果你還不會看CSS的語法,可以看我之前寫的 熱議:CSS為什麼這麼難學?一定是你的方法不對,超詳細地講解了如何解讀CSS的語法(帶實戰的)
什麼是漸變函式呢?根據它們的單詞名字可以知道,支援了 線性、徑向(其實就是圓)、錐形 的顏色漸變。我們用前兩個就可以滿足抖音 logo
的構造了
因為根據 MDN 上的解釋,我們是可以使用多個漸變函式來控制元素的背景影像的,多個值用 ,
隔開,例如官方的例子:
background-image: linear-gradient(rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)),
url("../../media/examples/lizard.png");
用個比較形象的比喻,background-image
就像我們寫字一樣,寫字需要一筆一劃寫,而 background-image
中 ,
隔開的每一個值就像每一個筆畫,這些值共同組成了一個 "影像"
那我們就可以藉助這些函式來畫出抖音的logo了
開搞開搞
先來測量一下抖音 logo 中 音符 的長寬比,為了等會給音符留出一定的空間
特地用截圖工具圈出了紅色音符的部分,得到的寬高是 248 * 285
,計算一下寬高比就約等於 248/285 = 0.87
,那我們就要在中間留出一個寬高比為 0.87
的矩形位置給音符
打地基
那就先打地基!
<style>
.douyin {
width: 100px;
aspect-ratio: 0.87; /* 寬高比 0.87 */
border-radius: 25%;
padding: 20px calc(20px + 100px / 0.87 * 0.13 / 2); /* 四周留白,中間騰出位置給音符 */
background-color: #000;
}
</style>
<div class="douyin" />
這裡需要解釋一下 padding
的值的設定,20px
是我隨便設定的一個邊距大小,既然頂部和底部都是 20px
,而且本身整體元素的寬高比又不是 1:1
(整體不是正方形),那為了視覺上的居中和整體寬高的 1:1
,我們需要將左右邊距增大至整體寬度與高度相等
因此 100px / 0.87
拿到的就是整體的高度,再乘以 0.13
拿到的就是寬高的差值,因為要平均分到兩邊,所以還要除以 2
現在妥妥是個正方形了,當前的效果:
這裡為了讓等會的音符只在圖中的那塊兒區域繪製,我們給外部容器設定一下 display: grid
,等會還需要藉助 grid
佈局的能力
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
}
畫1/4圓環
如何畫圓環?用一個簡單的例子來演示一下:
<style>
.demo {
/* demo 是一個正方形 */
background:
radial-gradient(
100% 100% at 100% 100%,
transparent 0 50%,
red 50% 100%,
transparent,
);
}
</style>
<div class="demo"/>
我們就得到了一個這樣的圖形:
怎麼得到這樣的 1/4圓環
的呢?我們把樣式拆解一下:
100% 100% at 100% 100%
:
at 的左側 表示圓(或橢圓)在橫向、豎向的半徑長度;at 的右側 表示圓形在座標軸上的位置
那對應到這個圖上就是:
transparent 0 50%
radial-gradient()
函式除了第一個引數,其餘的引數都表示 顏色及漸變程度
因此 transparent 0 50%
表示從 圓心 開始到 半徑為一半長度的位置 顏色為 透明
這裡怕大家看不出來,我把 transparent
改成 blue
,放效果圖給大家看:
red 50% 100%
原理同上一個,從半徑為 50%
的位置一直到半徑為 100%
的部分,顯示紅色
效果圖為:
其實只有 黃色箭頭 所指出的這個區域是我們程式碼造成的,那為什麼一直到正方形的左上角都是紅色呢?因為radial-gradient()
函式需要最後設定一個 color-stop
,請看下面
transparent
這也是函式的最後一個引數,表示漸變以透明色 為結束,即從上一個位置(red 50% 100%
)的結束位置開始一直到容器的邊緣,都顯示為透明
現在再來看看效果:
這樣一個 1/4圓環
就畫好了
那麼回到我們的正文來
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
+ background:
+ radial-gradient(
+ 100% 100% at 100% 100%,
+ transparent 0 50%,
+ #08fff9 50% 100%,
+ transparent
+ );
}
現在我們們存放音符的容器是一個寬高比為 0.87
的長方形,如果按照我們剛剛畫矩形的程式碼來,最後出來的應該是這樣的:
很明顯,圓環的兩端寬度不一致,此時我們可以利用 background-size
對其進行壓縮,以此得到一個寬度一致的圓環,我擺爛了,懶得計算了,直接控制檯微調吧
這下差不多等寬了,且大概是一個標準的 1/4圓環
,然後我們們要把它放到左側中間靠下一點的位置,程式碼如下:
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
background:
radial-gradient(
100% 100% at 100% 100%,
transparent 0 50%,
#08fff9 50% 100%,
transparent
)
+ left 52%/41% 36% no-repeat;
}
有內味兒了,有沒有?
畫半圓
原理都相似,就放一個半圓的生成以及位移過程圖吧:
程式碼如下,也不過多解釋各種數值的意義了,因為我全是微調的:
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
background:
radial-gradient(
100% 100% at 100% 100%,
transparent 0 50%,
#08fff9 50% 100%,
transparent
) left 52%/41% 36% no-repeat,
+ radial-gradient(
+ 50% 100% at top,
+ transparent 44%,
+ #08fff9 45% 98%,
+ transparent
+ ) 0 100%/73% 31% no-repeat;
}
畫長條
長條可能跟圓環和半圓不太一樣,它用到的是 linear-gradient()
線性函式,我們也不搞花裡胡哨的操作,就直接把整個區域都鋪滿顏色,然後通過橫縱縮放得到一個長方形吧
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
background:
radial-gradient(
100% 100% at 100% 100%,
transparent 0 50%,
#08fff9 50% 100%,
transparent
) left 52%/41% 36% no-repeat,
radial-gradient(
50% 100% at top,
transparent 44%,
#08fff9 45% 98%,
transparent
) 0 100%/73% 31% no-repeat,
+ linear-gradient(#08fff9, #08fff9) 66% 0/20% 70% no-repeat;
}
效果過程動畫如下:
畫半徑稍大一些的1/4圓環
再次略過講解,直接看程式碼:
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
background:
radial-gradient(
100% 100% at 100% 100%,
transparent 0 50%,
#08fff9 50% 100%,
transparent
) left 52%/41% 36% no-repeat,
radial-gradient(
50% 100% at top,
transparent 44%,
#08fff9 45% 98%,
transparent
) 0 100%/73% 31% no-repeat,
linear-gradient(#08fff9, #08fff9) 66% 0/20% 70% no-repeat,
+ radial-gradient(
+ 100% 100% at 100% 0,
+ transparent 0 58%,
+ #08fff9 58.5% 99%,
+ transparent
+ ) 100% 0/47% 41.8% no-repeat;
}
效果圖如下:
到此為止,一個音符就畫好了,離成功只剩一步之遙
拆分
剛剛我們們的程式碼時把 ::before
和 ::after
放在一起寫的,其實現在是兩個一模一樣的音符完全重疊,而且現在兩個音符的顏色也是一樣的,我們來改造一下
顏色通過變數獲取
為了程式碼不冗餘,我們們把剛才程式碼中所有的 #08fff9
用變數來獲取,即 #08fff9 => var(--color)
.douyin::before,
.douyin::after {
content: '';
grid-area: 1/1; /* 居中展示 */
background:
radial-gradient(
100% 100% at 100% 100%,
transparent 0 50%,
var(--color) 50% 100%,
transparent
) left 52%/41% 36% no-repeat,
radial-gradient(
50% 100% at top,
transparent 44%,
var(--color) 45% 98%,
transparent
) 0 100%/73% 31% no-repeat,
linear-gradient(var(--color), var(--color)) 66% 0/20% 70% no-repeat,
radial-gradient(
100% 100% at 100% 0,
transparent 0 58%,
var(--color) 58.5% 99%,
transparent
) 100% 0/47% 41.8% no-repeat;
}
並單獨給 ::before
和 ::after
設定顏色變數
+ .douyin::before {
+ --color: #08fff9;
+ }
+ .douyin::after {
+ --color: #f00044;
+ }
除此之外,我們要移動其中一個音符,讓兩個音符不再重疊
.douyin::before {
--color: #08fff9;
}
.douyin::after {
--color: #f00044;
+ transform: translate(3%, 3%);
}
看看效果
好了,但兩個音符錯位了,但是顏色的混合效果好像還沒有,這時候要用到 mix-blend-mode
屬性了,MDN的定義就是使當前元素與其父元素的內容和背景以某種方式混合,支援的屬性有些多,本文就不跳出去講太多別的東西了,我直接在控制檯一個個試過去,發現 lighten
、plus-lighter
、screen
都是能達到我們的效果的,不過具體作用我還不是很瞭解,日後可以學習一下
請看嘗試過程?
最後我們就設定下 mix-blend-mode: lighten
吧
wow! 我們的 Logo 製作好啦!
加個動畫
抖音怎麼不能不抖?
我們現在設定的是紅色的音符向右向上偏移 3%
,那我們現在就要這兩個音符都抖起來,其實就是修改它們各自的偏移量。又要改造一下程式碼了!
.douyin::before {
--color: #08fff9;
transform: translate(calc(var(--x, 0%) - 3%), calc(var(--x, 0%) - 3%));
}
.douyin::after {
--color: #f00044;
transform: translate(calc(3% - var(--x, 0%)), calc(3% - var(--x, 0%)));
}
/* hover時,設定偏移變數 --x */
.douyin:hover::before,
.douyin:hover::after {
--x: 0.1%;
transition: transform cubic-bezier(.5,300,.5,-150) .3s;
}
請看效果:
本來還想把我寫過的一個 文字故障風 的效果加到這個 Logo
裡的,一定很酷,但是有些無能為力,因為要給音符設定故障風效果,是要用到偽元素的,而現在音符本身已經是偽元素了,我不能脫離了我本文的標題 "僅用一個html標籤,實現帶動畫的抖音Logo" ,如果你感興趣,可以下去自己加上,到時候記得艾特我,我也想看看效果
想不到什麼花裡胡哨的動畫了,最後再給大家表演一下 抖音Logo 的 "異變" 吧
準備好了嗎?
1~
2~
3~
哇!不得不說,太好看了!哈哈哈哈,其實實現原理也不難,我只是給元素加了個 filter: invert(1);
的屬性
最後
怎麼樣,我是不是沒有標題黨?確實是 僅用一個HTML標籤,實現了一個帶動畫的抖音Logo 吧?
最後希望本文對大家有所幫助,零一能力有限,如果本文有任何錯誤,歡迎評論區指出;如果你有更多的奇思妙想,也歡迎評論區跟我一起探討~
也貼心得給大家準備了完完整整的示例程式碼,需要的小夥伴可以自行檢視
完整程式碼:https://github.com/zero2one3/...
我是零一,分享技術,不止前端!下期見~