Reputation: 266
I have a task to make an animation of drawing a line, but it's not that simple. My SVG should be the same size as the div block with the text. But the trouble is that I can't do it! In other words, you need to make the path the same height as the number of lines in the text. We currently see that as the content increases the path drops to the bottom.
How can I correct the situation to get the desired result ?
// line length
let svgPath = [...document.querySelectorAll(".list__splitter path")]
svgPath.forEach(path => {
let length = path.getTotalLength()
path.style.setProperty('--path-length', length);
})
// start animation
svgPath.forEach(path => {
path.classList.add("pathAnima")
})
.list {
display: flex;
flex-direction: column;
margin: 0 auto;
max-width: 400px;
}
.list__item {
padding: 1em;
background: #f9f9f9;
min-height: 92px;
}
.list__splitter {
position: relative;
}
.list__splitter--revert {
transform: scale(-1, 1);
}
.list__splitter__content {
position: absolute;
top: 0;
left: 0;
width: 100%;
transform: translatey(-50%);
}
.list__splitter__content svg {
width: 100%;
height: 123px;
}
.list__splitter__content svg path {
vector-effect: non-scaling-stroke;
}
.list__splitter__content::before,
.list__splitter__content::after {
width: 10px;
height: 10px;
position: absolute;
background: #f00;
}
.list__splitter__content::after {
content: "";
bottom: -4px;
right: -4px;
}
.list>*:nth-child(2) .list__splitter__content::before {
content: "";
top: -4px;
left: -4px;
}
.pathAnima {
stroke-dasharray: var(--path-length);
stroke-dashoffset: var(--path-length);
animation-name: pathAnima;
animation-duration: 3s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: linear;
}
@keyframes pathAnima {
to {
stroke-dashoffset: 0;
}
}
<div class="content">
<div class="list">
<div class="list__item">A certain <br> text</div>
<div class="list__splitter">
<div class="list__splitter__content">
<svg viewBox="0 0 517 123" fill="none" preserveAspectRatio="none">
<path d="M1.5.9v30.3a30 30 0 0030 30h454a30 30 0 0130 30v31.1" stroke="#000"/>
</svg>
</div>
</div>
<div class="list__item">A certain <br> text A certain <br> text A certain <br> text A certain <br> text</div>
<div class="list__splitter list__splitter--revert">
<div class="list__splitter__content">
<svg viewBox="0 0 517 123" fill="none" preserveAspectRatio="none">
<path d="M1.5.9v30.3a30 30 0 0030 30h454a30 30 0 0130 30v31.1" stroke="#000"/>
</svg>
</div>
</div>
<div class="list__item">A certain <br> text</div>
</div>
</div>
Upvotes: 2
Views: 162
Reputation: 274097
Why not a CSS only solution:
.list {
display: flex;
flex-direction: column;
margin: 0 auto;
max-width: 400px;
}
.list__item {
padding: 1em;
border-left:5px solid transparent;
border-right:5px solid transparent;
background:
linear-gradient(red,red) left/10px 10px no-repeat border-box,
#f9f9f9 padding-box;
min-height: 92px;
position: relative;
}
.list__item:nth-child(even) {
background-position:right;
}
.list__item::before,
.list__item::after{
content:"";
position:absolute;
width:50%;
height:50%;
left:-1px;
border-left:2px solid;
pointer-events:none;
z-index:3;
clip-path:inset(0 0 0 100%)
}
.list__item::before {
top:-1px;
border-top:2px solid;
border-top-left-radius:30px;
animation:two 2s 2s linear forwards;
}
.list__item::after {
bottom:-1px;
border-bottom:2px solid;
border-bottom-left-radius:30px;
animation:one 2s linear forwards;
}
.list__item:nth-child(even)::before,
.list__item:nth-child(even)::after{
transform:scaleX(-1);
transform-origin:right;
}
.list__item:first-child::before,
.list__item:last-child::after {
display:none;
}
@keyframes one {
0% {
clip-path:inset(0 calc(100% - 10px) 100% 0)
}
50% {
clip-path:inset(0 calc(100% - 10px) 0 0)
}
100% {
clip-path:inset(0 0 0 0)
}
}
@keyframes two {
0% {
clip-path:inset(0 0 calc(100% - 10px) 100%)
}
50% {
clip-path:inset(0 0 calc(100% - 10px) 0)
}
100% {
clip-path:inset(0 0 0 0)
}
}
<div class="list">
<div class="list__item">A certain <br> text</div>
<div class="list__item">A certain <br> text A certain <br> text A certain <br> text A certain <br> text A certain <br> text A certain <br> text A certain <br> text</div>
<div class="list__item">A certain <br> text</div>
</div>
Upvotes: 2
Reputation: 33
Study my solution to the problem: https://codepen.io/Andreslav/pen/KKNpJad
// Responsive SVG way
class DinamicPath {
constructor(className, path, segmentData) {
this.path = path
this.segmentData = segmentData
this.boxNode = [...document.querySelectorAll(className)]
this.init()
this.update()
window.onresize = () => this.update();
}
init() {
this.data = this.boxNode.map(node => {
let svgNode = node.querySelector("svg")
let pathNode = svgNode.querySelector("path")
pathNode.setAttribute('d', this.path)
return {
boxNode: node,
svgNode,
pathNode
}
})
}
update() {
this.data.forEach(({boxNode, svgNode, pathNode}) => {
this.segmentData.forEach(seg => {
let pathData = pathNode.getPathData()
pathData[seg.segmentIndex].values[seg.segmentSubIndex] = seg.value(boxNode)
pathNode.setPathData(pathData)
})
let length = pathNode.getTotalLength()
pathNode.style.setProperty('--path-length', length)
setTimeout(() => {
let pathBox = pathNode.getBBox()
svgNode.setAttribute('viewBox', `0 0 ${pathBox.width + 2} ${pathBox.height}`)
}, 0)
})
}
}
new DinamicPath(
// Svg container selector
".splitter",
// Base path
"M1 1 v9 a30 30 0 0 0 30 30 h0 a30 30 0 0 1 30 30 v0",
// Array of path segment update parameters
[
{
segmentIndex: 1, // segment index
segmentSubIndex: 0, // segment part index
value: (box) => {
// a function that returns a parameter value,
// where "box" matches the element with the passed selector
return box.parentNode.clientHeight / 2 - 30
}
},
{
segmentIndex: 3,
segmentSubIndex: 0,
value: (box) => box.parentNode.clientWidth - 30 - 30
},
{
segmentIndex: 5,
segmentSubIndex: 0,
value: (box) => box.parentNode.nextElementSibling.clientHeight / 2 - 30
},
]
)
;[...document.querySelectorAll(".list__item path")].forEach(path => {
path.classList.add("pathAnima")
})
.list {
display: flex;
flex-direction: column;
margin: 0 auto;
max-width: 600px;
}
.list__item {
padding: 2em;
background: #f9f9f9;
min-height: 60px;
position: relative;
}
.list__item::before {
content: "";
width: 10px;
height: 10px;
position: absolute;
background: #f00;
top: 50%;
z-index: 2;
border-radius: 50%;
}
.list__item:nth-child(even)::before {
right: 1px;
transform: translate(50%, -50%);
}
.list__item:nth-child(odd)::before {
left: 1px;
transform: translate(-50%, -50%);
}
.splitter {
position: absolute;
top: 50%;
left: 0;
width: 100%;
z-index: 1;
pointer-events: none;
}
.splitter--revert {
transform: scale(-1, 1);
bottom: 50%;
}
svg {
width: 100%;
fill: none;
}
svg path {
stroke: #000;
vector-effect: non-scaling-stroke;
}
.pathAnima {
stroke-dasharray: var(--path-length);
stroke-dashoffset: var(--path-length);
animation: pathAnima 1s linear forwards;
}
@keyframes pathAnima {
to {
stroke-dashoffset: 0;
}
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/path-data-polyfill.min.js"></script>
<div class="content">
<div class="list">
<div class="list__item">
Человеческий организм получает почти все необходимые вещества именно через пищу и воду. С питанием связаны все жизненно важные функции организма.
<div class="splitter">
<svg viewBox="0 0 1 1">
<path d=""/>
</svg>
</div>
</div>
<div class="list__item">
Здоровый праздничный ужин вовсе не обязательно должен состоять из шпината, гречки и вареной куриной грудки. Самыми лучшими способами приготовления еды являются следующие: варка на пару, запекание или варка в воде. Помимо стандартных мандаринов и ананасов, отличным украшением любого стола станут необычные, экзотические фрукты. Здоровой может быть даже выпечка, если она приготовлена на пару.
<div class="splitter splitter--revert">
<svg viewBox="0 0 1 1">
<path d=""/>
</svg>
</div>
</div>
<div class="list__item">
Являясь одной из самых распространённых в мире сельскохозяйственных культур, рис занимает главенствующую позицию в национальной кухне сотен народов. В России до XIX века рис называли «сарацинское зерно». Более половины населения Земли питаются в основном именно рисом, что делает эту сельскохозяйственную культуру важнейшей на планете. В некоторых странах Азии из этого растения готовят такие напитки, как вино и пиво. Из рисовых зерён делают так называемую съедобную рисовую бумагу, применяемую в кондитерском деле.
<div class="splitter">
<svg viewBox="0 0 1 1">
<path d=""/>
</svg>
</div>
</div>
<div class="list__item">
Ценность яблок кроется в их составе. Почти 80% яблок составляет вода. Остальная часть приходится на клетчатку, органические кислоты, углеводы. Именно зеленое яблоко рекомендуют употреблять во время диет. Среди фруктов яблоко является очень распространенным продуктом и практически целый год присутствует в нашем рационе питания. Употребление этих плодов натощак недопустимо при гастритах с повышенной кислотностью, язвенных болезнях, желчекаменной болезни.
<div class="splitter splitter--revert">
<svg viewBox="0 0 1 1">
<path d=""/>
</svg>
</div>
</div>
<div class="list__item">
Ценность яблок кроется в их составе. Почти 80% яблок составляет вода. Остальная часть приходится на клетчатку, органические кислоты, углеводы. Именно зеленое яблоко рекомендуют употреблять во время диет. Среди фруктов яблоко является очень распространенным продуктом и практически целый год присутствует в нашем рационе питания. Употребление этих плодов натощак недопустимо при гастритах с повышенной кислотностью, язвенных болезнях, желчекаменной болезни.
<div class="splitter">
<svg viewBox="0 0 1 1">
<path d=""/>
</svg>
</div>
</div>
<div class="list__item">
Ценность яблок кроется в их составе. Почти 80% яблок составляет вода. Остальная часть приходится на клетчатку, органические кислоты, углеводы. Именно зеленое яблоко рекомендуют употреблять во время диет. Среди фруктов яблоко является очень распространенным продуктом и практически целый год присутствует в нашем рационе питания. Употребление этих плодов натощак недопустимо при гастритах с повышенной кислотностью, язвенных болезнях, желчекаменной болезни.
<div class="splitter splitter--revert">
<svg viewBox="0 0 1 1">
<path d=""/>
</svg>
</div>
</div>
<div class="list__item">
Здоровый праздничный ужин вовсе не обязательно должен состоять из шпината, гречки и вареной куриной грудки. Самыми лучшими способами приготовления еды являются следующие: варка на пару, запекание или варка в воде. Помимо стандартных мандаринов и ананасов, отличным украшением любого стола станут необычные, экзотические фрукты. Здоровой может быть даже выпечка, если она приготовлена на пару.
</div>
</div>
</div>
Upvotes: 2