純 CSS 實現波浪效果!

2021-02-19 前端大全

(點擊上方公眾號,可快速關注)

作者:伯樂在線/chokcoco

http://web.jobbole.com/91803/

如有好文章投稿,請點擊 → 這裡了解詳情

而使用純 CSS 的方式,實現貝塞爾曲線,額,暫時是沒有很好的方法。

當然,藉助其他力量(SVG、CANVAS),是可以很輕鬆的完成所謂的波浪效果的,先看看,非 CSS 方式實現的波浪效果。

使用 SVG 實現波浪效果

藉助 SVG ,是很容易畫出三次貝塞爾曲線的。

看看效果:

代碼如下:

<svg width="200px" height="200px" version="1.1" xmlns="http://www.w3.org/2000/svg">

    <text class="liquidFillGaugeText" text-anchor="middle" font-size="42px" transform="translate(100,120)" style="fill: #000">50.0%</text>

    <!-- Wave -->

    <g id="wave">

        <path id="wave-2" fill="rgba(154, 205, 50, .8)" d="M 0 100 C 133.633 85.12 51.54 116.327 200 100 A 95 95 0 0 1 0 100 Z">

        <animate dur="5s" repeatCount="indefinite" attributeName="d" attributeType="XML" values="M0 100 C90 28, 92 179, 200 100 A95 95 0 0 1 0 100 Z;

                                    M0 100 C145 100, 41 100, 200 100 A95 95 0 0 1 0 100 Z;

                                    M0 100 C90 28, 92 179, 200 100 A95 95 0 0 1 0 100 Z"></animate>

        </path>

    </g>

    <circle cx="100" cy="100" r="80" stroke-width="10" stroke="white" fill="transparent"></circle>

    <circle cx="100" cy="100" r="90" stroke-width="20" stroke="yellowgreen" fill="none" class="percentage-pie-svg"></circle>

</svg>

SVG demo(https://codepen.io/Chokcoco/pen/MoRGYj)

畫出三次貝塞爾曲線的核心在於

<path id="wave-2" fill="rgba(154, 205, 50, .8)" d="M 0 100 C 133.633 85.12 51.54 116.327 200 100 A 95 95 0 0 1 0 100 Z">

 這一段。感興趣的可以自行去研究研究。

使用 canvas 實現波浪效果

使用 canvas 實現波浪效果的原理與 SVG 一樣,都是利用路徑繪製出三次貝塞爾曲線並賦予動畫效果。

使用 canvas 的話,代碼如下:

$(function() {

    let canvas = $("canvas");

    let ctx = canvas[0].getContext('2d');

    let radians = (Math.PI / 180) * 180;

    let startTime = Date.now();

    let time = 2000;

    let clockwise = 1;

    let cp1x, cp1y, cp2x, cp2y;

    

    // 初始狀態

    // ctx.bezierCurveTo(90, 28, 92, 179, 200, 100);

    // 末尾狀態

    // ctx.bezierCurveTo(145, 100, 41, 100, 200, 100);

    

    requestAnimationFrame(function waveDraw() {  

        let t = Math.min(1.0, (Date.now() - startTime) / time);

          

        if(clockwise) {

            cp1x = 90 + (55 * t);

            cp1y = 28 + (72 * t);

            cp2x = 92 - (51 * t);

            cp2y = 179 - (79 * t);

        } else {

            cp1x = 145 - (55 * t);

            cp1y = 100 - (72 * t);

            cp2x = 41 + (51 * t);

            cp2y = 100 + (79 * t);

        }

        

        ctx.clearRect(0, 0, 200, 200);

        ctx.beginPath();

        ctx.moveTo(0, 100);

        // 繪製三次貝塞爾曲線

        ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, 200, 100);

        // 繪製圓弧

        ctx.arc(100, 100, 100, 0, radians, 0);

        ctx.fillStyle = "rgba(154, 205, 50, .8)";

        ctx.fill();

        ctx.save();  

        

        if( t == 1 ) {

            startTime = Date.now();

            clockwise = !clockwise;

        }

 

        requestAnimationFrame(waveDraw);

    });

})

