I'm working on a webpage where I want text to behave in a specific way when it overflows its container: instead of breaking in the middle of a word, the entire word should move to the next line.
Here's what I've done so far:
I added the following CSS properties to control word breaking:
word-break: keep-all;
overflow-wrap: normal;
word-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
Here's the full snippet of my code, including JavaScript for animation and the HTML structure:
class Lenis {
constructor(options) {
this.options = options;
this.currentScroll = 0;
}
raf(time) {
// Dummy implementation for smooth scroll effect
this.currentScroll += (window.scrollY - this.currentScroll) * this.options.easing(0.1);
}
destroy() {
// Clean-up if necessary
}
}
function splitText(element) {
const text = element.textContent;
element.textContent = "";
const wrapper = document.createElement("div");
wrapper.style.display = "inline-block";
wrapper.style.width = "100%";
const spans = [...text].map((char) => {
const span = document.createElement("span");
span.textContent = char === " " ? "\u00A0" : char;
span.style.display = "inline-block";
wrapper.appendChild(span);
return span;
});
element.appendChild(wrapper);
return spans;
}
document.addEventListener("DOMContentLoaded", () => {
// Initialize Lenis for smooth scrolling
const lenis = new Lenis({
duration: 1.2,
easing: (t) => Math.min(1, 1.001 - Math.pow(2, -10 * t)),
direction: "vertical",
gestureDirection: "vertical",
smooth: true,
smoothTouch: false,
touchMultiplier: 2,
});
function raf(time) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
window.addEventListener("unload", () => lenis.destroy());
// Reveal text animation
const revealElements = document.querySelectorAll(".reveal-type");
revealElements.forEach((element) => {
const chars = splitText(element);
const bgColor = element.dataset.bgColor;
const fgColor = element.dataset.fgColor;
chars.forEach((char) => {
char.style.color = bgColor;
});
const animateOnScroll = () => {
const rect = element.getBoundingClientRect();
const windowHeight = window.innerHeight;
const elementHeight = rect.height;
const visibleHeight = windowHeight - rect.top;
const progressLength = elementHeight * 1.2;
if (visibleHeight <= 0) return;
let progress = visibleHeight / progressLength;
progress = Math.max(0, Math.min(1, progress));
const charsToColor = Math.floor(progress * chars.length);
chars.forEach((char, index) => {
if (index < charsToColor) {
char.style.color = fgColor;
} else {
char.style.color = bgColor;
}
});
};
animateOnScroll();
window.addEventListener("scroll", animateOnScroll);
window.addEventListener("unload", () => {
window.removeEventListener("scroll", animateOnScroll);
});
});
});
body {
margin: 0;
font-family: "Inter", sans-serif;
background: rgb(5, 4, 4);
}
section {
min-height: auto;
margin: 2rem auto;
padding: 2rem clamp(1rem, 5vw, 4rem);
display: grid;
place-content: center;
box-sizing: border-box;
}
section p {
font-size: clamp(1.2rem, 5vw, 9rem);
word-break: keep-all;
overflow-wrap: normal;
word-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
}
section:nth-of-type(1) {
border: 1px solid black;
height: auto;
padding: 0;
display: flex;
justify-content: center;
align-items: flex-start;
}
section:nth-of-type(1) img {
max-width: 100%;
height: auto;
-o-object-fit: cover;
object-fit: cover;
}
section:nth-of-type(2) {
max-width: 100%;
margin: 0 auto;
transform: translateX(0);
}/*# sourceMappingURL=main.css.map */
<section>
<img src="example" alt="Thumbnail">
</section>
<section>
<p
class="reveal-type"
data-bg-color="#232323"
data-fg-color="white"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
</section>
<section></section>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/lenis.min.js"></script>
As you can see, i already add
word-break: keep-all;
overflow-wrap: normal;
word-wrap: break-word;
-webkit-hyphens: auto;
hyphens: auto;
The Problem
Despite adding these CSS properties, the words are still breaking in the middle and wrapping to the next line. I expected the whole word to move to the next line if it doesn't fit
What I Tried
1. Using word-break: keep-all, which, as I understand, should prevent breaking words in the middle.
2. Combining it with overflow-wrap: normal and word-wrap: break-word, thinking it would work for all browsers.
3. Adding hyphens: auto to handle hyphenation gracefully. However, the behavior is still not what I expect. Words keep breaking mid-word.
My Environment
Browser: Arc or edge
Tools: React 19.0.0
A different idea using only CSS (for the future as the support is still not good)
body {
margin: 0;
font-family: "Inter", sans-serif;
background: rgb(5, 4, 4);
}
section {
margin-top: 100vh;
padding: 2rem clamp(1rem, 5vw, 4rem);
}
section p {
font-size: clamp(1.2rem, 5vw, 9rem);
}
.reveal-type span {
background: conic-gradient(#fff 0 0) left no-repeat #232323;
background-size: 0% 100%;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
animation: show linear forwards;
animation-timeline: view(block);
animation-range: entry 10% entry-crossing 110%;
}
@keyframes show {
to {
background-size: 100% 100%;
}
}
<section>
<p class="reveal-type">
<span>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</span>
</p>
</section>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With