使用純CSS實(shí)現(xiàn)動(dòng)態(tài)晴陰雨雪(單標(biāo)簽)
本期分享一下如何僅用CSS3,實(shí)現(xiàn)單標(biāo)簽的動(dòng)態(tài)晴陰雨雪。技術(shù)關(guān)鍵點(diǎn)就是“單標(biāo)簽”和“純CSS”。先看下最終效果:

再看看HTML代碼:
<!--晴--> <div class="weather sunny"></div> <!--陰--> <div class="weather cloudy"></div> <!--雨--> <div class="weather rainy"></div> <!--雪--> <div class="weather snowy"></div>
沒(méi)錯(cuò),就是這么任性,每個(gè)動(dòng)圖就一個(gè)標(biāo)簽,而且無(wú)圖無(wú)JS!下面就來(lái)詳細(xì)介紹下技術(shù)實(shí)現(xiàn)。
涉及到的關(guān)鍵CSS3屬性:
transform:用于移位、旋轉(zhuǎn)、縮放效果
box-shadow:利用投影實(shí)現(xiàn)圖像的復(fù)制(關(guān)鍵!)
clip-path:基于繪制的形狀對(duì)元素進(jìn)行遮罩處理
animation:設(shè)置元素的動(dòng)畫(huà)
以及實(shí)現(xiàn)單標(biāo)簽最關(guān)鍵的:before、:after偽類(lèi)運(yùn)用。
通過(guò)本期分享,能學(xué)到什么?
最大的一點(diǎn)就是:box-shadow的另類(lèi)玩法——“影分身”。
下面開(kāi)始逐個(gè)講解。
2 基礎(chǔ)背景
圖中的藍(lán)塊背景區(qū)域,很基礎(chǔ)了,不用講了。
設(shè)置了區(qū)域的寬高、背景色和圓角效果。
.weather {
position: relative;
display: inline-block;
width: 180px;
height: 240px;
background: #23b7e5;
border-radius: 8px;
}
3 晴天
晴天圖標(biāo)由兩個(gè)元素組成:太陽(yáng)和內(nèi)六角形陽(yáng)光。
:before、:after 兩個(gè)偽類(lèi)可以在元素內(nèi)部分別“添加”一個(gè)元素,正好都利用上了。
3.1 繪制太陽(yáng)
首先,用 :before實(shí)現(xiàn)太陽(yáng)。
.sunny:before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
background: #F6D963;
border-radius: 50%;
box-shadow: 0 0 20px #ff0;
z-index: 2;
}
content用來(lái)生成一個(gè)元素。
position、top、left、transform用來(lái)實(shí)現(xiàn)中心居中。
box-shadow實(shí)現(xiàn)外發(fā)光效果,這只是box-shadow最基本最常用的使用方式。

3.2 繪制內(nèi)六角形
用 :after實(shí)現(xiàn)內(nèi)六角形。
實(shí)現(xiàn)的關(guān)鍵就是使用遮罩。通過(guò)clip-path繪制一個(gè)內(nèi)六角形。這就變成了一個(gè)簡(jiǎn)單的初中幾何問(wèn)題。
內(nèi)六角形由兩個(gè)等邊三角形拼合而成。

合并之后,我們可以把整體劃分為若干個(gè)完全相同的小等邊三角形。

在垂直方向做個(gè)輔助線(xiàn),連接中間頂部和底部?jī)牲c(diǎn)。不難發(fā)現(xiàn),“垂直方向的最大長(zhǎng)度”要大于“水平方向的最大長(zhǎng)度”。

設(shè)小等邊三角形的邊長(zhǎng)為1,以?xún)?nèi)六角形中心為坐標(biāo)原點(diǎn),可以計(jì)算出每個(gè)點(diǎn)的坐標(biāo),如下:

為了使用clip-path的百分比定位來(lái)繪制圖像,下一步需要把長(zhǎng)度坐標(biāo)轉(zhuǎn)換為百分比坐標(biāo)。
設(shè)垂直方向最大長(zhǎng)度為100%,仍以?xún)?nèi)六角形中心為坐標(biāo)原點(diǎn),每個(gè)點(diǎn)的坐標(biāo)值轉(zhuǎn)換如下:

