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

大家好,我是零一,今天給大家表演 僅用一個 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 的 "異變" 吧

準備好了嗎?

3~

2~

1~

異變的抖音 Logo

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

最後

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

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

也貼心得給大家準備了完完整整的示例代碼,需要的小夥伴可以自行查看

完整代碼:https://github.com/zero2one3/code-example/tree/master/css/write_tiktok_logo_with_one_html_tag.html

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ucm0f9D1an9uVFqedhVEsQ