How do I do it so that the path is stretched under the content?

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

Answers (2)

Temani Afif
Temani Afif

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

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

Related Questions