由于clip-path繪制原點(diǎn)是在左上角,x軸右側(cè)為正值,y軸下方為正值。需要做下坐標(biāo)系轉(zhuǎn)換。即:
新x軸坐標(biāo)值 = 舊x軸坐標(biāo)值 + 50%
新y軸坐標(biāo)值 = (舊y軸坐標(biāo)值 - 50%) * -1

使用clip-path的polygon方法繪制內(nèi)六角形,坐標(biāo)已通過(guò)上面的步驟計(jì)算出來(lái)了。
樣式代碼如下:
.sunny:after {
content: "";
position: absolute;
top: 50%;
left: 50%;
margin: -45px 0 0 -45px;
width: 90px;
height: 90px;
background: #FFEB3B;
clip-path: polygon(
50% 0%,
65.43% 25%,
93.3% 25%,
78.87% 50%,
93.3% 75%,
64.43% 75%,
50% 100%,
35.57% 75%,
6.7% 75%,
21.13% 50%,
6.7% 25%,
35.57% 25%);
z-index: 1;
animation: sunScale 2s linear infinite;
}
@keyframes sunScale {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}

實(shí)現(xiàn)原理就是通過(guò)clip-path繪制了一個(gè)內(nèi)六角形遮罩,把黃顏色背景通過(guò)遮罩變成了最終的個(gè)內(nèi)六角形。
animation通過(guò)關(guān)鍵幀動(dòng)畫(huà)實(shí)現(xiàn)了“放大縮小”交替動(dòng)效。
最終效果:

4 陰天
觀察圖形發(fā)現(xiàn),有兩個(gè)云朵:前面的白云和后面的烏云。貌似需要分別用 :before和 :after實(shí)現(xiàn)。如果這樣做的話(huà),后續(xù)章節(jié)的雨天和雪天的雨雪元素就沒(méi)有多余的偽類(lèi)可用了。所以只能用一個(gè)偽類(lèi)實(shí)現(xiàn)兩朵云。 這里就用到了box-shadow的“影分身”了!
由于后續(xù)章節(jié)的雨天和雪天都復(fù)用了云的樣式,所以寫(xiě)在一起了,代碼如下:
.cloudy:before,
.rainy:before,
.snowy:before {
content: "";
position: absolute;
top: 50%;
left: 25%;
transform: translate(-50%, -50%);
width: 36px;
height: 36px;
background: #fff;
border-radius: 50%;
z-index: 2;
}

真實(shí)的元素(真身)就是一個(gè)圓。通過(guò)box-shodow來(lái)把投影作為“分身”。
先來(lái)看看box-shadow的屬性:
box-shadow: h-shadow v-shadow blur spread color inset;
參數(shù)詳解:
h-shadow: 陰影的水平偏移量。
v-shadow: 陰影的垂直偏移量。
blur: 模糊距離(就是漸變的距離,設(shè)為0就沒(méi)有漸變)。
spread: 投影的尺寸,通過(guò)這個(gè)控制“影分身”的大小。
color: 投影顏色,通過(guò)這個(gè)實(shí)現(xiàn)后方的烏云。
inset: 改為內(nèi)陰影。這里用不到。
先復(fù)制一個(gè)影分身試試:
box-shadow: #fff 22px -15px 0 6px;

