Code:
Javascript/GSAP
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const wordList = document.querySelector('[data-looping-words-list]');
const words = Array.from(wordList.children);
const totalWords = words.length;
const wordHeight = 100 / totalWords; // Offset as a percentage
const edgeElement = document.querySelector('[data-looping-words-selector]');
let currentIndex = 0;
function updateEdgeWidth() {
const centerIndex = (currentIndex + 1) % totalWords;
const centerWord = words[centerIndex];
const centerWordWidth = centerWord.getBoundingClientRect().width;
const listWidth = wordList.getBoundingClientRect().width;
const percentageWidth = (centerWordWidth / listWidth) * 100;
gsap.to(edgeElement, {
width: `${percentageWidth}%`,
duration: 0.5,
ease: 'Expo.easeOut',
});
}
function moveWords() {
currentIndex++;
gsap.to(wordList, {
yPercent: -wordHeight * currentIndex,
duration: 1.2,
ease: 'elastic.out(1, 0.85)',
onStart: updateEdgeWidth,
onComplete: function() {
if (currentIndex >= totalWords - 3) {
wordList.appendChild(wordList.children[0]);
currentIndex--;
gsap.set(wordList, { yPercent: -wordHeight * currentIndex });
words.push(words.shift());
}
}
});
}
updateEdgeWidth();
gsap.timeline({ repeat: -1, delay: 1 })
.call(moveWords)
.to({}, { duration: 2 })
.repeat(-1);
});
</script>
CSS
.clonable {
padding: 1.5em;
justify-content: center;
align-items: center;
min-height: 100vh;
display: flex;
position: relative;
}
.looping-words {
height: 3em;
font-size: 11vw;
line-height: .9;
position: relative;
}
.looping-words__list {
text-align: center;
text-transform: uppercase;
}
.looping-words__edge {
border-top: .045em solid red;
border-left: .045em solid red;
width: .25em;
height: .25em;
position: absolute;
top: 0;
left: 0;
}
.looping-words__edge.is_2 {
left: auto;
right: 0;
transform: rotate(90deg);
}
.looping-words__edge.is_3 {
inset: auto 0 0 auto;
transform: rotate(180deg);
}
.looping-words__edge.is_4 {
top: auto;
bottom: 0;
transform: rotate(270deg);
}
.looping-words__containers {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
}
.looping-words__p {
margin: 0;
}