canvas demo(https://codepen.io/Chokcoco/pen/OgGEBx)

主要是利用了動態繪製 ctx.bezierCurveTo() 三次貝塞爾曲線實現波浪的運動效果,感興趣的可以自行研究。

純 CSS 實現波浪效果

好,接下來才是本文的重點!使用純 CSS 的方式,實現波浪的效果。

你 TM 在逗我?剛剛不是還說使用 CSS 無能為力嗎?

是,我們沒有辦法直接繪製出三次貝塞爾曲線,但是我們可以利用一些討巧的方法,模擬達到波浪運動時的效果,姑且把下面這種方法看作一種奇技淫巧。

原理

原理十分簡單,我們都知道,一個正方形,給它添加 border-radius: 50%,將會得到一個圓形。

border-radius:用來設置邊框圓角,當使用一個半徑時確定一個圓形。

好的,如果 border-radius 沒到 50%,但是接近 50% ,我們會得到一個這樣的圖形:

注意邊角,整個圖形給人的感覺是有點圓,卻不是很圓。額,這不是廢話嗎

好的,那整這麼個圖形又有什麼用?還能變出波浪來不成?

沒錯!就是這麼神奇。:) 我們讓上面這個圖形滾動起來(rotate) ,看看效果:

可能很多人看到這裡還沒懂旋轉起來的意圖,仔細盯著一邊看,是會有類似波浪的起伏效果的。

而我們的目的,就是要藉助這個動態變換的起伏動畫,模擬製造出類似波浪的效果。

實現

當然,這裡看到是全景實現圖,所以感覺並不明顯,OK,讓我們用一個個例子看看具體實現起來能達到什麼樣的效果。

我們利用上面原理可以做到的一種波浪運動背景效果圖:

後面漂浮的波浪效果,其實就是利用了上面的 border-radius: 45% 的橢圓形,只是放大了很多倍,視野之外的圖形都 overflow: hidden ,只留下了一條邊的視野,並且增加了一些相應的 transform 變換。

注意,這裡背景是藍色靜止的,運動是白色的橢圓形。

代碼也很簡單,SCSS 代碼如下:

body {

    position: relative;

    align-items: center;

    min-height: 100vh;

    background-color: rgb(118, 218, 255);

    overflow: hidden;

 

    &:before, &:after {

        content: "";

        position: absolute;

        left: 50%;

        min-width: 300vw;

        min-height: 300vw;

        background-color: #fff;

        animation-name: rotate;

        animation-iteration-count: infinite;

        animation-timing-function: linear;

    }

 

    &:before {

        bottom: 15vh;

        border-radius: 45%;

        animation-duration: 10s;

    }

 

    &:after {

        bottom: 12vh;

        opacity: .5;

        border-radius: 47%;

        animation-duration: 10s;

    }

}

 

@keyframes rotate {

    0% {

        transform: translate(-50%, 0) rotateZ(0deg);

    }

    50% {

        transform: translate(-50%, -2%) rotateZ(180deg);

    }

    100% {

        transform: translate(-50%, 0%) rotateZ(360deg);

    }

}