繼續(xù)復(fù)制多個(gè)影分身,帶全部影分身的完整代碼如下:
.cloudy:before,
.rainy:before,
.snowy:before {
content: "";
position: absolute;
top: 50%;
left: 25%;
transform: translate(-50%, -50%);
width: 36px;
height: 36px;
background: #fff;
border-radius: 50%;
box-shadow:
#fff 22px -15px 0 6px,
#fff 57px -6px 0 2px,
#fff 87px 4px 0 -4px,
#fff 33px 6px 0 6px,
#fff 61px 6px 0 2px,
#ccc 29px -23px 0 6px,
#ccc 64px -14px 0 2px,
#ccc 94px -4px 0 -4px;
z-index: 2;
}
五個(gè)分身的白圓(#fff),三個(gè)分身的灰圓(#ccc)拼成了兩朵云。
再給云朵加上“上下浮動(dòng)”的動(dòng)效:
.cloudy:before {
animation: cloudMove 2s linear infinite;
}
@keyframes cloudMove {
0% {
transform: translate(-50%, -50%);
}
50% {
transform: translate(-50%, -60%);
}
100% {
transform: translate(-50%, -50%);
}
}

5 雨天
云朵的代碼直接復(fù)用第4章的陰天。這里使用 :after 偽類(lèi)實(shí)現(xiàn)雨滴。
先實(shí)現(xiàn)一個(gè)雨滴(為方便觀看,暫時(shí)隱藏云朵):
.rainy:after {
content: "";
position: absolute;
top:50%;
left: 25%;
width: 4px;
height: 14px;
background: #fff;
border-radius: 2px;
}

然后通過(guò)box-shadow“影分身”:
.rainy:after {
content: "";
position: absolute;
top:50%;
left: 25%;
width: 4px;
height: 14px;
background: #fff;
border-radius: 2px;
+ box-shadow:
+ #fff 25px -10px 0,
+ #fff 50px 0 0,
+ #fff 75px -10px 0,
+ #fff 0 25px 0,
+ #fff 25px 15px 0,
+ #fff 50px 25px 0,
+ #fff 75px 15px 0,
+ #fff 0 50px 0,
+ #fff 25px 40px 0,
+ #fff 50px 50px 0,
+ #fff 75px 40px 0;
}

再加入下雨的移動(dòng)動(dòng)效,修改如下:
.rainy:after {
...(略)
+ animation: rainDrop 2s linear infinite;
}
+ @keyframes rainDrop {
+ 0% {
+ transform: translate(0, 0) rotate(10deg);
+ }
+ 100% {
+ transform: translate(-4px, 24px) rotate(10deg);
+ box-shadow:
+ #fff 25px -10px 0,
+ #fff 50px 0 0,
+ #fff 75px -10px 0,
+ #fff 0 25px 0,
+ #fff 25px 15px 0,
+ #fff 50px 25px 0,
+ #fff 75px 15px 0,
+ rgba(255, 255, 255, 0) 0 50px 0,
+ rgba(255, 255, 255, 0) 25px 40px 0,
+ rgba(255, 255, 255, 0) 50px 50px 0,
+ rgba(255, 255, 255, 0) 75px 40px 0;
+ }
+ }

動(dòng)畫(huà)添加了10度的旋轉(zhuǎn),讓雨滴傾斜,以及垂直方向的移動(dòng)。
這里的關(guān)鍵就是:雖然本質(zhì)是垂直移動(dòng),但為了看上去是“循環(huán)”效果,需要將最下面的雨滴進(jìn)行透明漸變,同時(shí)調(diào)節(jié)X和Y軸的值,讓最終位置正好跟初始位置重合,就不會(huì)顯得“斷開(kāi)”。
我們生成的是三行雨滴,第一行被云朵擋住了,實(shí)際能看到的是下面兩行。在第一行移動(dòng)到第二行位置的時(shí)候,原第三行已經(jīng)透明看不見(jiàn)了,正好與初始狀態(tài)一樣,實(shí)現(xiàn)了無(wú)縫循環(huán)拼接。
6 雪天
雪天與雨天的區(qū)別就是把雨滴換成圓形,取消旋轉(zhuǎn)角度。 代碼如下:
.snowy:after {
content: "";
position: absolute;
top:50%;
left: 25%;
width: 8px;
height: 8px;
background: #fff;
border-radius: 50%;
box-shadow:
#fff 25px -10px 0,
#fff 50px 0 0,
#fff 75px -10px 0,
#fff 0 25px 0,
#fff 25px 15px 0,
#fff 50px 25px 0,
#fff 75px 15px 0,
#fff 0 50px 0,
#fff 25px 40px 0,
#fff 50px 50px 0,
#fff 75px 40px 0;
animation: snowDrop 2s linear infinite;
}
@keyframes snowDrop {
0% {
transform: translateY(0);
}
100% {
transform: translateY(25px);
box-shadow:
#fff 25px -10px 0,
#fff 50px 0 0,
#fff 75px -10px 0,
#fff 0 25px 0,
#fff 25px 15px 0,
#fff 50px 25px 0,
#fff 75px 15px 0,
rgba(255, 255, 255, 0) 0 50px 0,
rgba(255, 255, 255, 0) 25px 40px 0,
rgba(255, 255, 255, 0) 50px 50px 0,
rgba(255, 255, 255, 0) 75px 40px 0;
}
}

7 全部源碼
源碼如下,方便粘貼保存為html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title單標(biāo)簽!純CSS實(shí)現(xiàn)動(dòng)態(tài)晴陰雨雪</title>
</head>
<body>
<div class="weather sunny"></div>
<div class="weather cloudy"></div>
<div class="weather rainy"></div>
<div class="weather snowy"></div>
</body>
<style>
.weather {
position: relative;
display: inline-block;
width: 180px;
height: 240px;
background: #23b7e5;
border-radius: 8px;
}
.sunny:before {
content: "";
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
background: #F6D963;
border-radius: 50%;
box-shadow: 0 0 20px #ff0;
z-index: 2;
}
.sunny:after {
content: "";
position: absolute;
top: 50%;
left: 50%;
margin: -45px 0 0 -45px;
width: 90px;
height: 90px;
background: #FFEB3B;
clip-path: polygon(
50% 0%,
65.43% 25%,
93.3% 25%,
78.87% 50%,
93.3% 75%,
64.43% 75%,
50% 100%,
35.57% 75%,
6.7% 75%,
21.13% 50%,
6.7% 25%,
35.57% 25%);
z-index: 1;
animation: sunScale 2s linear infinite;
}
@keyframes sunScale {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
.cloudy:before,
.rainy:before,
.snowy:before {
content: "";
position: absolute;
top: 50%;
left: 25%;
transform: translate(-50%, -50%);
width: 36px;
height: 36px;
background: #fff;
border-radius: 50%;
box-shadow:
#fff 22px -15px 0 6px,
#fff 57px -6px 0 2px,
#fff 87px 4px 0 -4px,
#fff 33px 6px 0 6px,
#fff 61px 6px 0 2px,
#ccc 29px -23px 0 6px,
#ccc 64px -14px 0 2px,
#ccc 94px -4px 0 -4px;
z-index: 2;
}
.cloudy:before {
animation: cloudMove 2s linear infinite;
}
@keyframes cloudMove {
0% {
transform: translate(-50%, -50%);
}
50% {
transform: translate(-50%, -60%);
}
100% {
transform: translate(-50%, -50%);
}
}
.rainy:after {
content: "";
position: absolute;
top:50%;
left: 25%;
width: 4px;
height: 14px;
background: #fff;
border-radius: 2px;
box-shadow:
#fff 25px -10px 0,
#fff 50px 0 0,
#fff 75px -10px 0,
#fff 0 25px 0,
#fff 25px 15px 0,
#fff 50px 25px 0,
#fff 75px 15px 0,
#fff 0 50px 0,
#fff 25px 40px 0,
#fff 50px 50px 0,
#fff 75px 40px 0;
animation: rainDrop 2s linear infinite;
}
@keyframes rainDrop {
0% {
transform: translate(0, 0) rotate(10deg);
}
100% {
transform: translate(-4px, 24px) rotate(10deg);
box-shadow:
#fff 25px -10px 0,
#fff 50px 0 0,
#fff 75px -10px 0,
#fff 0 25px 0,
#fff 25px 15px 0,
#fff 50px 25px 0,
#fff 75px 15px 0,
rgba(255, 255, 255, 0) 0 50px 0,
rgba(255, 255, 255, 0) 25px 40px 0,
rgba(255, 255, 255, 0) 50px 50px 0,
rgba(255, 255, 255, 0) 75px 40px 0;
}
}
.snowy:after {
content: "";
position: absolute;
top:50%;
left: 25%;
width: 8px;
height: 8px;
background: #fff;
border-radius: 50%;
box-shadow:
#fff 25px -10px 0,
#fff 50px 0 0,
#fff 75px -10px 0,
#fff 0 25px 0,
#fff 25px 15px 0,
#fff 50px 25px 0,
#fff 75px 15px 0,
#fff 0 50px 0,
#fff 25px 40px 0,
#fff 50px 50px 0,
#fff 75px 40px 0;
animation: snowDrop 2s linear infinite;
}
@keyframes snowDrop {
0% {
transform: translateY(0);
}
100% {
transform: translateY(25px);
box-shadow:
#fff 25px -10px 0,
#fff 50px 0 0,
#fff 75px -10px 0,
#fff 0 25px 0,
#fff 25px 15px 0,
#fff 50px 25px 0,
#fff 75px 15px 0,
rgba(255, 255, 255, 0) 0 50px 0,
rgba(255, 255, 255, 0) 25px 40px 0,
rgba(255, 255, 255, 0) 50px 50px 0,
rgba(255, 255, 255, 0) 75px 40px 0;
}
}
</style>
</html>

總結(jié)
以上所述是小編給大家介紹的使用純CSS實(shí)現(xiàn)動(dòng)態(tài)晴陰雨雪(單標(biāo)簽),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
相關(guān)文章

CSS3打造的現(xiàn)代交互式登錄界面詳細(xì)實(shí)現(xiàn)過(guò)程
本文介紹CSS3和jQuery在登錄界面設(shè)計(jì)中的應(yīng)用,涵蓋動(dòng)畫(huà)、選擇器、自定義字體及盒模型技術(shù),提升界面美觀與交互性,同時(shí)優(yōu)化性能和可訪(fǎng)問(wèn)性,感興趣的朋友跟隨小編一起看看吧2025-06-20CSS普通流、浮動(dòng)與定位網(wǎng)頁(yè)布局三大機(jī)制及最佳實(shí)踐
本文給大家講解CSS 的三種核心布局機(jī)制——普通流(Normal Flow)、浮動(dòng)(Float)和定位(Positioning)對(duì)于創(chuàng)建靈活、響應(yīng)式的網(wǎng)頁(yè)至關(guān)重要,本文將深入探討這三種機(jī)制的工作原2025-06-19
css實(shí)現(xiàn)角標(biāo)效果并帶有文章或圖標(biāo)效果(完整代碼)
文章介紹如何用CSS實(shí)現(xiàn)角標(biāo)效果,通過(guò).active類(lèi)結(jié)合::after和::before偽元素,利用定位、邊框和旋轉(zhuǎn)創(chuàng)建紅色邊框與白色三角形的提示標(biāo)志,適用于按鈕或卡片元素的視覺(jué)增強(qiáng)設(shè)計(jì)2025-06-19CSS Anchor Positioning重新定義錨點(diǎn)定位的時(shí)代來(lái)臨(最新推薦)
CSS Anchor Positioning是一項(xiàng)仍在草案中的新特性,由 Chrome 125 開(kāi)始提供原生支持需啟用實(shí)驗(yàn) flag,它允許你在 CSS 中通過(guò)錨點(diǎn)(anchor)來(lái)相對(duì)于任意 DOM 元素定位,本文2025-06-17CSS中的Static、Relative、Absolute、Fixed、Sticky的應(yīng)用與詳細(xì)對(duì)比
CSS 中的 position 屬性用于控制元素的定位方式,不同的定位方式會(huì)影響元素在頁(yè)面中的布局和層疊關(guān)系,以下是 static、relative、absolute、fixed、sticky 的詳細(xì)對(duì)比和應(yīng)用2025-06-17CSS place-items: center解析與用法詳解
place-items: center; 是一個(gè)強(qiáng)大的 CSS 簡(jiǎn)寫(xiě)屬性,用于同時(shí)控制 網(wǎng)格(Grid) 和 彈性盒(Flexbox) 布局中的對(duì)齊方式,本文給大家介紹CSS place-items: center; 詳解與用法2025-06-17
CSS實(shí)現(xiàn)元素?fù)螡M(mǎn)剩余空間的五種方法
在日常開(kāi)發(fā)中,我們經(jīng)常需要讓某個(gè)元素占據(jù)容器的剩余空間,本文將介紹5種不同的方法來(lái)實(shí)現(xiàn)這個(gè)需求,并分析各種方法的優(yōu)缺點(diǎn),感興趣的朋友一起看看吧2025-06-17CSS中前端單位 px、vw、vh 等的區(qū)別與使用建議
CSS單位區(qū)別與使用場(chǎng)景總結(jié):px絕對(duì)、vw/vh響應(yīng)式,%繼承父尺寸,em/rem文字縮放,vmin/vmax適應(yīng)寬高變化,固定布局用px或%,響應(yīng)式布局用vw/vh/rem,文字用em或rem,本文給大家2025-06-16CSS 樣式表的四種應(yīng)用方式及css注釋的應(yīng)用小結(jié)
這篇文章主要介紹了CSS 樣式表的四種應(yīng)用方式及css注釋的應(yīng)用小結(jié),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-05-21CSS中padding基本概念及簡(jiǎn)單寫(xiě)法
在CSS布局中,padding屬性是控制元素內(nèi)容與其邊框之間距離的關(guān)鍵工具,本文介紹CSS基礎(chǔ)中padding,通過(guò)本文的介紹,我們深入了解了padding的基本概念、簡(jiǎn)寫(xiě)方法以及它對(duì)元2025-05-16




