<div id="container">
<div id="text">Lorem ipsum <b>dolor</b> sit amet, <small>consectetuer adipiscing elit</small>.</div>
<div id="shadings"></div>
</div>
html,
body {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: #cae9ff;
}
body {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 3.5vw;
}
#text,
#shadings {
height: 1.5em;
padding-bottom: 0.25em;
}
#text {
whitespace: pre;
display: inline;
width: fit-content;
}
small {
font-size: 0.6em;
}
#shadings {
position: relative;
mix-blend-mode: multiply;
transition: 0.5s ease-in-out transform;
}
#shadings div {
position: absolute;
height: 1em;
background-color: #00fff5;
left: 0;
}
#shadings div:nth-child(2n) {
background-color: #3cdbd3;
}
#shadings div:last-child {
position: relative;
opacity: 0;
}
#container:hover #shadings {
transform: translateY(-1em);
}
/**
* A generator that recursively find all text nodes in a subtree rooted at el.
*/
function* recursivelyFindTextNode(el: Node): Generator<Node> {
if (el.nodeType === Node.TEXT_NODE) {
yield el;
} else if (el.nodeType === Node.ELEMENT_NODE) {
for (let i = 0; i < el.childNodes.length; i++) {
yield* recursivelyFindTextNode(el.childNodes[i]);
}
}
}
function measure(el: Node): number[] {
const result: number[] = [];
const range = document.createRange();
range.setStartBefore(el);
// expand all text nodes found.
const nodes = [...recursivelyFindTextNode(el)];
for (const textNode of nodes) {
const textLength = [...textNode.textContent].length;
for (let i = 0; i < textLength; i++) {
range.setEnd(textNode, i);
const rect = range.getBoundingClientRect();
if (rect.width !== 0) result.push(rect.width);
}
}
// Get the total length of the text
range.setEndAfter(nodes.length > 0 ? nodes[nodes.length - 1] : el);
const rect = range.getBoundingClientRect();
result.push(rect.width);
return result;
}
const el = document.getElementById("text");
const cont = document.getElementById("shadings");
const lengths = measure(el);
for (const l of lengths) {
const d = document.createElement("div");
d.style.width = `${l}px`;
cont.prepend(d);
}
// text width placeholder
const d = document.createElement("div");
d.style.width = `${lengths[lengths.length - 1]}px`;
cont.appendChild(d);
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.