僅用一個HTML標籤,實現帶動畫的抖音LOGO

零一發表於2022-04-25

大家好,我是零一,今天給大家表演 僅用一個HTML標籤實現帶動畫的抖音LOGO,涉及了很多知識點,歡迎交流討論

先上結果,最終實現效果如下:

成品圖

還原度應該還可以吧?

抖音Logo結構

想要用CSS來畫抖音的Logo,前提要先了解它的構造,一定是一些幾何圖形的拼接組合,因為之前很多業界大佬已經扒過抖音的Logo的結構了,我就拿來借用一下:

圖片來源於網路

好的,有點複雜,簡化一下,其實就是 4 個部分

每個顏色劃出來的區域代表一個部分,所以最後是:1/4圓環 + 半圓 + 長條矩形 + 半徑略大一些的1/4圓環

製作思路

回到本文標題,有人要說我標題黨了,這 logo 都劃分成四個部分了,你怎麼用一個標籤搞定呢?就算你用 ::before::after,也加上標籤本體一共也就三個部分

而且!抖音的 logo 是有兩層的:

抖音logo

可以看到,是一個青色的音符和一個紅色的音符疊加的

所以! 這麼多元素,你怎麼用一個標籤完成呢?而且還說帶動畫,是不是逗我們玩呢?

好了,別急,我們們先捋一下思路哈:

  • 先從元素的大方向開始思考:

    • 需要實現一個黑色背景(需要一個標籤)
    • 兩個音符疊加("黑色背景"已經是一個標籤了,那兩個音符只能是兩個偽元素)
  • 再從元素的小細節著手突破:

    • 需要在一個偽元素中一筆畫出整個音符圖案(容我思考一下...)

如何在一個偽元素中一筆畫出整個音符圖案呢?

? 想到辦法了,超級簡單,給大家演示一下

<style>
  /* 為了保證文章整潔,省略一些程式碼... */
  .douyin::before {
    background: url('青色的音符.png')
  }
  
  .douyin::affter {
    background: url('紅色的音符.png')
  }
</style>

<div class="douyin"/>

好了,輕鬆搞定,本文結束!鼓掌?? 大家 點贊、收藏、轉發 走起~

別罵了,別罵了,剛剛跟大家開了個小玩笑,正文走起!

我們肯定是要用到 background 屬性的,不然哪來的色塊啊,去扒一下 MDN 文件:

都不用想了,只有一個 background-image 有用,那再具體看看:

劃重點了!同學們,background-image 支援為一個元素設定一個或多個影像,來看一下其支援哪些影像型別:

看了語法,發現基本上 <image> 型別支援的都是直接設定圖片的,唯獨有一個支援漸變函式的,例如:linear-gradientrepeating-linear-gradientradial-gradientconic-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的定義就是使當前元素與其父元素的內容和背景以某種方式混合,支援的屬性有些多,本文就不跳出去講太多別的東西了,我直接在控制檯一個個試過去,發現 lightenplus-lighterscreen 都是能達到我們的效果的,不過具體作用我還不是很瞭解,日後可以學習一下

請看嘗試過程?

最後我們就設定下 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~

異變的抖音Logo

哇!不得不說,太好看了!哈哈哈哈,其實實現原理也不難,我只是給元素加了個 filter: invert(1); 的屬性

最後

怎麼樣,我是不是沒有標題黨?確實是 僅用一個HTML標籤,實現了一個帶動畫的抖音Logo 吧?

最後希望本文對大家有所幫助,零一能力有限,如果本文有任何錯誤,歡迎評論區指出;如果你有更多的奇思妙想,也歡迎評論區跟我一起探討~

也貼心得給大家準備了完完整整的示例程式碼,需要的小夥伴可以自行檢視

完整程式碼https://github.com/zero2one3/...

我是零一,分享技術,不止前端!下期見~

相關文章