CSS 實現(xiàn)按鈕點擊動效的套路
大廠技術(shù)??高級前端??Node進階
點擊上方?程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
在 Web 中,大部分按鈕可能都是平平無奇的,有時候為了強調(diào)品牌特殊或者滿足特殊功能,可能需要給按鈕添加一點點擊動效。比如,用過 Ant Design 的小伙伴應(yīng)該都能發(fā)現(xiàn),在點擊按鈕的時候會有一個很微妙的水波動畫

這就非常有特色了,看到這樣的按鈕自然會聯(lián)系上 Ant Design 。
動畫過程其實不復(fù)雜,看了一下官方的實現(xiàn),是通過 js 動態(tài)更改屬性實現(xiàn)的,在點擊的時候,改變屬性,觸發(fā)動畫,當(dāng)動畫結(jié)束之后,再將該屬性還原(還原是為了保證下次點擊仍然有動畫),如下

看著好像有點麻煩?其實,這種效果也是可以純 CSS 實現(xiàn)的,而且還能實現(xiàn)其他更多有趣的效果

一起看看吧~
一、CSS 過渡動畫
通常 CSS 中實現(xiàn)動畫有兩種思路,transition和animation。一般而言,簡單的、需要主動觸發(fā)(:hover 、:active或者動態(tài)切換類名等)的可以用transition實現(xiàn),其他的都可以用animation。
回到這個例子,動畫足夠簡單了,就兩個變化,而且需要主動觸發(fā)(這里是點擊,可以想到:active),所以優(yōu)先考慮用transition來實現(xiàn)。
觀察整個動畫,其實就是兩個效果疊加而成
陰影不斷擴大 透明度不斷降低
那么,這個動畫(過渡)的兩種狀態(tài)可以這樣來表示
/*?初始狀態(tài)?*/
button{
??opacity:?.4;
??transition:?.3s;
}
/*?擴散狀態(tài)?*/
button{
??box-shadow:?0?0?0?6px?var(--primary-color);
??opacity:?0;
}
嗯,兩種狀態(tài)的樣式都寫好了,怎么觸發(fā)點擊呢?
二、CSS 點擊動畫
先完善一下基本樣式,假設(shè) HTML 結(jié)構(gòu)如下
簡單美化一下
:root{
??--primary-color:?royalblue;
}
.button{
??padding:?5px?16px;
??color:?#000000d9;
??border:?1px?solid?#d9d9d9;
??background-color:?transparent;
??border-radius:?2px;
??line-height:?1.4;
??box-shadow:?0?2px?#00000004;
??cursor:?pointer;
??transition:?.3s;
}
.button:hover{
??color:?var(--primary-color);
??border-color:?currentColor;
}
然后添加陰影擴散動畫,為了方便透明度的控制,這里用::after偽類單獨渲染
.button::after{
??content:?'';
??position:?absolute;
??inset:?0;
??border-radius:?inherit;
??opacity:?0.4;
??transition:?.3s;
}
如果按照正常的思路通過:active來觸發(fā)過渡動畫,可能會這樣來實現(xiàn)
.button:active::after{
??box-shadow:?0?0?0?6px?var(--primary-color);
??opacity:?0;
}
效果如下:

嗯,好像不大對勁?接著往下看
三、CSS 過渡重置
為什么會有上面這種現(xiàn)象呢?這里提一下:active。:active只有在鼠標(biāo)按下時才會起作用,通常在點擊一個按鈕時,都是輕輕地點擊,而不是長按,如果在:active上添加動畫,那么在鼠標(biāo)抬起的時候,動畫一般都沒有結(jié)束,所以會導(dǎo)致在鼠標(biāo)抬起的時候,動畫馬上就停止了,如果是transition,還會有一個“回退”的過渡效果。
那么,有沒有什么方法可以只在鼠標(biāo)抬起的時候產(chǎn)生動畫呢?
我的實現(xiàn)是這樣的,假設(shè)默認就是有陰影(透明度為0)的狀態(tài),在:active的時候迅速去除陰影(這里的“迅速”,是指取消按下去的過渡動畫),然后由于默認是有過渡的,所以鼠標(biāo)抬起的時候陰影就回退到有陰影的狀態(tài)了,這樣可以保證按下去是沒有動畫的,抬起來觸發(fā)過渡動畫
整個流程其實是這樣:

取消過渡動畫也很簡單,設(shè)置時長為 0 就行了,代碼實現(xiàn)就是這樣
.button::after{
??/*其他樣式*/
??opacity:?0;
??box-shadow:?0?0?0?6px?var(--primary-color);
??transition:?.3s;
}
/*點擊*/
.button:active::after{
??box-shadow:?none;
??opacity:?0.4;
??transition:?0s;?/*取消過渡*/
}
然后,神奇的效果就出來了!

