1. 巧用 transition 實現直播間 點贊動畫

        共 6307字,需瀏覽 13分鐘

         ·

        2022-08-11 23:15

        在各種短視頻界面上,我們經常會看到類似這樣的點贊動畫:

        79d523164172934ab58b45f0c823bda4.webp

        非常的有意思,有意思的交互會讓用戶更愿意進行互動。

        那么,這么有趣的點贊動畫,有沒有可能使用純 CSS 實現呢?那當然是必須的,本文,就將巧妙的借助 transition,僅僅使用 CSS 完成這么一個點贊動畫。

        實現不同表情的不斷上升

        如果使用純 CSS 實現這一整套動畫的話。我們首先需要實現一段無限循環(huán)的,大量不同的表情不斷向上漂浮的動畫。

        像是這樣:

        710c4d4a1786be482cac145ffb5360e7.webp

        這個整體還是比較容易實現的,核心原理就是同一個動畫,設置不同的 transition-durationtransition-dalay,和一定范圍內的旋轉角度。

        我們首先要實現多個表情,一個 DOM 標簽放入一個隨機的表情。

        我們可以手動一個一個的添加:

        <ul?class="g-wrap">
        ????<li>??</li>
        ????<li>??</li>
        ????<li>??</li>
        ????//?...?隨機設置不同的表情符號,共?50?個
        ????<li>...</li>
        </ul>

        當然,我個人覺得這樣太麻煩。我習慣利用 SASS 的循環(huán)函數及隨機函數,利用偽元素的 content 去隨機生成不同表情。像是這樣:

        <ul?class="g-wrap">
        ????<li></li>
        ????<li></li>
        ????<li></li>
        ????//?...?共50個空標簽
        </ul>
        $expression:?"??",?"??",?"??",?"??",?"??",?"??",?"??",?"??",?"????",?"??",?"??",?"??",?"??",?"??";
        .g-wrap?{
        ????position:?relative;
        ????width:?50px;
        ????height:?50px;
        }
        @for?$i?from?1?to?51?{
        ????li:nth-child(#{$i})?{
        ????????position:?absolute;
        ????????top:?0;
        ????????left:?0;
        ????????width:?50px;
        ????????height:?50px;
        ????????
        ????????&::before?{
        ????????????content:?nth($expression,?random(length($expression)));
        ????????????position:?absolute;
        ????????????font-size:?50px;
        ????????}
        ????}
        }

        這樣,我們就能得到 50 個疊加在一起的表情:

        1c41cbc92243710e5056270fe6f83c83.webp

        因為透明度為 1 的緣故,只能看到最上面的幾個表情,實際上這里疊加了 50 個不同的表情。

        這里的核心就是 content: nth($expression, random(length($expression))),我們利用了 SASS 的 random 和 length 和 nth 等方法,隨機的將 $expression 列表中的表情,添加給了不同的 li 的 before 偽元素的 content 內。

        接下來,我們需要讓它們動起來。

        這個簡單,添加一個無限的 transform: translate() 動畫即可:

        @for?$i?from?1?to?51?{
        ????li:nth-child(#{$i})?{
        ????????animation:?move?3000ms?infinite?linear;
        ????}
        }
        @keyframes?move?{
        ????100%?{
        ????????transform:?translate(0,?-250px);
        ????}
        }

        效果如下:

        cc548b90b023833436270602059dc1eb.webp

        OK,由于 50 個元素都疊加在一起,所以我們需要將動畫區(qū)分開來,我們給它們添加隨機的動畫時長,并且,賦予不同的負 transition-delay 值:

        @for?$i?from?1?to?51?{
        ????li:nth-child(#{$i})?{
        ????????animation:?move?#{random()?*?2500?+?1500}ms?infinite?#{random()?*?4000?/?-1000}s?linear;
        ????}
        }
        @keyframes?move?{
        ????100%?{
        ????????transform:?translate(0,?-250px);
        ????}
        }

        效果如下:

        26305e364b2be7d5b846eda5080731f2.webp

        效果已經非常接近我們想要的了!這里有一點點的跳躍,需要理解 move #{random() * 2500 + 1500}ms infinite #{random() * 4000 / -1000}s linear 這里大段代碼:

        1. #{random() * 2500 + 1500}ms 生成 1500ms ~ 4000ms 之間的隨機數,表示動畫的持續(xù)時長
        2. #{random() * 4000 / -1000}s 生成 -4000ms ~ 0s 之間的隨機數,表示負的動畫延遲量,這樣做的目的是為了讓動畫提前進行

        如果你對負的 transition-delay 的作用還不了解,可以看看我的這篇文章 -- 深入淺出 CSS 動畫[1]

        到這,還是不夠隨機,我們再通過隨機添加一個較小的旋轉角度,讓整體的效果更加的隨機:

        @for?$i?from?1?to?51?{
        ????li:nth-child(#{$i})?{
        ????????transform:?rotate(#{random()?*?80?-?40}deg);
        ????????animation:?move?#{random()?*?2500?+?1500}ms?infinite?#{random()?*?4000?/?-1000}s?linear;
        ????}
        }
        @keyframes?move?{
        ????100%?{
        ????????transform:?rotate(0)?translate(0,?-250px);
        ????}
        }

        這里 transform: rotate(#{random() * 80 - 40}deg) 的作用就是隨機生成 -40deg ~ 40deg 的隨機數,產生一個隨機的角度。

        至此,我們就得到了這樣一個效果:

        710c4d4a1786be482cac145ffb5360e7.webp

        利用 transition 化腐朽為神奇

        到這里。很多同學可能還不明白,明明是點贊一次產生一個表情,為什么需要一次生成這么多不斷運動的表情效果呢?

        這是因為,由于 CSS 沒法直接正面做到點擊一次,生成一個表情,所以我們需要換一種思路實現。

        如果這些表情一直都是在運動的,只不過不點擊的時候,它們的透明度都為 0,我們要做的,就是當我們點擊的時候,讓它們從 opacity: 0 變到 opacity: 1。

        要實現這一點,我們需要巧妙的用到 transition

        我們以一個表情為例子:

        1. 默認它的透明度為 opacity: 0.1
        2. 點擊的時候,它的透明度瞬間變成 opacity: 1
        3. 然后,通過 transition-delayopacity: 1 的狀態(tài)保持一段時間后
        4. 逐漸再消失,變回 opacity: 0.1

        看上去有億點點復雜,代碼會更容易理解:

        li?{
        ????opacity:?.1;
        ????transition:?1.5s?opacity?0.8s;
        }
        li:active?{
        ????opacity:?1;
        ????transition:?.1s?opacity;
        }

        效果如下:

        bfc96ab10830c85067c0b2b83a491c41.webp

        一定要理解上面的代碼!巧妙地利用 transition 在正常狀態(tài)和 active 狀態(tài)下的變化,我們實現了這種巧妙的點擊效果。

        如果我們把初始的 opacity: 0.1 改成 opacity: 0 呢?就會是這樣:

        267d47b51f78b5acdf4c1b61d06be02f.webp

        好,我們結合一下上面兩個動畫:

        1. 我們將所有的表情,默認的透明度改為 0.1
        2. 被點擊的時候,透明度變成 1
        3. 透明度在 1 ?維持一段時間,逐漸消失

        代碼如下:

        @for?$i?from?1?to?51{
        ????li:nth-child(#{$i})?{
        ????????position:?absolute;
        ????????top:?0;
        ????????left:?0;
        ????????width:?50px;
        ????????height:?50px;
        ????????transform:?rotate(#{random()?*?80?-?40}deg);
        ????????animation:?move?#{random()?*?2500?+?1500}ms?infinite?#{random()?*?4000?/?-1000}s?linear;
        ????????opacity:?.1;
        ????????transition:?1.5s?opacity?.8s;
        ????????
        ????????&::before?{
        ????????????content:?nth($expression,?random(length($expression)));
        ????????????position:?absolute;
        ????????}
        ????}
        ????
        ????li:active?{
        ????????opacity:?1;
        ????????transition:?.1s?opacity;
        ????}
        }

        @keyframes?move?{
        ????100%?{
        ????????transform:?rotate(0)?translate(0,?-250px);
        ????}
        }

        效果如下:

        93a4384a12af44a041382af9b6d59134.webp

        嘿,是不是有那么點意思了!

        好最后一步,我們通過一個點擊按鈕引導用戶點擊,并且給與一個點擊反饋,每次點擊的時候,點贊按鈕放大 1.1 倍,同時,我們把默認表情的透明度從 opacity: 0.1 徹底改為 opacity: 0。

        這樣,整個動畫的完整的核心代碼:

        <ul?class="g-wrap">
        ????<li></li>
        ????<li></li>
        ????<li></li>
        ????//?...?共50個空標簽
        </ul>
        $expression:?"??",?"??",?"??",?"??",?"??",?"??",?"??",?"??",?"????",?"??",?"??",?"??",?"??",?"??";
        .g-wrap?{
        ????position:?relative;
        ????width:?50px;
        ????height:?50px;
        ????&::before?{
        ????????content:?"????";
        ????????position:?absolute;
        ????????width:?50px;
        ????????height:?50px;
        ????????transition:?0.1s;
        ????}
        ????&:active::before?{
        ????????transform:?scale(1.1);
        ????}
        }

        @for?$i?from?1?to?51?{
        ????li:nth-child(#{$i})?{
        ????????position:?absolute;
        ????????width:?50px;
        ????????height:?50px;
        ????????transform:?rotate(#{random()?*?80?-?40}deg);
        ????????animation:?move?#{random()?*?2500?+?1500}ms?infinite?#{random()?*?4000?/?-1000}s?cubic-bezier(.46,.53,.51,.62);
        ????????opacity:?0;
        ????????transition:?1.5s?opacity?.8s;
        ????????&::before?{
        ????????????content:?nth($expression,?random(length($expression)));
        ????????????position:?absolute;
        ????????}
        ????}
        ????li:active?{
        ????????transition:?.1s?opacity;
        ????????opacity:?1!important;
        ????}
        }
        @keyframes?move?{
        ????100%?{
        ????????transform:?rotate(0)?translate(0,?-250px);
        ????}
        }

        這里,需要注意的是:

        1. 點贊的按鈕,通過了父元素 .g-wrap 的偽元素實現,這樣的好處是,子元素 li 的 :active 點擊事件,是可以冒泡傳給父元素的,這樣每次子元素被點擊,我們都可以放大一次點贊按鈕,用于實現點擊反饋。
        2. 稍微修改一下緩動函數,讓整體效果更為均衡合理

        這樣,我們就得到了題圖一開始的效果,利用純 CSS 實現的點贊動畫:

        79d523164172934ab58b45f0c823bda4.webp

        完整的代碼,你可以戳這里:CodePen Demo -- Like Animation[2]

        一點瑕疵

        當然,這個方案是有一點點問題的。

        1. 就是如果當點擊的速率過快,是無法實現一個點擊,產生一個表情的

        這是由于 CSS 方案的本質是通過點擊一個透明表情,讓它變成不透明。而點擊過快的話,會導致兩次或者多次點擊,點在了同一個元素上,這樣,就無法實現一個點擊,產生一個表情。所以上面代碼中修改緩動 cubic-bezier(.46,.53,.51,.62) 的目的也是在于,讓元素動畫前期運動更快,這樣可以有利于適配更快的點擊速率。

        1. 不僅僅是點擊按鈕,點擊按鈕上方也能出現效果

        這樣也很好理解,由于本質是個障眼法,所以點擊按鈕上方,只要是元素運動路徑的地方,也是會有元素顯形的。這個硬要解決也可以,通過再疊加一層透明元素在按鈕上方,通過層級關系屏蔽掉點擊事件。

        1. 表情的隨機只是偽隨機

        利用 SASS 隨機的方案在經過編譯后是不會產生隨機效果的。所以,這里只能是偽隨機,基于 DOM 的個數,當 DOM 數越多,整體而言,隨機的效果越好?;旧?50 個 DOM 是比較足夠的。

        1. CSS 版本的點贊效果是單機版

        無法多用戶聯(lián)動,可能是影響能不能實際使用最為關鍵的因素。

        不過,總而言之,使用純 CSS 實現的方案,整體效果還是不錯的。

        最后

        怎樣,其實也不是很難吧?好了,本文到此結束,希望本文對你有所幫助 :)

        如果還有什么疑問或者建議,可以多多交流,原創(chuàng)文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

        參考資料

        [1]

        深入淺出 CSS 動畫: https://github.com/chokcoco/iCSS/issues/141

        [2]

        CodePen Demo -- Like Animation: https://codepen.io/Chokcoco/pen/WNzJooB


        前端 社群



        下方加 Nealyang 好友回復「 加群」即可。



        如果你覺得這篇內容對你有幫助,我想請你幫我2個小忙:

        1. 點個「在看」,讓更多人也能看到這篇文章

        點贊和在看就是最大的支持

        瀏覽 66
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 李采潭三点尽露三级 | 一本久久精品一区二区 | 久久夜色精品国产欧美一区麻豆 | 亚洲第一AV| 女s的女m女女系列vk |