為了方便寫 DEMO,用到的長度單位是 VW 與 VH,不太了解這兩個單位的可以戳這裡:vh、vw、vmin、vmax 知多少(https://github.com/chokcoco/iCSS/issues/15)

CSS demo(https://codepen.io/Chokcoco/pen/OgGEBx)

可能有部分同學,還存在疑問,OK,那我們把上面的效果縮小 10 倍,將視野之外的動畫也補齊,那麼其實生成波浪的原理是這樣的:

圖中的虛線框就是我們實際的視野範圍。

值得探討的點

值得注意的是,要看到,這裡我們生成波浪,並不是利用旋轉的橢圓本身,而是利用它去切割背景,產生波浪的效果。那為什麼不直接使用旋轉的橢圓本身模擬波浪效果呢?因為

中間高,兩邊低的效果不符合物理學原理,看上去十分彆扭;

可以點進去看看下面這個例子:

CodePen Demo — pure css wave(https://codepen.io/Chokcoco/pen/xreWZV)

使用純 CSS 實現波浪進度圖

好,既然掌握了這種方法,下面我們就使用純 CSS 實現上面最開始使用 SVG 或者 CANVAS 才能實現的波浪進度圖。

HTML 結構如下:

<div class="container">

    <div class="wave"/>

</div>

CSS 代碼如下:

.wave {

    position: relative;

    width: 200px;

    height: 200px;

    background-color: rgb(118, 218, 255);

    border-radius: 50%;

    &::before,

    &::after{

        content: "";

        position: absolute;

        width: 400px;

        height: 400px;

        top: 0;

        left: 50%;

        background-color: rgba(255, 255, 255, .4);

        border-radius: 45%;

        transform: translate(-50%, -70%) rotate(0);

        animation: rotate 6s linear infinite;

        z-index: 10;

    }

    

    &::after {

        border-radius: 47%;

        background-color: rgba(255, 255, 255, .9);

        transform: translate(-50%, -70%) rotate(0);

        animation: rotate 10s linear -5s infinite;

        z-index: 20;

    }

}

 

@keyframes rotate {

    50% {

        transform: translate(-50%, -73%) rotate(180deg);

    } 100% {

        transform: translate(-50%, -70%) rotate(360deg);

    }

}

效果圖:

CodePen Demo — Pure Css Wave Loading(https://codepen.io/Chokcoco/pen/EXJrdB

雖然效果差了一點點,但是相較於要使用學習成本更高的 SVG 或者 CANVAS,這種純 CSS 方法無疑可使用的場景更多,學習成本更低!

一些小技巧

單純的讓一個 border-radius 接近 50 的橢圓形旋轉,動畫效果可能不是那麼好,我們可以適當的添加一些其他變換因素,讓動畫效果看上去更真實:

在動畫過程中,動態的改變 border-radius 的值;

在動畫過程中,利用 transform 對旋轉橢圓進行輕微的位移、變形;

上面也演示到了,多個橢圓同時轉動,賦予不同時長的動畫,並且添加輕微的透明度,讓整個效果更佳逼真。

 

最後

系列 CSS 文章匯總在我的 Github(https://github.com/chokcoco/iCSS) ,持續更新,歡迎點個 star 訂閱收藏。

好了,本文到此結束,希望對你有幫助 :)

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

覺得本文對你有幫助?請分享給更多人

關注「前端大全」,提升前端技能

相關焦點

  • 厲害了-純 CSS 實現波浪效果!
    一直以來,使用純 CSS 實現波浪效果都是十分困難的。因為實現波浪的曲線需要藉助貝塞爾曲線。而使用純 CSS 的方式,實現貝塞爾曲線,額,暫時是沒有很好的方法。使用 canvas 實現波浪效果使用 canvas 實現波浪效果的原理與 SVG 一樣,都是利用路徑繪製出三次貝塞爾曲線並賦予動畫效果。
  • 純 CSS 實現波浪效果
    使用純 CSS 實現波浪效果不再困難,CSS 奇技淫巧。
  • 《前端5分鐘》之使用純css實現網站換膚和焦點圖切換動畫
    你將收穫網站換膚設計方案介紹:target偽類介紹和用法以及如何使用css實現網站換膚transition動畫以及如何用純css實現焦點圖動畫效果展示1.網站換膚2.焦點圖動畫>實現思路1.網站換膚通常我們實現網站換膚都基於如下方式實現:方案一: 使用OOCSS模式,通過js動態切換公共類名來達到換膚效果方案二: 點擊不同的按鈕切換不同的樣式表,如下:theme-green.csstheme-red.csstheme-black.css方案三
  • 純css實現循環跑馬燈
    經常在一些抽獎活動頁面看到一些獎池獎品不停循環滾動的場景(比如b站會員購魔力賞的獎品循環),如果用純css實現應該是怎樣的呢?
  • 巧用CSS cross-fade(.)實現背景圖像半透明效果
    前段時間有挺火的一個小遊戲,拿兩張圖片疊加在一起,看看複合人物的效果,用css怎麼實現呢?可能大部分人想到的是將兩個img用定位的方式疊加在一起,分別設置透明度,當然這個辦法是可行的,其實css還提供了一個cross-fade()方法,講兩張圖片作為背景圖引入,可以實現相同的效果。
  • 逼真版仿英雄聯盟純html+css+jqueryLOL網頁版
    當然同時我也是一個喜歡挑戰的孩子哈哈哈……頁面實現效果圖首頁:當登錄成功之後,跳轉到當前頁面的時候,首先彈出一層廣告。輪播圖,及好友列表那因為是純html頁面做的,也沒有資料庫。所以這裡用了比較蠢的辦法。就是加載的時候,所有英雄卡片img標籤都顯示出來,且每個標籤都有每個英雄的p標籤標識。然後搜索的時候使用JQuery 選擇器來找到標識與搜索文本框的值去匹配。匹配成功之後,那麼就show()出來 沒有達到條件的就hide()。思路2:滑鼠移入卡片的JQuery事件:移入顯示每個img英雄標識的相關信息。
  • 非JS用CSS實現hover顯示標題效果
    現在,我們可以通過CSS3特效來實現懸停彈出效果。這是一個有趣的事情,讓我們放棄了更多的JS。但是,很多時候我們都忘記了CSS2.1給我們帶來的美好效果。因為它具有非常好的瀏覽器支持,我們可以做很多特效以便兼容目前所有主流瀏覽器。
  • 如何用純css打造類materialUI的按鈕點擊動畫並封裝成react組件
    正文首先我們看一下materialUI的按鈕點擊效果:本質上也是用了css3動畫的特性, 筆者查看原始碼和通過點擊發現materialUI會根據點擊位置不同而作不同位置的動畫,這個有點意思.我們先不講這麼複雜的例子,下面通過css3的方案來實現一個類似的效果.筆者實現的效果如下:
  • 前端進階:css必知的幾個底層知識和技巧
    一.css尺寸1.首選最小寬度–實現複雜圖形效果在css中,圖片和文字的權重遠大於布局,因此當width:0時表現出來的寬度就是「首選最小寬度」。中文的最小寬度為每個漢字的寬度,西方文字取決於連續的英文字符單元。
  • css動畫 | 實現小球下落動畫
    知識點:animation關鍵點:小球下落與上升,ease-in與ease-out效果如下DOCTYPE html><html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> html,body{ margin: 0; padding: 0;
  • 一個在線css三角形生成器
    (上班摸魚也成了可能, 確實很多時候就是不想寫代碼還想要有錢拿) 在文末筆者會附上css工具的在線地址, 接下來我們來看看具體實現流程.實現css三角形生成器因為這個工具的需求來自於前端, 所以肯定是要對css和js編程有一定的基礎, 比如css3的
  • 30 CSS的4種編寫方式
    這裡是把h1標籤的文字設置成紅色,瀏覽器中效果如下:2 外鏈式所謂外鏈式,就是把CSS代碼保存在單獨的.css文件中,然後用<link>標籤引入這個文件。比如,我在項目文件夾中,創建一個"外鏈式.html"文件,再在css文件夾中創建一個"css.css"文件。然後在"css.css"這個文件中寫css代碼,在.css文件中寫css代碼,就不需要寫style標籤了,直接寫css語句就行了。
  • CSS+DIV常見的三種元素定位方式,你知道幾個?
    css中元素的定位複雜的網頁布局都是通過各種網頁元素靈活定位實現的,網頁中的各種元素定位都有自己的特點。今天為大家聊一下css中常用的三種定位方法。這裡說的定位不是table排版的,而是通過DIV+CSS的方法對頁面中的塊元素的定位。
  • 有趣的CSS題目(11):reset.css 知多少?
    ,但是有深究過reset.css 每一句的人恐怕不多,其實其中也是有很多學問的,知己知彼,真正釐清它,對提高 CSS 大有裨益。所以,YUI 的 reset.css 的諸多問題,催生出了另一個版本的 reset.css ,名為 Normalize.css。Normalize.cssNormalize.css 有著詳盡的注釋,由於篇幅太長,可以點開網址看看,本文不貼出全部代碼。
  • 使用HTML DIV+CSS樣式+JavaScript實現自定義個性化的模態窗口
    <html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title></title><style type="text/css
  • css padding屬性設置元素內邊距
    padding屬性定義及用法在css中,padding屬性是一個簡寫屬性,用來設置所有內邊距屬性(填充),將上邊距屬性、右邊距屬性、下邊距屬性、左邊距屬性定義在同一個聲明中。DOCTYPE html><html><head><meta charset="utf-8" /><title>css padding屬性設置元素內邊距</title><style type="text/css">div{width:260px;border:1px solid #000
  • 這裡有一些CSS中文排版技巧,值得收藏!
    文字排版 字體 我們可以使用css可以使用text-align樣式代碼,如下代碼可實現文本居中顯示。了不起的蓋茨比 還可以設置居右: h1{ text-align:right; } 了不起的蓋茨比 圖文環繞 在css
  • HTML技巧篇:實現元素水平與垂直居中的幾種方式
    本篇文章主要給大家介紹一下如何使用html+css實現元素的水平與垂直居中效果,這也是我們網頁在編碼製作中會經常用到的問題。200px;就可以實現文字的居中效果,具體的代碼如下所示:由上圖可以看出我們實現了單行文字的垂直居中效果,但是很多時候我們的文字並不知道具體有多少,可能有一行,也可能有很多行,那麼遇到多行文字的這種問題我們要如何處理呢。
  • css list-style-type屬性筆記
    list-style-type屬性定義及用法在css中,list-style-type屬性是使用來設置列表項標記的類型,在有序列表和無序列表中經常都會使用該屬性。"inherit";如果需要同時設置多個列表屬性,可以使用list-style屬性,list-style屬性可以在一個聲明中同時設置list-style-type(列表項標記的類型), list-style-position(何處放置列表項標記), list-style-image(圖像來替換列表項的標記)屬性;list-style-type屬性語法格式css
  • 精通react/vue組件設計教你實現一個極具創意的加載(Loading)組件
    正文在開始組件設計之前希望大家對css3和js有一定的基礎,並了解基本的react/vue語法.我們先看看實現後的組件效果:因為動圖體積太大,就不給大家傳gif了,接下來我們具體分析一下該組件的特點.1.