前言
??SVG 實現擬物態圓環進度條,速速來Get吧~
??文末分享源代碼。記得點贊+關注+收藏!
1.實現效果
在這里插入圖片描述
2.實現步驟
- 定義一個圓角矩形作為父容器,背景色為--bg
在這里插入圖片描述
--bg: #edf1f5;
<div class="container"></div>
.container {
padding: 30px;
border-radius: 20px;
background: var(--bg);
box-shadow: 0px 20px 30px rgba(100, 131, 177, 0.2);
border: 1px solid #fff;
}
- 父容器添加一個正方形,寬高w
在這里插入圖片描述
/* 寬度 */
--w: 200px;
<div class="container-box" ></div>
.container-box {
position: relative;
width: var(--w);
height: var(--w);
border: 1px solid red;
}
- 在container-box容器中添加一個圓形,寬高為100%,基于父元素absolute定位,left為0,top為0,添加box-shadow陰影,定義陰影變量--back-bg和--back-shadow
在這里插入圖片描述
--back-bg: #c5ccda;
--back-shadow: #ffffff;
<div class="circle-outer"></div>
.circle-outer {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 6px 6px 8px var(--back-bg), -6px -6px 8px var(--back-shadow);
background: var(--bg);
}
- 為circle-outer添加前偽元素,用該偽元素實現一個圓形,定義css變量gap,表示該圓形與父元素之前的距離
在這里插入圖片描述
/* 父容器gap*/
--gap: 30px;
- 那么可以算出circle-outer前偽元素的寬高為--inner,即calc(var(--w) - var(--gap))
在這里插入圖片描述
/* 第二層圓形寬度 */
--inner: calc(var(--w) - var(--gap));
.circle-outer::before {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: var(--bg);
width: var(--inner);
height: var(--inner);
box-shadow: inset 8px 8px 10px var(--back-bg),
inset -4px -4px 8px var(--back-shadow);
}
- 在container-box容器中添加svg,寬高為父元素的100%,基于父元素absolute定位
可縮放矢量圖形(Scalable Vector Graphics,SVG)基于 XML 標記語言,用于描述二維的矢量圖形
svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
//旋轉90deg
transform: rotate(-90deg);
}
- svg中添加defs
SVG 允許我們定義以后需要重復使用的圖形元素。建議把所有需要再次使用的引用元素定義在defs元素里面。這樣做可以增加 SVG 內容的易讀性和無障礙。在defs元素中定義的圖形元素不會直接呈現。你可以在你的視口的任意地方利用 <use>元素呈現這些元素。
- defs中定義一個radialGradient
radialGradient:
radialGradient 用來定義徑向漸變,以對圖形元素進行填充或描邊。
- 定義兩個顏色,表示radialGradient的色值,即環形的色值
--ring-color1: #c1dfc4;
--ring-color2: #3cba92;
<defs>
<radialGradient
id="gradient"
cx="50%"
cy="50%"
r="60%"
fx="50%"
fy="50%"
>
<stop offset="30%" stop-color="var(--ring-color2)" />
<stop offset="100%" stop-color="var(--ring-color1)" />
</radialGradient>
</defs>
- 在svg中添加circle,stroke為上述定義的radialGradient
circle:
<circle> SVG 元素是一個 SVG 的基本形狀,用來創建圓,基于一個圓心和一個半徑。
cx 屬性定義一個中心點的 x 軸坐標。
cy 屬性定義一個中心點的 y 軸坐標。
r 屬性用來定義圓的半徑。
<circle stroke="url(#gradient)" id="circle"></circle>
- 這里我們先說明幾個字段的意義
stroke-width:
stroke-width屬性指定了當前對象的輪廓的寬度。它的默認值是1。如果使用了一個<percentage>,這個值代表當前視口的百分比。如果使用了0值,則將不繪制輪廓。
stroke-dasharray:
屬性 stroke-dasharray 可控制用來描邊的點劃線的圖案范式。作為一個外觀屬性,它也可以直接用作一個 CSS 樣式表內部的屬性。
eg:
stroke-dasharray = 20 表示:虛線長20,間距20,然后重復 虛線長20,間距20
stroke-dashoffset:
stroke-dashoffset 屬性指定了 dash 模式到路徑開始的距離,偏移的意思
- 定義css變量stroke,表示stroke-width,定義--circle表示svg中circle的寬高,由下圖可以得到--circle為calc(var(--inner) - var(--stroke))
在這里插入圖片描述
/* 環形stroke寬度 */
--stroke: 20px;
/* svg環形寬度 */
--circle: calc(var(--inner) - var(--stroke));
- 為cricle添加樣式,基于svg水平垂直居中,根據css變量設置cx,cy,r,stroke-dasharray為圓的周長,即3.14*圓的直徑(--circle)
- 這里先設置stroke-dashoffset為任意值,當stroke-dashoffset與stroke-dasharray相等的時候,將不顯示內容,stroke-dashoffset設置的越小,顯示內容越多,當為0時候,顯示全部
在這里插入圖片描述
svg circle {
position: absolute;
//設置垂直居中
--z: calc(var(--w) / 2);
--c: calc(var(--circle) / 2);
transform: translate(
calc(var(--z) - var(--c)),
calc(var(--z) - var(--c))
);
cy: calc(var(--circle) / 2);
cx: calc(var(--circle) / 2);
r: calc(var(--circle) / 2);
fill: none;
stroke-linecap: round;
stroke-dasharray: calc(3.14 * var(--circle));
stroke-dashoffset: 250;
stroke-width: var(--stroke);
}
- 為circle-outer添加后偽元素,用該偽元素實現一個圓形
在這里插入圖片描述
- 那么可以算出circle-outer后偽元素的寬高為--center,即calc(var(--circle) - var(--stroke))
在這里插入圖片描述
/* 第三層圓形寬度 */
--center: calc(var(--circle) - var(--stroke));
.circle-outer::after {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: var(--bg);
width: var(--center);
height: var(--center);
box-shadow: 6px 6px 8px var(--back-bg), -2px -2px 8px var(--back-shadow);
}
- 為container-box添加偽元素,顯示當前百分比,標簽內定義data-num,去掉輔助邊框,有模有樣了哈~
在這里插入圖片描述
<div class="container-box" data-num="--" >
...
</div>
.container-box::after {
content: attr(data-num);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: var(--text-aolor);
font-size: 30px;
}
.container-box {
- border: 1px solid red;
}
- 接下來,寫一個定時器,實現進度條加載,就完成了啦~
在這里插入圖片描述
const getData = () => {
const circle = document.getElementById("circle");
const box = document.getElementById("box");
let perimeter = 3.14 * 150; //這是stroke-dasharray的值
let i = 0;
let timer = null;
const loading = () => {
if (i < 100) {
i++;
box.dataset.num = i + "%";
let per = perimeter - (perimeter * i) / 100;
circle.style.strokeDashoffset = per;
} else {
clearInterval(timer);
}
};
loading();
timer = setInterval(loading, 100);
};
getData();
3.實現代碼
<!DOCTYPE html>
<html lang="en">
<head>
<title>151.SVG 實現擬物態圓環進度條</title>
</head>
<link rel="stylesheet" href="../common.css" />
<style>
body {
background: var(--back-bg);
}
:root {
--bg: #edf1f5;
--back-bg: #c5ccda;
--back-shadow: #ffffff;
--ring-color1: #c1dfc4;
--ring-color2: #3cba92;
--text-aolor: #497241;
/* 父容器寬度 */
--w: 200px;
/* 父容器gap*/
--gap: 30px;
/* 第二層圓形寬度 */
--inner: calc(var(--w) - var(--gap));
/* 環形stroke寬度 */
--stroke: 20px;
/* svg環形寬度 */
--circle: calc(var(--inner) - var(--stroke));
/* 第三層圓形寬度 */
--center: calc(var(--circle) - var(--stroke));
}
.container {
padding: 30px;
border-radius: 20px;
background: var(--bg);
box-shadow: 0px 20px 30px rgba(100, 131, 177, 0.2);
border: 1px solid #fff;
}
.container-box {
position: relative;
width: var(--w);
height: var(--w);
}
.circle-outer {
position: relative;
width: 100%;
height: 100%;
border-radius: 50%;
box-shadow: 6px 6px 8px var(--back-bg), -6px -6px 8px var(--back-shadow);
background: var(--bg);
}
.circle-outer::before {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: var(--bg);
width: var(--inner);
height: var(--inner);
box-shadow: inset 8px 8px 10px var(--back-bg),
inset -4px -4px 8px var(--back-shadow);
}
.circle-outer::after {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
background: var(--bg);
width: var(--center);
height: var(--center);
box-shadow: 6px 6px 8px var(--back-bg), -2px -2px 8px var(--back-shadow);
}
.container-box::after {
content: attr(data-num);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: var(--text-aolor);
font-size: 30px;
}
svg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
transform: rotate(-90deg);
}
svg circle {
position: absolute;
--z: calc(var(--w) / 2);
--c: calc(var(--circle) / 2);
transform: translate(
calc(var(--z) - var(--c)),
calc(var(--z) - var(--c))
);
cy: calc(var(--circle) / 2);
cx: calc(var(--circle) / 2);
r: calc(var(--circle) / 2);
fill: none;
stroke-linecap: round;
/* 設置圓的stroke-dasharray和stroke-dashoffset,為圓的周長 */
stroke-dasharray: calc(3.14 * var(--circle));
stroke-dashoffset:calc(3.14 * var(--circle));
stroke-width: var(--stroke);
}
</style>
<body>
<div class="container">
<div class="container-box" data-num="--" id="box">
<div class="circle-outer"></div>
<svg>
<defs>
<radialGradient
id="gradient"
cx="50%"
cy="50%"
r="60%"
fx="50%"
fy="50%"
>
<stop offset="30%" stop-color="var(--ring-color2)" />
<stop offset="100%" stop-color="var(--ring-color1)" />
</radialGradient>
</defs>
<circle stroke="url(#gradient)" id="circle"></circle>
</svg>
</div>
</div>
</body>
<script>
const getData = () => {
const circle = document.getElementById("circle");
const box = document.getElementById("box");
let perimeter = 3.14 * 150; //這是stroke-dasharray的值
let i = 0;
let timer = null;
const loading = () => {
if (i < 100) {
i++;
box.dataset.num = i + "%";
let per = perimeter - (perimeter * i) / 100;
circle.style.strokeDashoffset = per;
} else {
clearInterval(timer);
}
};
loading();
timer = setInterval(loading, 100);
};
getData();
</script>
</html>