使用純CSS實(shí)現(xiàn)動態(tài)晴陰雨雪(單標(biāo)簽)

本期分享一下如何僅用CSS3,實(shí)現(xiàn)單標(biāo)簽的動態(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>
沒錯,就是這么任性,每個(gè)動圖就一個(gè)標(biāo)簽,而且無圖無JS!下面就來詳細(xì)介紹下技術(shù)實(shí)現(xiàn)。
涉及到的關(guān)鍵CSS3屬性:
transform:用于移位、旋轉(zhuǎn)、縮放效果
box-shadow:利用投影實(shí)現(xiàn)圖像的復(fù)制(關(guān)鍵!)
clip-path:基于繪制的形狀對元素進(jìn)行遮罩處理
animation:設(shè)置元素的動畫
以及實(shí)現(xiàn)單標(biāo)簽最關(guān)鍵的:before、:after偽類運(yùn)用。
通過本期分享,能學(xué)到什么?
最大的一點(diǎn)就是:box-shadow的另類玩法——“影分身”。
下面開始逐個(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è)元素組成:太陽和內(nèi)六角形陽光。
:before、:after 兩個(gè)偽類可以在元素內(nèi)部分別“添加”一個(gè)元素,正好都利用上了。
3.1 繪制太陽
首先,用 :before實(shí)現(xiàn)太陽。
.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用來生成一個(gè)元素。
position、top、left、transform用來實(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)鍵就是使用遮罩。通過clip-path繪制一個(gè)內(nèi)六角形。這就變成了一個(gè)簡單的初中幾何問題。
內(nèi)六角形由兩個(gè)等邊三角形拼合而成。
合并之后,我們可以把整體劃分為若干個(gè)完全相同的小等邊三角形。
在垂直方向做個(gè)輔助線,連接中間頂部和底部兩點(diǎn)。不難發(fā)現(xiàn),“垂直方向的最大長度”要大于“水平方向的最大長度”。
設(shè)小等邊三角形的邊長為1,以內(nèi)六角形中心為坐標(biāo)原點(diǎn),可以計(jì)算出每個(gè)點(diǎn)的坐標(biāo),如下:
為了使用clip-path的百分比定位來繪制圖像,下一步需要把長度坐標(biāo)轉(zhuǎn)換為百分比坐標(biāo)。
設(shè)垂直方向最大長度為100%,仍以內(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)已通過上面的步驟計(jì)算出來了。
樣式代碼如下:
.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)原理就是通過clip-path繪制了一個(gè)內(nèi)六角形遮罩,把黃顏色背景通過遮罩變成了最終的個(gè)內(nèi)六角形。
animation通過關(guān)鍵幀動畫實(shí)現(xiàn)了“放大縮小”交替動效。
最終效果:
4 陰天
觀察圖形發(fā)現(xiàn),有兩個(gè)云朵:前面的白云和后面的烏云。貌似需要分別用 :before和 :after實(shí)現(xiàn)。如果這樣做的話,后續(xù)章節(jié)的雨天和雪天的雨雪元素就沒有多余的偽類可用了。所以只能用一個(gè)偽類實(shí)現(xiàn)兩朵云。 這里就用到了box-shadow的“影分身”了!
由于后續(xù)章節(jié)的雨天和雪天都復(fù)用了云的樣式,所以寫在一起了,代碼如下:
.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è)圓。通過box-shodow來把投影作為“分身”。
先來看看box-shadow的屬性:
box-shadow: h-shadow v-shadow blur spread color inset;
參數(shù)詳解:
h-shadow: 陰影的水平偏移量。
v-shadow: 陰影的垂直偏移量。
blur: 模糊距離(就是漸變的距離,設(shè)為0就沒有漸變)。
spread: 投影的尺寸,通過這個(gè)控制“影分身”的大小。
color: 投影顏色,通過這個(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)拼成了兩朵云。
再給云朵加上“上下浮動”的動效:
.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 偽類實(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; }
然后通過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; }
再加入下雨的移動動效,修改如下:
.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; + } + }
動畫添加了10度的旋轉(zhuǎn),讓雨滴傾斜,以及垂直方向的移動。
這里的關(guān)鍵就是:雖然本質(zhì)是垂直移動,但為了看上去是“循環(huán)”效果,需要將最下面的雨滴進(jìn)行透明漸變,同時(shí)調(diào)節(jié)X和Y軸的值,讓最終位置正好跟初始位置重合,就不會顯得“斷開”。
我們生成的是三行雨滴,第一行被云朵擋住了,實(shí)際能看到的是下面兩行。在第一行移動到第二行位置的時(shí)候,原第三行已經(jīng)透明看不見了,正好與初始狀態(tài)一樣,實(shí)現(xiàn)了無縫循環(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)動態(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)動態(tài)晴陰雨雪(單標(biāo)簽),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
相關(guān)文章
- CSS Grid 是一種二維布局系統(tǒng),可以同時(shí)控制行和列,相比 Flex(一維布局),更適合用在整體頁面布局或復(fù)雜模塊結(jié)構(gòu)中,這篇文章主要介紹了前端CSS Grid 布局詳解,需要的朋2025-04-16
CSS Padding 和 Margin 區(qū)別全解析
CSS 中的 padding 和 margin 是兩個(gè)非?;A(chǔ)且重要的屬性,它們用于控制元素周圍的空白區(qū)域,本文將詳細(xì)介紹 padding 和 margin 的概念、區(qū)別以及如何在實(shí)際項(xiàng)目中使用它們2025-04-07- will-change 是一個(gè) CSS 屬性,用于告訴瀏覽器某個(gè)元素在未來可能會發(fā)生哪些變化,本文給大家介紹CSS will-change 屬性詳解,感興趣的朋友一起看看吧2025-04-07
- 本文給大家分享在 CSS 中,去除a標(biāo)簽(超鏈接)的下劃線的幾種方法,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-04-07
- 在前端開發(fā)中,CSS(層疊樣式表)不僅是用來控制網(wǎng)頁的外觀和布局,更是實(shí)現(xiàn)復(fù)雜交互和動態(tài)效果的關(guān)鍵技術(shù)之一,隨著前端技術(shù)的不斷發(fā)展,CSS的用法也日益豐富和高級,本文將2025-04-07
css中的 vertical-align與line-height作用詳解
文章詳細(xì)介紹了CSS中的`vertical-align`和`line-height`屬性,包括它們的作用、適用元素、屬性值、常見使用場景、常見問題及解決方案,感興趣的朋友跟隨小編一起看看吧2025-03-26淺析CSS 中z - index屬性的作用及在什么情況下會失效
z-index屬性用于控制元素的堆疊順序,值越大,元素越顯示在上層,它需要元素具有定位屬性(如relative、absolute、fixed或sticky),本文給大家介紹CSS 中z - index屬性的作用2025-03-21- 文章詳細(xì)介紹了CSS中的打印媒體查詢@mediaprint包括基本語法、常見使用場景和代碼示例,如隱藏非必要元素、調(diào)整字體和顏色、處理鏈接的URL顯示、分頁控制、調(diào)整邊距和背景等2025-03-18
CSS模擬 html 的 title 屬性(鼠標(biāo)懸浮顯示提示文字效果)
本文介紹了如何使用CSS模擬HTML的title屬性,通過鼠標(biāo)懸浮顯示提示文字效果,通過設(shè)置`.tipBox`和`.tipBox.tipContent`的樣式,實(shí)現(xiàn)了提示內(nèi)容的隱藏和顯示,感興趣的朋友一起2025-03-10前端 CSS 動態(tài)設(shè)置樣式::class、:style 等技巧(推薦)
本文介紹了Vue.js中動態(tài)綁定類名和內(nèi)聯(lián)樣式的兩種方法:對象語法和數(shù)組語法,通過對象語法,可以根據(jù)條件動態(tài)切換類名或樣式;通過數(shù)組語法,可以同時(shí)綁定多個(gè)類名或樣式,此外2025-02-26