這樣就實現(xiàn)了和 Ant Design 幾乎相同的點擊效果
四、其他動效案例
上面其實提供了一種思路,只要是這種點擊動畫,都可以采用這種方式來實現(xiàn)。比如這樣一個刷新按鈕,需要點擊的時候轉(zhuǎn)一下

用這種思路就很容易了,這個例子比上面那個要簡單一些,畢竟只有旋轉(zhuǎn)變化,沒有透明度變化,核心代碼如下
.icon{
????transform:?rotate(360deg);
????transition:?.5s;
}
.button:active?.icon{
????transform:?rotate(0);
????transition:?0s;
}
完整代碼可以訪問 ant design button (codepen.io),整合了更多的 demo

再比如這樣的點擊粒子動效,原理也是相同的

在之前文章CSS實現(xiàn)一個粒子動效的按鈕中已經(jīng)有講到,這里就不多說了,完整代碼可以訪問 button-active (codepen.io)
五、更復(fù)雜的動畫
前面提到過,簡單的動畫可以用過渡transition來實現(xiàn),那么稍微復(fù)雜點的,比如下面這種 “Q彈Q彈” 的按鈕

這類動畫,單純的transition就無能為力了,必須借助animation來實現(xiàn),原理還是類似
先定義一個動畫關(guān)鍵幀
@keyframes?tada?{
????from?{
????????transform:?scale3d(1,?1,?1)
????}
????10%,?20%?{
????????transform:?scale3d(.9,?.9,?.9)?rotate3d(0,?0,?1,?-3deg)
????}
????30%,?50%,?70%,?90%?{
????????transform:?scale3d(1.1,?1.1,?1.1)?rotate3d(0,?0,?1,?3deg)
????}
????40%,?60%,?80%?{
????????transform:?scale3d(1.1,?1.1,?1.1)?rotate3d(0,?0,?1,?-3deg)
????}
????to?{
????????transform:?scale3d(1,?1,?1)
????}
}
這個動畫來自于 Animate.css 中的 tada,直接 copy 過來就行
然后讓按鈕動起來
.button{
??animation:?tada?1s;
}
在點擊的時候重置動畫,直接重置動畫,animation可能會更好理解一些,這樣在抬起的時候會重新運行動畫
.button:active{
??animation:?none;
}
這樣就實現(xiàn)了,是不是出乎意料的容易?
不過有一點小瑕疵,每次頁面刷新,按鈕會主動進行一次動畫(因為動畫是自動執(zhí)行的),如下

那么,如何避免首次進來時動畫不執(zhí)行呢?
這里有一個小技巧,可以在默認情況下設(shè)置動畫時長為 0 ,這樣在首次動畫執(zhí)行后,馬上就結(jié)束了,然后在 hover時恢復(fù)默認的動畫時長,由于動畫已經(jīng)結(jié)束,改變動畫時長也不會觸發(fā)動畫再次運行,所以實現(xiàn)就是
.button{
??animation:?jump?0s;
}
.button:hover{
??animation-duration:?1s;
}
.button:active{
??animation:?none;
}
這樣刷新頁面就不會再有動畫了

接下來,借助 animate.css 你可以更換任意的動畫,比如

完整代碼可以訪問button-jump (codepen.io),整合了更多的 demo

六、總結(jié)和說明
以上就是關(guān)于 CSS 點擊動畫的幾個套路和一些案例,其實就是默認執(zhí)行動畫,點擊時重置一下就行了。整體來說代碼很簡單,只是理解起來可能不是特別順暢,下面總結(jié)一下實現(xiàn)要點:
簡單動畫用transition,其他用 animation transition 可以通過設(shè)置時長為 0 來重置 animation 可以通過設(shè)置 none 來重置 在 :active 時重置動畫,點擊后會再次運行動畫 復(fù)雜的動畫可以借助現(xiàn)有的動畫庫,例如 anmate.css 設(shè)置動畫時長為 0 可以避免首次渲染出現(xiàn)動畫
相比 js 實現(xiàn),CSS 實現(xiàn)代碼更少,加載更快,無需等待 js 加載完成,體驗更優(yōu)(比如天然支持敲空格鍵觸發(fā)),同時也更容易維護和使用,直接復(fù)制一個類名就行了。最后,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉(zhuǎn)發(fā)???
關(guān)于本文
作者:XboxYan
https://segmentfault.com/a/1190000041400360
Node 社群
我組建了一個氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計劃也可以),我們可以一起進行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
如果你覺得這篇內(nèi)容對你有幫助,我想請你幫我2個小忙:
1. 點個「在看」,讓更多人也能看到這篇文章 2. 訂閱官方博客?www.inode.club?讓我們一起成長 點贊和在看就是最大的支持??
