Эластичная линия
Главная/Библиотека/Эластичная линия
Видеоинстукция по подключению
Пошаговая инструкция
Шаг 1
Создаём shape высотой в 60px, убираем заливку и вешаем класс elastic-line
Шаг 2
Добавить блок Т123 внизу страницы

<!--Эластичная линия
https://pt-webdesign.ru/elastic-->
<style>
:root {
--ElasticLineHeight: 1.2px; /*Толщина линии*/
--ElasticLineColor: #E0EEEE; /*Цвет линии*/
}
.elastic-line , .elastic-line .tn-atom,
.elastic-line-2 , .elastic-line-2 .tn-atom {
height: 100%;
display: block;
}
.container-elastic-line,
.container-elastic-line-2 {
width: 100%;
height: 100%;
overflow-y: visible;
}
.container-elastic-line svg,
.container-elastic-line-2 svg {
width: 100%;
overflow-x: hidden;
height: 400%;
pointer-events: none;
transform: translateY(-50%);
position: relative;
top: 50%;
}
.container-elastic-line svg path {
stroke-width: var(--ElasticLineHeight);
stroke: var(--ElasticLineColor);
fill: none;
position: absolute;
}
.container-elastic-line-2 svg path {
stroke-width: var(--ElasticLineHeight);
stroke: red;
fill: none;
position: absolute;
}
.elastic-line-box {
height: 100%;
width: 100%;
display: block;
position: absolute;
z-index: 1;
}
</style>
<div class="container-elastic-line line-elastic">
<span class="elastic-line-box"></span>
<svg class="svg-container" id="svg1">
<path class="curve" d="M0 120 Q210 120, 1920 120"></path>
</svg>
</div>
<!--<div class="container-elastic-line-2 line-elastic">-->
<!-- <span class="elastic-line-box"></span>-->
<!-- <svg class="svg-container" id="svg2">-->
<!-- <path class="curve" d="M0 120 Q210 120, 1920 120"></path>-->
<!-- </svg>-->
<!--</div>-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$('.container-elastic-line').appendTo('.elastic-line .tn-atom');
$('.container-elastic-line-2').appendTo('.elastic-line-2 .tn-atom');
document.addEventListener("DOMContentLoaded", function () {
const svgs = document.querySelectorAll('.line-elastic svg');
const boxes = document.querySelectorAll('.elastic-line-box');
const paths = document.querySelectorAll('.line-elastic svg path');
const numLines = svgs.length;
const progress = new Array(numLines).fill(0);
const x = new Array(numLines).fill(0.5);
const time = new Array(numLines).fill(Math.PI / 2);
const reqIds = new Array(numLines).fill(null);
function setPath(index, prog) {
const svgWidth = svgs[index].getBoundingClientRect().width;
x[index] = (svgWidth * x[index]) / svgWidth;
paths[index].setAttributeNS(null, "d", `M0 120 Q${svgWidth * x[index]} ${120 + prog}, ${svgWidth} 120`);
}
function lerp(x, y, a) {
return x * (1 - a) + y * a;
}
function manageMouseEnter(index) {
if (reqIds[index]) {
cancelAnimationFrame(reqIds[index]);
resetAnimation(index);
}
}
function manageMouseMove(index, e) {
const { movementY } = e;
progress[index] += movementY;
setPath(index, progress[index]);
}
function manageMouseLeave(index) {
animateOut(index);
}
function animateOut(index) {
const newProgress = progress[index] * Math.sin(time[index]);
progress[index] = lerp(progress[index], 0, 0.025);
time[index] += 0.2;
setPath(index, newProgress);
if (Math.abs(progress[index]) > 0.75) {
reqIds[index] = requestAnimationFrame(() => animateOut(index));
} else {
resetAnimation(index);
}
}
function resetAnimation(index) {
time[index] = Math.PI / 2;
progress[index] = 0;
}
boxes.forEach((box, index) => {
box.addEventListener("mouseenter", () => manageMouseEnter(index));
box.addEventListener("mousemove", (e) => manageMouseMove(index, e));
box.addEventListener("mouseleave", () => manageMouseLeave(index));
});
});
</script>
Скопировать
<!--Эластичная линия
https://pt-webdesign.ru/elastic-->
<style>
:root {
--ElasticLineHeight: 1.2px; /*Толщина линии*/
--ElasticLineColor: #E0EEEE; /*Цвет линии*/
}
.elastic-line , .elastic-line .tn-atom,
.elastic-line-2 , .elastic-line-2 .tn-atom {
height: 100%;
display: block;
}
.container-elastic-line,
.container-elastic-line-2 {
width: 100%;
height: 100%;
overflow-y: visible;
}
.container-elastic-line svg,
.container-elastic-line-2 svg {
width: 100%;
overflow-x: hidden;
height: 400%;
pointer-events: none;
transform: translateY(-50%);
position: relative;
top: 50%;
}
.container-elastic-line svg path {
stroke-width: var(--ElasticLineHeight);
stroke: var(--ElasticLineColor);
fill: none;
position: absolute;
}
.container-elastic-line-2 svg path {
stroke-width: var(--ElasticLineHeight);
stroke: red;
fill: none;
position: absolute;
}
.elastic-line-box {
height: 100%;
width: 100%;
display: block;
position: absolute;
z-index: 1;
}
</style>
<div class="container-elastic-line line-elastic">
<span class="elastic-line-box"></span>
<svg class="svg-container" id="svg1">
<path class="curve" d="M0 120 Q210 120, 1920 120"></path>
</svg>
</div>
<!--<div class="container-elastic-line-2 line-elastic">-->
<!-- <span class="elastic-line-box"></span>-->
<!-- <svg class="svg-container" id="svg2">-->
<!-- <path class="curve" d="M0 120 Q210 120, 1920 120"></path>-->
<!-- </svg>-->
<!--</div>-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$('.container-elastic-line').appendTo('.elastic-line .tn-atom');
$('.container-elastic-line-2').appendTo('.elastic-line-2 .tn-atom');
document.addEventListener("DOMContentLoaded", function () {
const svgs = document.querySelectorAll('.line-elastic svg');
const boxes = document.querySelectorAll('.elastic-line-box');
const paths = document.querySelectorAll('.line-elastic svg path');
const numLines = svgs.length;
const progress = new Array(numLines).fill(0);
const x = new Array(numLines).fill(0.5);
const time = new Array(numLines).fill(Math.PI / 2);
const reqIds = new Array(numLines).fill(null);
function setPath(index, prog) {
const svgWidth = svgs[index].getBoundingClientRect().width;
x[index] = (svgWidth * x[index]) / svgWidth;
paths[index].setAttributeNS(null, "d", `M0 120 Q${svgWidth * x[index]} ${120 + prog}, ${svgWidth} 120`);
}
function lerp(x, y, a) {
return x * (1 - a) + y * a;
}
function manageMouseEnter(index) {
if (reqIds[index]) {
cancelAnimationFrame(reqIds[index]);
resetAnimation(index);
}
}
function manageMouseMove(index, e) {
const { movementY } = e;
progress[index] += movementY;
setPath(index, progress[index]);
}
function manageMouseLeave(index) {
animateOut(index);
}
function animateOut(index) {
const newProgress = progress[index] * Math.sin(time[index]);
progress[index] = lerp(progress[index], 0, 0.025);
time[index] += 0.2;
setPath(index, newProgress);
if (Math.abs(progress[index]) > 0.75) {
reqIds[index] = requestAnimationFrame(() => animateOut(index));
} else {
resetAnimation(index);
}
}
function resetAnimation(index) {
time[index] = Math.PI / 2;
progress[index] = 0;
}
boxes.forEach((box, index) => {
box.addEventListener("mouseenter", () => manageMouseEnter(index));
box.addEventListener("mousemove", (e) => manageMouseMove(index, e));
box.addEventListener("mouseleave", () => manageMouseLeave(index));
});
});
</script>
Made on
Tilda