手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

青灯夜游
發布: 2022-02-18 09:03:58
轉載
2291 人瀏覽過

這篇文章手把手教大家,一步步使用純CSS繪製一個中國結,並為這個中國結添加紅包雨動畫效果,希望對大家有所幫助!

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

春節是中國人最重要的節日,春節期間的習俗也非常多,東西南北各不相同。 為了增添年味,過年時家家戶戶會置辦各種年貨和裝飾品,把家裡營造得紅紅火火,紅燈籠,紅對聯,紅福字,以及紅色的中國結。

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

中國結原料是簡簡單單的紅繩,經過古人的巧妙構思,編織成一個菱形網格的樣子。網格上的繩線緊緊連結在一起,象徵一家人團結和睦,幸福美滿。

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

那麼如何用CSS來實作一個中國結呢?先看最終效果。

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

線上預覽Codepen位址:
https://codepen.io/cliea/pen/LYOPbBr

如此Amazing 的效果,你也可以做出來,以下讓我們開始吧!

一、編碼之前

1. 蒐集素材,越簡潔越好

先從網上搜一張中國結的圖片,中國結的樣式不止一種,我們選擇一種最經典的中國結的編織樣式。 圖片的品質決定了最後成品的質量,以下就是一張比較整潔,結構清晰的中國結圖。供我們寫CSS時參考使用。

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

2. 觀察細節,構思實現的可能性

#有了圖片就可以開始寫程式碼了嗎?當然不是。

首先回想現在要做的事:用CSS畫個中國結。

你真的想好了嗎?這是一個可以實現的目標嗎?想像一下,當你的領導給你一個任務:讓手機殼依照APP的主題色而變色。你會直接開始寫程式碼嗎?

你會想兩個問題:

  • APP作為一個軟體,是否有和手機殼互動的介面

  • 手機殼如果接收到色值,如何變色

這是比較極端的例子,上面兩個都無法實現。回到CSS和這張中國結的圖片。我們首先要想的是,我們應該用哪些CSS技術,來實現這個圖片。你現在回過頭仔細觀察上面的圖。

經過短暫的觀察,我們發現這樣一些要點

  • 中國結的繩子是由漸變色組成,深紅,淺紅,深紅

  • 中間的主體部分由22根相互交叉的繩子組合而成,而且每過一個交叉點就會交換一下層級順序

  • 有一些環狀結構,色漸變的過程與直線相同

  • #整體都是紅色,以黃色點綴

然後就是預想一下實作原理

  • #直線的色彩漸變,使用linear-gradientrepeating-linear-gradient

  • 環狀漸變,使用radial-gradient

  • #網格的交叉,使用mask遮罩來達到交叉效果

  • #四分之三環以及底部兩根彎曲的繩子使用clip-path來裁切

  • 為了讓編碼更方便,採用SCSS

  • 許多地方可以使用::before::after實現,減少html程式碼

3.結構拆分,化整為零

上面是從技術角度從整體觀察,下面就是對整個圖片進行拆分,先確定其html結構。

  • 中間像棋盤一樣的網格結構,可以作為一個html標籤

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

  • 四周16個小半圓,使用16個標籤定位實現

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

  • #兩個四分之三圓,放在一組裡,使用相同的樣式,第二個基於第一個旋轉180deg

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

#
  • 兩個十字結,樣式一樣,所以也放在一組裡

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

  • 頂部三個小結構,放在一組,外層命名為header

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

  • #底部左右兩部分高度相似,也放在一組,並命名為footer

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

這樣我們得到了html的結構

登入後複製

在實際編碼當中,html並不是一次寫成,而是經過不斷調整才變成上面這個樣子。

二、CSS逐一實現中國結部件

1.網格

#網格最終效果是個菱形,也就是正方形旋轉了45deg,我們先不旋轉,看看它是什麼樣子

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

