JSFiddle - React, Tailwind, and code Playground
by gRoberts
HTML
<div class="lines-shift-container" style="--shift-delay: var(--shift-base-delay);">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rem quasi magnam quis, officiis consectetur velit omnis porro? Harum cum, culpa ipsum reiciendis aperiam dignissimos quis sunt consequuntur, odio, nemo illo.</div>
CSS
--shift-base-delay: 200ms;
--shift-delay: 200ms;
.lines-shift-container {
--shift-base-delay: 140ms; /* 200ms default */
--anim-duration: calc(var(--shift-base-delay) * 10);
--shift-delay: 0ms;
visibility: hidden;
}
.lines-shift-container--200ms-delay { --shift-delay: var(--shift-base-delay); }
.lines-shift-container--400ms-delay { --shift-delay: calc(var(--shift-base-delay) * 2); }
.lines-shift-container--600ms-delay { --shift-delay: calc(var(--shift-base-delay) * 3); }
.shift-line {
--line-number: var(--nth-child-idx);
overflow: hidden;
display: inline-flex;
position: relative;
width: 100%;
/*line-height: 1em;*/
/*background-color: rgba(255, 0, 0, 0.2);*/
}
/*.shift-line sup {
font-size: 0.5em;
top: -.7em;
}*/
.shift-line > span {
display: inline-block;
will-change: opacity, transform;
/*transition: transform 200ms cubic-bezier(.46,.45,.39,1.14);*/
transition: opacity calc(var(--anim-duration) / 3) linear, transform var(--anim-duration) cubic-bezier(0.19, 1, 0.22, 1);
/*transform: translateY(0%);*/
transform: translateY(103%);
/*opacity: 0;*/
transition-delay: calc(var(--shift-base-delay) + var(--shift-delay) + (var(--anim-duration) / 10) * (var(--line-number) - 1));
}
body.page--loaded:not(.pace-running) .lines-shift-container,
body.wp-admin .lines-shift-container {
visibility: initial;
}
body.page--loaded:not(.pace-running) .lines-shift-container:not(.lines-shift-container--vt) .shift-line > span {
transform: translateY(0%);
/*opacity: 1;*/
}
body.page--loaded:not(.pace-running) .visible-tag--visible .lines-shift-container.lines-shift-container--vt .shift-line > span {
transform: translateY(0%);
}
body.wp-admin .shift-line > span {
transform: translateY(0%);
}
JavaScript
function nextAnimationFrame() {
return new Promise(function(resolve, reject) {
window.requestAnimationFrame(function() {
window.requestAnimationFrame(resolve);
});
});
}
function transitionEnd(target) {
return new Promise(function(resolve, reject) {
target.addEventListener('transitionend', resolve, {once: true});
});
}
(function() {
console.log(document);
if('fonts' in document) {
document.fonts.ready.then(async function() {
processShiftLineContainers();
await nextAnimationFrame();
document.body.classList.add('page--loaded');
});
} else {
window.addEventListener('DOMContentLoaded', async function() {
processShiftLineContainers();
await nextAnimationFrame();
document.body.classList.add('page--loaded');
});
}
let resizeTimeout = null;
window.addEventListener('resize', function() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(processShiftLineContainers, 1000);
});
})();
function processShiftLineContainers() {
const shiftContaners = Array.from(document.querySelectorAll('.lines-shift-container'));
shiftContaners.forEach(c => wrapLines(c, '<span class="shift-line"><span>', '</span></span>'));
}
function wrapLines(target, before, after) {
let lines = detectLines(target);
lines = lines.map(l => before + l + after);
let html = lines.join(' ');
target.innerHTML = html;
}
function detectLines(target) {
const text = target.textContent;
const words = text.split(' ');
const div = document.createElement('div');
// Creating copy of text container with text affecting properties
const tstyle = window.getComputedStyle(target);
const rect = target.getBoundingClientRect();
div.style.width = rect.width + 'px'; //tstyle.getPropertyValue('width');
div.style.fontFamily = tstyle.getPropertyValue('font-family');
...