Взгляните на следующий код:
function getScrollPercent() {
const h = document.documentElement;
const st = 'scrollTop';
const sh = 'scrollHeight';
const clientHeight = h.clientHeight;
const scrollTop = h[st];
const scrollHeight = h[sh];
return scrollTop / (scrollHeight - clientHeight) * 100;
}
function update_scroll() {
const scrollPercent = getScrollPercent();
document.getElementById("scroll-line").style.height = `${scrollPercent}%`;
document.getElementById("progress").textContent = Math.round(scrollPercent) + '%';
}
window.addEventListener('scroll', update_scroll);
update_scroll();
.content-site {
height: 500vh;
}
#main_box {
position: fixed;
right: 50px;
bottom: 80px;
}
#body_box {
width: 100px;
height: 100px;
background: #b0ffcb;
box-shadow: 0 0 4px #050030;
border-radius: 50% !important;
position: relative;
overflow: hidden;
}
#progress {
position: absolute;
top: 40%;
left: auto;
z-index: 3;
color: #f00;
display: block;
margin: 0 auto;
width: 100%;
text-align: center;
}
#scroll-line {
width: 100%;
position: absolute;
top: 0;
left: 0;
border-radius: 50%;
z-index: 2;
background-color: #050030;
}
<div class = "content-site"></div>
<footer>
<div id = "main_box">
<div id = "body_box">
<div id = "scroll-line"></div>
<p id = "progress"></p>
</div>
</div>
</footer>
Как видите, я реализовал индикатор выполнения, который меняет состояние в зависимости от положения прокрутки страницы.
Теперь вместо изменения цвета фона элемента при прокрутке я хочу создать вокруг элемента кольцо прогресса, которое меняет свое состояние при прокрутке страницы.
Вот пример того, что я ищу:
https://codepen.io/christianmair/pen/dLVbze
Проблема с приведенным выше примером заключается в том, что он использует SVG, что делает код очень сложным.
Я хочу сделать это с помощью кода, который я написал до сих пор, но я попробовал много способов и не смог достичь желаемого результата.
Более простое решение с SVG.
function getScrollPercent() {
const h = document.documentElement;
const st = 'scrollTop';
const sh = 'scrollHeight';
const clientHeight = h.clientHeight;
const scrollTop = h[st];
const scrollHeight = h[sh];
return scrollTop / (scrollHeight - clientHeight) * 100;
}
function update_scroll() {
const scrollPercent = getScrollPercent();
const circle = document.querySelector('.progress-ring__circle');
const radius = circle.r.baseVal.value;
const circumference = 2 * Math.PI * radius;
const offset = circumference - scrollPercent / 100 * circumference;
circle.style.strokeDashoffset = offset;
document.getElementById("progress").textContent = Math.round(scrollPercent) + '%';
}
window.addEventListener('scroll', update_scroll);
update_scroll();
.content-site {
height: 500vh;
}
#main_box {
position: fixed;
right: 50px;
bottom: 80px;
}
#body_box {
width: 100px;
height: 100px;
background: #b0ffcb;
box-shadow: 0 0 4px #050030;
border-radius: 50% !important;
position: relative;
overflow: hidden;
}
#progress {
position: absolute;
top: 40%;
left: auto;
z-index: 3;
color: #f00;
display: block;
margin: 0 auto;
width: 100%;
text-align: center;
}
.progress-ring__circle {
fill: none;
stroke: #050030;
stroke-width: 8;
stroke-dasharray: 265;
}
.progress-ring__background {
fill: none;
stroke: #b0ffcb;
stroke-width: 8;
}
.progress-ring__circle,
.progress-ring__background {
stroke-linecap: round;
}
<div class = "content-site"></div>
<footer>
<div id = "main_box">
<div id = "body_box">
<svg class = "progress-ring" width = "100" height = "100">
<circle class = "progress-ring__background" cx = "50" cy = "50" r = "42"></circle>
<circle class = "progress-ring__circle" cx = "50" cy = "50" r = "42"></circle>
</svg>
<div id = "progress"></div>
</div>
</div>
</footer>
@ParkingMaster Верно, но они сказали так, потому что это сложно. Я попробовал сделать простой вариант. В этом-то и дело.
Ох, я не дочитал :D
Попробуйте conic-gradient
и добавьте меньший круг, цвет фона которого такой же, как у #body_box
.
background: conic-gradient(black 0deg, black calc(360deg * var(--scrollPercent)), transparent calc(360deg * var(--scrollPercent)), transparent 360deg);
function getScrollPercent() {
const { clientHeight, scrollTop, scrollHeight } = document.documentElement;
return scrollTop / (scrollHeight - clientHeight);
}
function update_scroll() {
const scrollPercent = getScrollPercent();
document.getElementById("scroll-line").style.setProperty("--scrollPercent", scrollPercent);
document.getElementById("progress").textContent = Math.round(scrollPercent * 100) + "%";
}
window.addEventListener("scroll", update_scroll);
update_scroll();
.content-site {
height: 500vh;
}
#main_box {
position: fixed;
right: 50px;
bottom: 80px;
}
#body_box {
--bg: #b0ffcb;
width: 100px;
height: 100px;
background: var(--bg);
box-shadow: 0 0 4px #050030;
border-radius: 50% !important;
position: relative;
overflow: hidden;
}
#progress {
position: absolute;
top: 40%;
left: auto;
z-index: 3;
color: #f00;
display: block;
margin: 0 auto;
width: 100%;
text-align: center;
}
#scroll-line {
--scrollPercent: 0;
width: 100%;
z-index: 2;
background: conic-gradient(black 0deg, black calc(360deg * var(--scrollPercent)), transparent calc(360deg * var(--scrollPercent)), transparent 360deg);
}
#scroll-line::before {
content: "";
display: block;
width: calc(100% - 15px);
background: var(--bg);
}
#scroll-line,
#scroll-line::before {
aspect-ratio: 1;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 50%;
}
<div class = "content-site"></div>
<footer>
<div id = "main_box">
<div id = "body_box">
<div id = "scroll-line"></div>
<p id = "progress"></p>
</div>
</div>
</footer>
Спасибо. Это именно то, что я хотел, просто и практично.
ОП хочет сделать это без SVG.