直以來,使用純 CSS 實現波浪效果都是十分困難的。
因為實現波浪的曲線需要借助貝塞爾曲線。
而使用純 CSS 的方式,實現貝塞爾曲線,額,暫時是沒有很好的方法。
當然,借助其他力量(SVG、CANVAS),是可以很輕松的完成所謂的波浪效果的,先看看,非 CSS 方式實現的波浪效果。
借助 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>
畫出三次貝塞爾曲線的核心在于這一段。感興趣的可以自行去研究研究。
使用 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);
});
})
主要是利用了動態繪制 ctx.bezierCurveTo() 三次貝塞爾曲線實現波浪的運動效果,感興趣的可以自行研究。
好,接下來才是本文的重點!使用純 CSS 的方式,實現波浪的效果。
你 TM 在逗我?剛剛不是還說使用 CSS 無能為力嗎?
是,我們沒有辦法直接繪制出三次貝塞爾曲線,但是我們可以利用一些討巧的方法,模擬達到波浪運動時的效果,姑且把下面這種方法看作一種奇技淫巧。
原理十分簡單,我們都知道,一個正方形,給它添加 border-radius: 50%,將會得到一個圓形。
border-radius:用來設置邊框圓角,當使用一個半徑時確定一個圓形。
好的,如果 border-radius 沒到 50%,但是接近 50% ,我們會得到一個這樣的圖形:
注意邊角,整個圖形給人的感覺是有點圓,卻不是很圓。額,這不是廢話嗎
好的,那整這么個圖形又有什么用?還能變出波浪來不成?
沒錯!就是這么神奇。:) 我們讓上面這個圖形滾動起來(rotate) ,看看效果:
可能很多人看到這里還沒懂旋轉起來的意圖,仔細盯著一邊看,是會有類似波浪的起伏效果的。
而我們的目的,就是要借助這個動態變換的起伏動畫,模擬制造出類似波浪的效果。
當然,這里看到是全景實現圖,所以感覺并不明顯,OK,讓我們用一個個例子看看具體實現起來能達到什么樣的效果。
我們利用上面原理可以做到的一種波浪運動背景效果圖:
CodePen Demo -- Pure CSS Wave[1]
后面漂浮的波浪效果,其實就是利用了上面的 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 知多少[2]
可能有部分同學,還存在疑問,OK,那我們把上面的效果縮小 10 倍,將視野之外的動畫也補齊,那么其實生成波浪的原理是這樣的:
圖中的虛線框就是我們實際的視野范圍。
值得注意的是,要看到,這里我們生成波浪,并不是利用旋轉的橢圓本身,而是利用它去切割背景,產生波浪的效果。那為什么不直接使用旋轉的橢圓本身模擬波浪效果呢?因為中間高,兩邊低的效果不符合物理學原理,看上去十分別扭;
可以點進去看看下面這個例子:
CodePen Demo -- pure css wave[3]
好,既然掌握了這種方法,下面我們就使用純 CSS 實現上面最開始使用 SVG 或者 CANVAS 才能實現的波浪進度圖。
HTML 結構如下:
<div class="container">
<div class="wave"></div>
</div>
.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[4]
雖然效果差了一點點,但是相較于要使用學習成本更高的 SVG 或者 CANVAS,這種純 CSS 方法無疑可使用的場景更多,學習成本更低!
還能實現類似這樣的充電效果:
單純的讓一個 border-radius 接近 50 的橢圓形旋轉,動畫效果可能不是那么好,我們可以適當的添加一些其他變換因素,讓動畫效果看上去更真實:
提起圖標,大家可能第一個會想到PS、美工等詞語,但很多小圖標現在根本都不需要再打開PS了。
1、常見的括號( 前進或后退“>” )
.arrow{
width:12rpx;
height:12rpx;
border-top:1px solid #999;
border-right:1px solid #999;
transform:rotate(-45deg);
position:absolute;
right:10px;
}
2、常見的關閉按鈕( “X” ),這里需要用到一個偽類
.close {
display: inline-block;
width: 30px;
height: 4px;
background: #333;
transform: rotate(45deg);
}
.close::after {
content: '';
display: block;
width: 30px;
height: 4px;
background: #333;
transform: rotate(-90deg);
}
3、常見的勾選( “√” )
.check {
position: relative;
display: inline-block;
width: 25px;
height: 25px;
background: #333;
border-radius: 25px;
}
.check::after {
content: "";
position: absolute;
left: 5px;
top: 8px;
width: 50%;
height: 25%;
border: 2px solid #fff;
border-radius: 1px;
border-top: none;
border-right: none;
background: transparent;
transform: rotate(-45deg);
}
4、常見的加號( “+” ),同樣需要利用偽類
.add {
width: 100px;
height: 100px;
color: #ccc;
transition: color .25s;
position: relative;
}
.add::before{
content: '';
position: absolute;
left: 50%;
top: 50%;
width: 80px;
margin-left: -40px;
margin-top: -5px;
border-top: 10px solid;
}
.add::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
height: 80px;
margin-left: -5px;
margin-top: -40px;
border-left: 10px solid;
}
5、常見的波浪線( “~” ),同樣需要利用偽類
.info::before {
content: '';
position: absolute;
top: 30px;
width: 100%;
height: 0.25em;
background:
linear-gradient(
135deg,
transparent,
transparent 45%,
#008000,
transparent 55%,
transparent 100%
),
linear-gradient(
45deg,
transparent,
transparent 45%,
#008000,
transparent 55%,
transparent 100%
);
background-size: 0.5em 0.5em;
background-repeat: repeat-x, repeat-x;
}
5、常見的三角形
.triangle-up {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}
6、常見的扇形
.sector {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-top: 100px solid #f00;
border-radius: 50%;
}
7、仿微信對話框
.alertDialog {
/* 對話框:一個圓角矩形和一個小三角形 */
width: 150px;
height: 100px;
background: #f00;
border-radius: 10px;
position: relative;
}
.alertDialog:before {
content: "";
width: 0;
height: 0;
position: absolute;
left: -20px;
top: 40px;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-right: 20px solid #f00;
}
8、鉆石圖標
.diamond {
/* 鉆石:梯形和三角形組成 */
width: 50px;
height: 0;
position: relative;
border-bottom: 25px solid #f00;
border-left: 25px solid transparent;
border-right: 25px solid transparent;
}
.diamond:before {
content: "";
width: 0;
height: 0;
position: absolute;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-top: 70px solid #f00;
left: -25px;
top: 25px;
}
9、五角星圖標
.starFive {
width: 0;
height: 0;
position: relative;
border-left: 80px solid transparent;
border-right: 80px solid transparent;
border-bottom: 60px solid #f00;
transform: rotate(35deg);
}
.starFive:before {
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 80px solid transparent;
border-right: 80px solid transparent;
border-bottom: 60px solid #f00;
transform: rotate(-70deg);
top: 3px;
left: -80px;
}
.starFive:after {
content: "";
position: absolute;
width: 0;
height: 0;
border-bottom: 60px solid #f00;
border-right: 20px solid transparent;
border-left: 20px solid transparent;
transform: rotate(-35deg);
top: -40px;
left: -49px;
}
喜歡的可以加個關注,不定期發布更多CSS相關文章
1)背景樣式屬性,用于定義 HTML 元素的背景色、背景圖片,同時還可以進行背景定位、背景圖片重復、背景圖片固定。
background-color 屬性可以給指定標簽元素設置背景色。
舉個例子! 我們給 body 元素設置一個背景顏色:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background-color: yellowgreen;
}
</style>
</head>
<body></body>
</html>
background-image 屬性可以把圖像插入背景。background-size 屬性可以給背景圖設置大小。
舉個例子! 我們給 body 元素設置一個背景圖像。
wget https://labfile.oss.aliyuncs.com/courses/3773/moon.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background-image: url("moon.jpg");
background-size: 300px 300px;
}
</style>
</head>
<body></body>
</html>
通過 background-position 屬性,可以改變圖像在背景中的位置。
background-position 屬性,設置屬性值為居中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background-image: url("moon.jpg");
background-size: 300px 300px;
background-position: center;
}
</style>
</head>
<body></body>
</html>
background-repeat 屬性是用來設置背景圖像是否平鋪。
下表列出了 background-repeat 屬性的一些可取值以及每個可取值的含義。
可 取 值 | 描 述 |
repeat | 背景圖像將在垂直方向和水平方向重復(默認值) |
repeat-x | 背景圖像將在水平方向重復 |
repeat-y | 背景圖像將在垂直方向重復 |
no-repeat | 背景圖像將僅顯示一次 |
我們規定應該從父元素繼承 background-repeat 屬性的設置。
background-repeat 屬性并設置值為不平鋪:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
background-image: url("moon.jpg");
background-size: 300px 300px;
background-position: center;
background-repeat: no-repeat;
}
</style>
</head>
<body></body>
</html>
(2)文本相關的屬性:
文本屬性用于定義文本的樣式,通過文本屬性,可以改變文本的顏色、字間距、對齊方式、文本修飾和文本縮進等。常用文本屬性如下表所示:
屬 性 | 可 取 值 | 描 述 |
line-height | normal、number、length、% | 設置行高 |
text-indent | length、% | 設置文本縮進 |
text-align | left、right、center、justify、start、end | 設置對齊方式 |
letter-spacing | normal、length | 設置字符間距 |
text-decoration | line、color、style、thickness | 設置文本修飾 |
white-space | normal、pre、nowrap、pre-wrap、pre-line、break-spaces | 規定如何處理空白 |
line-break | auto、loose、normal、strict、anywhere、unset | 處理如何斷開帶有標點符號的文本的行 |
line-height 用于設置多行元素的空間量,可取值具體說明如下:
例子,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>line-height 的使用</title>
<style>
div {
width: 300px;
height: 400px;
border: 1px solid;
font-size: 15px;
display: inline-block;
vertical-align: top;
}
.div1 {
line-height: 2; /*15 * 2*/
}
.div2 {
line-height: 30%; /*15 * 30% */
}
</style>
</head>
<body>
<div class="div1">
<p>“海水呀,你說的是什么?”</p>
<p>“是永恒的疑問?!?lt;/p>
<p>“天空呀,你回答的話是什么?”</p>
<p>“是永恒的沉默?!?lt;/p>
</div>
<div class="div2">
<p>“海水呀,你說的是什么?”</p>
<p>“是永恒的疑問。”</p>
<p>“天空呀,你回答的話是什么?”</p>
<p>“是永恒的沉默?!?lt;/p>
</div>
</body>
</html>
顯示為,
*請認真填寫需求信息,我們會在24小時內與您取得聯系。