先設定一個變量,表示繩子的寬度,我們設為-- width,這個尺寸很重要,後面所有尺寸都是基於這個寬度,這樣後面我們調整整個圖形的大小,只要改這一個--width就行了。

:root { --width: 1.7vh; }
登入後複製

垂直和水平都各有11根繩,繩子之間的間隙約為繩子寬度的0.5倍,所以可以得到網格的寬高都為11 0.5 * 10 = 16倍的繩子寬度,所以我們可以這樣寫:

:root { --width: 1.7vh; --grid-width: calc(var(--width) * 16); } .grid { width: var(--grid-width); height: var(--grid-width); }
登入後複製

body加上一些樣式,讓盒子居中,再加上一個深色背景

body{ margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #1d1e22; overflow: hidden; }
登入後複製

再給.grid也加一個白色背景色,測試一下:

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

這樣螢幕正中間就出現了一個白色方塊,下面我們把白色背景改成11根線的樣式:

:root{ --width: 1.7vh; --red-1: #f40001; --red-2: #d40000; --red-3: #8c0703; --rope: var(--red-3), var(--red-2) calc(var(--width) * 0.25), var(--red-1) calc(var(--width) * 0.45), var(--red-1) calc(var(--width) * 0.55), var(--red-2) calc(var(--width) * 0.75), var(--red-3) var(--width); --grid-width: calc(var(--width) * 16); --bg-line: linear-gradient(90deg, var(--rope), transparent var(--width)) 0 0 / calc(var(--width) * 1.5) calc(var(--width) * 1.5); } .grid{ width: var(--grid-width); height: var(--grid-width); background: var(--bg-line); }
登入後複製

就得到了下面的效果:

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

##可能你有點蒙圈。發生了什麼事情?

還是讓事情變得簡單點,我們先畫一條不帶漸變的紅線:

.grid{ background: linear-gradient( 90deg, var(--red-1), var(--red-1) var(--width), transparent var(--width) ); }
登入後複製

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

先是線性漸變

linear- gradient,然後旋轉角度設為90deg,讓它從左到右漸變(預設是從下往上),然後起始值設為--red-1(你問我red-1red-3哪來的?效果圖上吸來的),在--width處也設定為--red-1,這樣就得到了一條寬為--width的紅線。但這還沒完,得接著在--width處加一個透明transpanrent,這樣從--width直到圖形的最右側就都不填充顏色了。

但這不太像根繩子,讓紅線漸變起來:

.grid{ background: linear-gradient( 90deg, var(--red-3), var(--red-2) calc(var(--width) * 0.25), var(--red-1) calc(var(--width) * 0.45), var(--red-1) calc(var(--width) * 0.55), var(--red-2) calc(var(--width) * 0.75), var(--red-3) var(--width), transparent var(--width) ); }
登入後複製

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

#這樣就得到了一條有一點點立體效果的繩子。可怎麼讓它橫向重複

11次,並且間隔0.5倍的--width呢?看下面的程式碼:

.grid{ background: linear-gradient( 90deg, var(--red-3), var(--red-2) calc(var(--width) * 0.25), var(--red-1) calc(var(--width) * 0.45), var(--red-1) calc(var(--width) * 0.55), var(--red-2) calc(var(--width) * 0.75), var(--red-3) var(--width), transparent var(--width) ) 0 0 / calc(var(--width) * 1.5) calc(var(--width) * 1.5); }
登入後複製

大家來找茬:這段程式碼和上一段有什麼不同?眼尖的你可能已經看出來了,多了這一行:

0 0 / calc(var(--width) * 1.5) calc(var(--width) * 1.5)
登入後複製

/為分界線,左邊的含義是background-positoin,右邊的含義是background-size

0 0也就是左上角。calc(var(--width) * 1.5) calc(var(--width) * 1.5)也就是一個正方形,寬度為1.5倍繩寬。

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

這樣一個小方塊,在垂直和水平方向上重複,就得了我們想要的結果:

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

可是我們想要的是

網格,現在頂多也就算個柵格。

那就使用偽類複製一份,並且旋轉

90deg

:root{ --width: 1.7vh; --red-1: #f40001; --red-2: #d40000; --red-3: #8c0703; --rope: var(--red-3), var(--red-2) calc(var(--width) * 0.25), var(--red-1) calc(var(--width) * 0.45), var(--red-1) calc(var(--width) * 0.55), var(--red-2) calc(var(--width) * 0.75), var(--red-3) var(--width); --grid-width: calc(var(--width) * 16); --bg-line: linear-gradient(90deg, var(--rope), transparent var(--width)) 0 0 / calc(var(--width) * 1.5) calc(var(--width) * 1.5); } .grid { width: var(--grid-width); height: var(--grid-width); background: var(--bg-line); &:after { content: ""; display: block; width: var(--grid-width); height: var(--grid-width); background: var(--bg-line); transform: rotate(90deg); } }
登入後複製

1手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

對比一下參考圖片:

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

不能说完全不相干,但是人家一看就经过了能工巧匠的编织,咱们这只能算简单的叠加,怎么才能让上面变成下面呢?

经过仔细的观察,发现只要把上面一层横着的线,稍加一些遮挡就能实现交叉编织的效果。用哪个css属性实现呢?那就只有mask了。

下图蓝色框是需要遮挡的部分,绿色框是需要重复的部分。

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

仔细分析一下绿框的构成:

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

本质上是在一个3×3的正方形上挖两个1×1的小洞,位置分别是0 01.5 1.5。我们要如何画这样一张图?并把这张图应用到mask上呢?

mask是通过传入的图片进行遮罩处理,而背景图除了传入一张png以外,CSS还内置了几个生成背景图的函数:

  • linear-gradient:线性渐变
  • repeating-linear-gradient:重复线性渐变
  • radial-gradient:径向渐变
  • conic-gradient:圆锥渐变

这些函数都可以和mask配合。这里我们使用conic-gradient实现上面的图形。

conic-gradient实现上图,思路要反着来:不是在方形上挖孔,而是用多个矩形将要渲染的部分填充颜色,剩下的部分自然就是透明的:

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

CSS实现如下:

:root{ ... --conic: #000 0 90deg, transparent 0 100%; } .grid { ... &:after { ... -webkit-mask: conic-gradient(from 0deg at var(--width) calc(var(--width) * 1.5), var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3), conic-gradient(from 90deg at calc(var(--width) * 2.5) 0, var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3), conic-gradient(from 180deg at calc(var(--width) * 1.5) var(--width), var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3), conic-gradient(from 90deg at 0 calc(var(--width) * 2.5), var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3); } }
登入後複製

预览效果

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

目前为止完整代码

:root{ --width: 1.7vh; --red-1: #f40001; --red-2: #d40000; --red-3: #8c0703; --rope: var(--red-3), var(--red-2) calc(var(--width) * 0.25), var(--red-1) calc(var(--width) * 0.45), var(--red-1) calc(var(--width) * 0.55), var(--red-2) calc(var(--width) * 0.75), var(--red-3) var(--width); --grid-width: calc(var(--width) * 16); --bg-line: linear-gradient(90deg, var(--rope), transparent var(--width)) 0 0 / calc(var(--width) * 1.5) calc(var(--width) * 1.5); --conic: #000 0 90deg, transparent 0 100%; } body{ margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background: #1d1e22; overflow: hidden; } .grid { width: var(--grid-width); height: var(--grid-width); background: var(--bg-line); &:after { content: ""; display: block; width: var(--grid-width); height: var(--grid-width); background: var(--bg-line); transform: rotate(90deg); -webkit-mask: conic-gradient(from 0deg at var(--width) calc(var(--width) * 1.5), var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3), conic-gradient(from 90deg at calc(var(--width) * 2.5) 0, var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3), conic-gradient(from 180deg at calc(var(--width) * 1.5) var(--width), var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3), conic-gradient(from 90deg at 0 calc(var(--width) * 2.5), var(--conic)) 0 0 / calc(var(--width) * 3) calc(var(--width) * 3); } }
登入後複製
登入後複製

没错,这个图形,只用了.grid这一个标签!

但是只有网格还不够,让我们继续。

2. 半圆环

回头看一下参考图:

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

嗯,环形渐变,那就是radial-gradient了:

登入後複製
.ring-small { i { position: absolute; width: calc(var(--width) * 2.5); height: calc(var(--width) * 1.5); background: radial-gradient( circle at 50% 100%, transparent calc(var(--width) * 0.25), var(--red-3) calc(var(--width) * 0.25), var(--red-2) calc(var(--width) * (0.25 + 0.25)), var(--red-1) calc(var(--width) * (0.25 + 0.45)), var(--red-1) calc(var(--width) * (0.25 + 0.55)), var(--red-2) calc(var(--width) * (0.25 + 0.75)), var(--red-3) calc(var(--width) * (0.25 + 1)), transparent calc(var(--width) * (0.25 + 1)) ); } }
登入後複製

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

这样就得到了半个环形图,让我们使用定位把它和网格结合看看

/* 先给最外层加个相对定位,后面的绝对定位都相对这一层 */ .chinese-knot { width: var(--grid-width); height: var(--grid-width); position: relative; } .ring-small { i { position: absolute; top: calc(var(--width) * -1.5); left: calc(var(--width) * 3); } }
登入後複製

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

对比素材图,发现环形不是直接紧贴在网格上的,而是先延伸了一小段直线,再接的曲线。那我们就给它增个高吧:

.ring-small { i { &:before, &:after { content: ""; position: absolute; bottom: calc(var(--width) * -0.5 + 1px); width: var(--width); height: calc(var(--width) * 0.5); background: var(--bg-line); } &:after { right: 0; } } }
登入後複製

上面使用两个伪类,为半圆环加了两截高度为0.5--width的增高垫,效果如下图

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

接着复制16个这样的图形,分别定位到各自的位置上:

         
登入後複製
.ring-small { i { position: absolute; width: calc(var(--width) * 2.5); height: calc(var(--width) * 1.5); background: radial-gradient( circle at 50% 100%, transparent calc(var(--width) * 0.25), var(--red-3) calc(var(--width) * 0.25), var(--red-2) calc(var(--width) * (0.25 + 0.25)), var(--red-1) calc(var(--width) * (0.25 + 0.45)), var(--red-1) calc(var(--width) * (0.25 + 0.55)), var(--red-2) calc(var(--width) * (0.25 + 0.75)), var(--red-3) calc(var(--width) * (0.25 + 1)), transparent calc(var(--width) * (0.25 + 1)) ); &:before, &:after { content: ""; position: absolute; bottom: calc(var(--width) * -0.5 + 1px); width: var(--width); height: calc(var(--width) * 0.5); background: var(--bg-line); } &:after { right: 0; } &:nth-child(-n + 4) { top: calc(var(--width) * -2 + 2px); } &:nth-child(1) { left: calc(var(--width) * 3); } &:nth-child(2) { left: calc(var(--width) * 6); } &:nth-child(3) { left: calc(var(--width) * 9); } &:nth-child(4) { left: calc(var(--width) * 12); } &:nth-child(-n + 8):nth-child(n + 5) { bottom: calc(var(--width) * -2 + 2px); transform: rotate(180deg); } &:nth-child(5) { left: calc(var(--width) * 1.5); } &:nth-child(6) { left: calc(var(--width) * 4.5); } &:nth-child(7) { left: calc(var(--width) * 7.5); } &:nth-child(8) { left: calc(var(--width) * 10.5); } &:nth-child(-n + 12):nth-child(n + 9) { left: calc(var(--width) * -2.5 + 2px); transform: rotate(-90deg); } &:nth-child(9) { top: calc(var(--width) * 3.5); } &:nth-child(10) { top: calc(var(--width) * 6.5); } &:nth-child(11) { top: calc(var(--width) * 9.5); } &:nth-child(12) { top: calc(var(--width) * 12.5); } &:nth-child(-n + 16):nth-child(n + 13) { right: calc(var(--width) * -2.5 + 2px); transform: rotate(90deg); } &:nth-child(13) { top: calc(var(--width) * 2); } &:nth-child(14) { top: calc(var(--width) * 5); } &:nth-child(15) { top: calc(var(--width) * 8); } &:nth-child(16) { top: calc(var(--width) * 11); } } }
登入後複製

就得到了这样的效果

2手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

哈哈,很像下水管道~

3. 四分之三圆环

还是先看素材:

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

嗯,不得不怀疑网易云的 LOGO 的灵感是不是就是中国结。

30-手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

单个环形已经实现了,两个环也不难吧:

登入後複製
.ring-big { i { position: absolute; width: calc(var(--width) * 6); height: calc(var(--width) * 6); b { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: radial-gradient( circle at 50% 50%, transparent calc(var(--width) * 0.5), var(--red-3) calc(var(--width) * 0.5), var(--red-2) calc(var(--width) * (0.5 + 0.25)), var(--red-1) calc(var(--width) * (0.5 + 0.45)), var(--red-1) calc(var(--width) * (0.5 + 0.55)), var(--red-2) calc(var(--width) * (0.5 + 0.75)), var(--red-3) calc(var(--width) * (0.5 + 1)), transparent calc(var(--width) * (0.5 + 1)), transparent calc(var(--width) * 2), var(--red-3) calc(var(--width) * 2), var(--red-2) calc(var(--width) * (2 + 0.25)), var(--red-1) calc(var(--width) * (2 + 0.45)), var(--red-1) calc(var(--width) * (2 + 0.55)), var(--red-2) calc(var(--width) * (2 + 0.75)), var(--red-3) calc(var(--width) * (2 + 1)), transparent calc(var(--width) * (2 + 1)) ); } } }
登入後複製

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

为什么标签里要再套一个标签呢,因为接下来我们要执行clip-path,还要给圆环增高,而clip-path会给增高的部分也裁剪掉,所以只能再套一层,让内层的自己clip,增高则使用的伪类实现。下面就是将圆环右下角1/4裁剪掉并且加一个增高垫的代码:

.ring-big { i { ... b { ... clip-path: polygon(0 0, 100% 0, 100% 50%, 50% 50%, 50% 100%, 0 100%); } &:before, &:after { content: ""; position: absolute; top: calc(var(--width) * 3 - 1px); left: calc(var(--width) * 3.5); width: calc(var(--width) * 2.5); height: calc(var(--width) * 0.5 + 2px); background: repeating-linear-gradient( 90deg, var(--red-3), var(--red-2) calc(var(--width) * 0.25), var(--red-1) calc(var(--width) * 0.45), var(--red-1) calc(var(--width) * 0.55), var(--red-2) calc(var(--width) * 0.75), var(--red-3) var(--width), transparent var(--width), transparent calc(var(--width) * 1.5) ); } &:after { transform: rotate(90deg); transform-origin: left top; top: calc(var(--width) * 3.5); left: calc(var(--width) * 3.5 + 1px); } } }
登入後複製

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

复制一份并定位:

.ring-big { i { ... &:nth-child(1) { left: calc(var(--width) * -3.5); top: calc(var(--width) * -3.5); } &:nth-child(2) { left: auto; top: auto; right: calc(var(--width) * -3.5); bottom: calc(var(--width) * -3.5); transform: rotate(180deg); } } }
登入後複製

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

到这里,工作的一半就已经完成了~继续

4. 十字结

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

这个图形,相对于上面几个,已经没什么难度了,五个1×1的正方形,中间的渐变方向和周围四个垂直。

中间的正方形,用父级本身实现,里面周围四个,用四个子标签实现:

登入後複製
.cross-node { .node { position: absolute; z-index: 2; width: var(--width); height: var(--width); background: var(--bg-line); i { position: absolute; width: var(--width); height: var(--width); background: var(--bg-line); transform: rotate(90deg); &:nth-child(1) { left: calc(var(--width) * -1); } &:nth-child(2) { left: var(--width); } &:nth-child(3) { top: calc(var(--width) * -1); } &:nth-child(4) { top: var(--width); } } &:nth-child(1) { right: calc(var(--width) * -1); top: calc(var(--width) * -1); } &:nth-child(2) { left: calc(var(--width) * -1); bottom: calc(var(--width) * -1); } } }
登入後複製

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

5. 挂绳

前面我们都是让中国结处于一个斜躺的姿态,写头部和尾部之前,让我们先把它摆正:

.chinese-knot { ... transform: rotate(-45deg) translate(calc(var(--width) * 4), calc(var(--width) * -4)); }
登入後複製

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

回头看素材图:

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

先确定一下html结构:

登入後複製

i是上面的吊绳,b是圆环,span是衔接处的短绳,带点黄色装饰。为了方便调整定位,我们从下往上实现,先写短绳:

:root { --yellow-1: #fced00; --yellow-2: #f28a00; --yellow-3: #da571b; --bg-yellow: linear-gradient( 90deg, var(--yellow-3), var(--yellow-2) 20%, var(--yellow-1) 40%, var(--yellow-1) 60%, var(--yellow-2) 80%, var(--yellow-3) 100% ); } .header { position: absolute; right: 0; top: 0; transform: rotate(45deg); i { position: absolute; bottom: calc(var(--width) * 1); left: calc(var(--width) * -0.5); width: calc(var(--width) * 1); height: calc(var(--width) * 2); background: var(--bg-line); &:before { content: ""; display: block; height: calc(var(--width) * 0.5); background: var(--bg-yellow); } } }
登入後複製

然后是圆环:

.header { ... b { position: absolute; bottom: calc(var(--width) * 3); left: calc(var(--width) * -1.5); width: calc(var(--width) * 3); height: calc(var(--width) * 3); background: radial-gradient( circle at 50%, transparent calc(var(--width) * 0.75), var(--red-3) calc(var(--width) * 0.75), var(--red-2) calc(var(--width) * (0.75 + 0.15)), var(--red-1) calc(var(--width) * (0.75 + 0.3)), var(--red-1) calc(var(--width) * (0.75 + 0.45)), var(--red-2) calc(var(--width) * (0.75 + 0.6)), var(--red-3) calc(var(--width) * (0.75 + 0.75)), transparent calc(var(--width) * (0.75 + 0.75)) ); } }
登入後複製

最后是长的吊绳:

.header { ... span { position: absolute; bottom: calc(var(--width) * 5); left: calc(var(--width) * -0.25); width: calc(var(--width) * 0.5); height: calc(var(--width) * 30); background: linear-gradient(90deg, var(--red-2), var(--red-1) 20%, var(--red-2) 70%, var(--red-3)); border-radius: calc(var(--width) * 0.25); } }
登入後複製

单独效果

3手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

整体效果

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

6. 流苏

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

确定html结构:

登入後複製

可以看到,流苏部分,有两个弯曲的1/8环,我们用两个b标签来表示。这个形状依然还是先画一个完整的环,然后裁剪来实现:

.footer { position: absolute; left: 0; bottom: 0; b { position: absolute; width: calc(var(--width) * 15); height: calc(var(--width) * 15); background: radial-gradient( circle at 50%, transparent calc(var(--width) * 6.5), var(--red-3) calc(var(--width) * 6.5), var(--red-2) calc(var(--width) * (6.5 + 0.25)), var(--red-1) calc(var(--width) * (6.5 + 0.45)), var(--red-1) calc(var(--width) * (6.5 + 0.55)), var(--red-2) calc(var(--width) * (6.5 + 0.75)), var(--red-3) calc(var(--width) * (6.5 + 1)), transparent calc(var(--width) * (6.5 + 1)) ); } }
登入後複製

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

加上裁剪并定位:

.footer { ... b { ... &:nth-child(1) { left: calc(var(--width) * -8.5); top: calc(var(--width) * 1); clip-path: polygon(50% 0, 50% 50%, 10% 0); } &:nth-child(2) { left: calc(var(--width) * -16); top: calc(var(--width) * -6.5); clip-path: polygon(100% 50%, 50% 50%, 100% 90%); } } }
登入後複製

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

两个小尾巴就实现了。

最后是流苏。先画一下背景上的垂直细线,这里我们用repeating-linear-gradient实现,每隔2px画一条1px宽的透明度为0.2的黑线:

.footer { .tassels { i { position: absolute; width: calc(var(--width) * 2.5); height: calc(var(--width) * 14); background: var(--red-2) repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.2) 1px, transparent 1px, transparent 3px) 50% 50% / 3px 1px;} } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

再蒙上一层黄色的装饰:

.footer { .tassels { i { ... &:before { content: ""; position: absolute; top: calc(var(--width) * 0.5); width: 100%; height: calc(var(--width) * 3.6); background: var(--bg-yellow); clip-path: polygon(0 0, 100% 0, 100% 10%, 0 10%, 0 15%, 100% 15%, 100% 85%, 0 85%, 0 90%, 100% 90%, 100% 100%, 0 100%, 0 0); } } }
登入後複製

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

上面代码中使用clip-path对黄色背景裁剪,露出两条红线,裁剪路径可以用下图表示:

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

最终效果:

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

三、加点动画

本来到这里就应该结束了。但是我想让这个中国结有点实际用途,比如加点交互什么的。

红包也是春节的习俗之一,那就加一个拉一下中国结掉落红包雨的特效吧~

1. 拉一下

给中国结在:active状态下加个位移即可实现:

.chinese-knot { width: var(--grid-width); height: var(--grid-width); position: relative; transform: rotate(-45deg) translate(calc(var(--width) * 4), calc(var(--width) * -4)); cursor: pointer; -webkit-tap-highlight-color: transparent; transition: all 0.5s; &:active { transform: rotate(-45deg) translate(calc(var(--width) * 2), calc(var(--width) * -2)); } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

2. 画个红包

先搜索一个红包素材:

4手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

观察一下红包结构,深红背景,浅红弧形开口,加一个黄色圆形封口,上面写着一个繁体的开字。

我们可以先确定html结构。.rain作为外层,代表整个红包雨,一个i标签代表一个红包:

登入後複製

一个标签怎么实现上面提到的三种元素呢?看代码:

.rain { position: absolute; top: 0; left: 0; right: 0; display: flex; justify-content: space-around; i { position: relative; display: block; width: calc(var(--width) * 5); height: calc(var(--width) * 8); background: var(--red-3); border-radius: calc(var(--width) * 0.4); overflow: hidden; box-shadow: 0 calc(var(--width) * 1) calc(var(--width) * 1) rgba(0, 0, 0, 0.3); &:before { content: ""; position: absolute; left: 50%; transform: translate(-50%, -50%); width: calc(var(--width) * 8); height: calc(var(--width) * 8); background: var(--red-1); opacity: 0.5; border-radius: 50%; } &:after { content: "開"; position: absolute; left: 50%; transform: translate(-50%, 140%); width: calc(var(--width) * 2); height: calc(var(--width) * 2); background: var(--yellow-2); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-style: normal; font-size: calc(var(--width) * 0.5); color: var(--yellow-1); text-shadow: 1px 1px 0 rgba(0, 0, 0, 0.1); } } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

使用i标签自身实现红包主体,:before伪类实现弧形的开口,:after伪类实现黄色圆形封口,在content中写上字。

一个红包完成了,再复制 9 个:

登入後複製

5手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

这样就得到了 10 个固定在顶部,并且整齐排列的红包了。

3. 红包雨动画

下雨嘛,从上往下运动就好了:

.rain { ... i { ... animation: fall 3s ease-in infinite; } } @keyframes fall { 0% { transform: translate(0, 0); } 100% { transform: translate(0, 100vh); } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

聪明的你估计已经猜到了这样的结果:谁家的雨是这样齐刷刷的下来的?

那我们就红包的垂直位置错落一点,使用sassrandom函数来实现随机:

.rain { ... i { ... @for $i from 1 through 10 { &:nth-child(#{$i}) { top: random(60) + vh; } } } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

额,效果怎么和想象的不一样。依旧还是齐刷刷下落,只不过是"错落"的齐刷刷。

那我们让每个红包的开始时间也随机不就行了嘛:

.rain { ... i { ... @for $i from 1 through 10 { &:nth-child(#{$i}) { top: random(60) + vh; animation-delay: random(30) * 0.1s; } } } }
登入後複製

5手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

嗯,好了一点点。但是有一个问题,屏幕上的雨点,有时候很多,有时候很少,不够均匀。那我们把动画的持续时间也随机会怎么样呢?

.rain { ... i { ... @for $i from 1 through 10 { &:nth-child(#{$i}) { top: random(60) + vh; animation-delay: random(30) * 0.1s; animation-duration: random(10) * 0.1s + 2s; /* 2s ~ 3s 之间随机 */ } } } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

终于更像雨了~

但是现在雨滴是凭空出现的,很生硬,我们只要把开始的位置挪到负一屏,然后让它下落到正二屏就行了:

.rain { ... top: -100vh; } @keyframes fall { 0% { transform: translate(0, 0); } 100% { transform: translate(0, 200vh); } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

这样就有了源源不断下落的效果。

4. 拉一下触发红包雨

CSS不是JS,怎么触发点击事件呢?

我们就要运用CSS本身的特性了,checkbox复选框有个选中状态:checked,而复选框可以用点击切换这个状态,再使用CSS的兄弟选择器element ~ element即可实现点击添加样式的效果。

样式可以触发了,那如何触发动画呢?

animation属性添加到元素上后,播放状态默认是running,我们需要先把初始播放状态改为paused(暂停), 然后通过上面的方法,把元素的播放状态改回running来实现播放动画的效果:

  
...
登入後複製
.rain { ... i { ... animation: fall 3s ease-in infinite; /* 默认不播放动画 */ animation-play-state: paused; } } #switch { visibility: hidden; pointer-events: none; } /* checkbox 选中时播放动画 */ #switch:checked ~ .rain i { animation-play-state: running; } /* 点击时重置动画,否则取消checkbox选中状态,动画会中止并停留在当前位置 */ .chinese-knot:active ~ .rain i { animation: none; }
登入後複製

上面的html中,我们让.chinese-knotdiv改为label来指向checkbox,方法是labelforcheckboxid设为相同的值。

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

效果很不错,我们再给红包雨下落时加个背景,以提醒用户当前的状态。并且下红包雨时,调低中国结的透明度,以突出红包的存在感。

 
...
登入後複製
.bg { position: absolute; left: 0; top: 0; height: 100vh; width: 100vw; background: linear-gradient(0deg, #171a4b, #96367f); opacity: 0; transition: all 0.5s; } #switch:checked ~ .bg { opacity: 1; } #switch:checked ~ .chinese-knot { opacity: 0.2; &:hover { opacity: 0.5; } }
登入後複製

手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

完结撒花~~~

总结

这篇文章整理了我从搜集素材开始,创作一个作品的全部过程,代码写了一天,这篇文章写了半天。希望能让 CSS 初学者对 CSS 燃起兴趣,也希望让接触了一段时间 CSS 的朋友获得一些灵感和帮助。

(学习视频分享:css视频教程

以上是手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
css
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!