目錄
一、編碼之前
1. 蒐集素材,越簡潔越好
2. 觀察細節,構思實現的可能性
3.結構拆分,化整為零
二、CSS逐一實現中國結部件
1.網格
2. 半圆环
3. 四分之三圆环
4. 十字结
5. 挂绳
6. 流苏
三、加点动画
1. 拉一下
2. 画个红包
3. 红包雨动画
4. 拉一下触发红包雨
总结
首頁 web前端 css教學 手把手帶你使用純CSS繪製一個中國結,並添加動畫效果!

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

Jan 27, 2022 am 10:52 AM
css

這篇文章手把手教大家,一步步使用純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 的結構

<div class="chinese-knot">
  <div class="grid"></div>
  <div class="ring-small">
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
    <i></i>
  </div>
  <div class="ring-big">
    <i><b></b></i>
    <i><b></b></i>
  </div>
  <div class="cross-node">
    <div class="node">
      <i></i>
      <i></i>
      <i></i>
      <i></i>
    </div>
    <div class="node">
      <i></i>
      <i></i>
      <i></i>
      <i></i>
    </div>
  </div>
  <div class="header">
    <i></i>
    <b></b>
    <span></span>
  </div>
  <div class="footer">
    <b></b>
    <b></b>
    <div class="tassels">
      <i></i>
      <i></i>
    </div>
  </div>
</div>
登入後複製

在實際編碼當中,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);
  }
}
登入後複製
<div class="grid"></div>
登入後複製

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

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

2. 半圆环

回头看一下参考图:

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

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

  <div class="ring-small">
    <i></i>
  </div>
登入後複製
.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个这样的图形,分别定位到各自的位置上:

<div class="grid"></div>
<i> <i> <i> <i> <i> <i> <i> <i> <i> <i> <i> <i> <i> <i> <i> <i>
登入後複製
.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繪製一個中國結,並添加動畫效果!

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

<div class="ring-big">
    <i><b></b></i>
</div>
登入後複製
.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繪製一個中國結,並添加動畫效果!

为什么 <i> 标签里要再套一个标签呢,因为接下来我们要执行 clip-path,还要给圆环增高,而clip-path 会给增高的部分也裁剪掉,所以只能再套一层,让内层的 <b> 自己 clip,增高则使用 <i> 的伪类实现。下面就是将圆环右下角 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 的正方形,中间的渐变方向和周围四个垂直。

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

<div class="cross-node">
    <div class="node">
      <i></i>
      <i></i>
      <i></i>
      <i></i>
    </div>
    <div class="node">
      <i></i>
      <i></i>
      <i></i>
      <i></i>
    </div>
  </div>
登入後複製
.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结构:

<div class="header">
    <i></i>
    <b></b>
    <span></span>
</div>
登入後複製

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结构:

<div class="footer">
    <b></b>
    <b></b>
    <div class="tassels">
      <i></i>
      <i></i>
    </div>
</div>
登入後複製

可以看到,流苏部分,有两个弯曲的 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标签代表一个红包:

<div class="rain">
  <i></i>
</div>
登入後複製

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

.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 个:

<div class="rain">
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
  <i></i>
</div>
登入後複製

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 来实现播放动画的效果:

<input type="checkbox" id="switch">
<label class="chinese-knot" for="switch">...</label>
<div class="rain">...</div>
登入後複製
.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繪製一個中國結,並添加動畫效果!

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

<input type="checkbox" id="switch">
<div class="bg"></div>
<label class="chinese-knot" for="switch">...</label>
<div class="rain">...</div>
登入後複製
.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中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1670
14
CakePHP 教程
1428
52
Laravel 教程
1329
25
PHP教程
1274
29
C# 教程
1256
24
vue中怎麼用bootstrap vue中怎麼用bootstrap Apr 07, 2025 pm 11:33 PM

在 Vue.js 中使用 Bootstrap 分為五個步驟:安裝 Bootstrap。在 main.js 中導入 Bootstrap。直接在模板中使用 Bootstrap 組件。可選:自定義樣式。可選:使用插件。

了解HTML,CSS和JavaScript:初學者指南 了解HTML,CSS和JavaScript:初學者指南 Apr 12, 2025 am 12:02 AM

WebDevelovermentReliesonHtml,CSS和JavaScript:1)HTMLStructuresContent,2)CSSStyleSIT和3)JavaScriptAddSstractivity,形成thebasisofmodernWebemodernWebExexperiences。

HTML,CSS和JavaScript的角色:核心職責 HTML,CSS和JavaScript的角色:核心職責 Apr 08, 2025 pm 07:05 PM

HTML定義網頁結構,CSS負責樣式和佈局,JavaScript賦予動態交互。三者在網頁開發中各司其職,共同構建豐富多彩的網站。

bootstrap怎麼插入圖片 bootstrap怎麼插入圖片 Apr 07, 2025 pm 03:30 PM

在 Bootstrap 中插入圖片有以下幾種方法:直接插入圖片,使用 HTML 的 img 標籤。使用 Bootstrap 圖像組件,可以提供響應式圖片和更多樣式。設置圖片大小,使用 img-fluid 類可以使圖片自適應。設置邊框,使用 img-bordered 類。設置圓角,使用 img-rounded 類。設置陰影,使用 shadow 類。調整圖片大小和位置,使用 CSS 樣式。使用背景圖片,使用 background-image CSS 屬性。

bootstrap怎麼寫分割線 bootstrap怎麼寫分割線 Apr 07, 2025 pm 03:12 PM

創建 Bootstrap 分割線有兩種方法:使用 標籤,可創建水平分割線。使用 CSS border 屬性,可創建自定義樣式的分割線。

bootstrap怎麼設置框架 bootstrap怎麼設置框架 Apr 07, 2025 pm 03:27 PM

要設置 Bootstrap 框架,需要按照以下步驟:1. 通過 CDN 引用 Bootstrap 文件;2. 下載文件並將其託管在自己的服務器上;3. 在 HTML 中包含 Bootstrap 文件;4. 根據需要編譯 Sass/Less;5. 導入定製文件(可選)。設置完成後,即可使用 Bootstrap 的網格系統、組件和样式創建響應式網站和應用程序。

bootstrap怎麼調整大小 bootstrap怎麼調整大小 Apr 07, 2025 pm 03:18 PM

要調整 Bootstrap 中元素大小,可以使用尺寸類,具體包括:調整寬度:.col-、.w-、.mw-調整高度:.h-、.min-h-、.max-h-

bootstrap按鈕怎麼用 bootstrap按鈕怎麼用 Apr 07, 2025 pm 03:09 PM

如何使用 Bootstrap 按鈕?引入 Bootstrap CSS創建按鈕元素並添加 Bootstrap 按鈕類添加按鈕文本

See all articles