滚动时::after伪元素与父元素的偏移问题求助
解决滚动时::after伪元素与父元素文本错位问题
问题根源
当屏幕宽度不足导致文本换行时,父元素.fill使用width: fit-content会收缩为换行后的文本宽度,但伪元素设置了white-space: nowrap,导致伪元素文本保持单行、宽度远大于父元素,最终填充时出现错位。使用max-content虽能对齐,但会让单行文本溢出屏幕,不符合需求。
解决方案
通过调整父元素和伪元素的定位、文本换行规则,同时优化JS逻辑来解决问题:
- 修改CSS样式
- 将父元素的
width: fit-content替换为display: inline-block,既保留收缩到内容宽度的特性,又能让文本正常换行且不溢出屏幕。 - 伪元素设置
left: 50%+transform: translateX(-50%)实现居中对齐,同时移除white-space: nowrap,让伪元素文本与原文本保持一致的换行行为。
- 将父元素的
修改后的CSS:
body { font-size: 20px; } .fill { font-size: 3rem; margin: auto; text-align: center; position: relative; -webkit-text-stroke: 1px #003049; -webkit-text-fill-color: transparent; display: inline-block; /* 替换width: fit-content */ } .fill::after { content: attr(data-text); position: absolute; top: 0; left: 50%; transform: translateX(-50%); -webkit-text-fill-color: #003049; width: var(--width, 0); overflow: hidden; white-space: normal; /* 与原文本保持一致的换行 */ transition: width .6s; text-align: center; /* 保持文本居中对齐 */ } #accueil { height: 100vh; width: 100%; background: rgba(0, 0, 0, .3); position: relative; display: flex; justify-content: center; align-items: center; }
- 优化JS逻辑
移除多余的for循环,避免每次滚动事件重复计算,提升性能:
修改后的JS:
let textToAnimate = document.getElementById('text'); let homeSection = document.getElementById('accueil'); let topSection = homeSection.offsetTop; let topText = textToAnimate.offsetTop; let endAnimation = (topText - topSection) - 20; let fillElement = document.querySelector('.fill'); window.addEventListener("scroll", function(e) { let initialOffset = topSection - window.innerHeight; if(window.scrollY >= initialOffset) { let coef = (window.scrollY - topSection) / endAnimation; coef = Math.min(Math.max(coef, 0), 1); fillElement.style.setProperty('--width', coef * 100 + '%'); } })
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body { font-size: 20px; } .fill { font-size: 3rem; margin: auto; text-align: center; position: relative; -webkit-text-stroke: 1px #003049; -webkit-text-fill-color: transparent; display: inline-block; } .fill::after { content: attr(data-text); position: absolute; top: 0; left: 50%; transform: translateX(-50%); -webkit-text-fill-color: #003049; width: var(--width, 0); overflow: hidden; white-space: normal; transition: width .6s; text-align: center; } #accueil { height: 100vh; width: 100%; background: rgba(0, 0, 0, .3); position: relative; display: flex; justify-content: center; align-items: center; } </style> </head> <body> <section id="accueil"> <h3 id="text" class="fill" data-text="Hi, this is a text fill animation">Hi, this is a text fill animation</h3> </section> <section> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce semper auctor nibh, id ultricies massa. Etiam fringilla lectus non viverra blandit. Ut ornare elit dolor, eget ultricies neque dapibus ac. Quisque mollis neque sit amet dui tincidunt, sed volutpat tellus ultricies. Quisque ut pulvinar arcu. Ut vitae nisi sem. Nullam ultrices a lorem at porta. Aliquam et nulla in nibh hendrerit convallis. Etiam nisi turpis, viverra vel iaculis sit amet, ornare pulvinar sapien. Suspendisse at imperdiet elit. Nullam nec suscipit magna. Praesent non rutrum orci. Duis facilisis magna vel sapien blandit sodales. In et sem vel magna euismod vulputate. Duis nibh ex, interdum sed scelerisque vitae, varius at diam. Duis sed purus quis risus sagittis elementum at ac lacus. Sed at leo blandit, pretium mauris non, tincidunt ex. Suspendisse consectetur finibus est nec posuere. Nullam rutrum leo dui, et ultrices mi tempus sit amet. Proin ullamcorper orci felis, eu elementum mi tempus sit amet. Nullam et lectus suscipit, feugiat ligula sit amet, condimentum magna. Proin vitae orci vitae purus auctor semper id a leo. Etiam et condimentum mi. Suspendisse lacinia eleifend turpis sit amet finibus. Morbi ultricies imperdiet libero. Integer quis egestas lectus. Quisque sem turpis, fringilla at purus ac, dictum luctus sem. Mauris efficitur dictum velit quis consectetur. Nulla posuere justo at pharetra egestas. Vivamus nulla ipsum, ornare vitae elementum quis, gravida eget velit. Mauris pellentesque vel massa vel fermentum. Suspendisse posuere arcu quis metus pretium, at mollis dolor cursus. Cras nec turpis mollis odio sodales suscipit. Nam luctus nibh sed augue gravida feugiat. Etiam egestas dictum mauris, non faucibus libero pharetra ut. Maecenas in sem et orci facilisis faucibus. Quisque quis euismod lorem, eu gravida sem. Nam eu tellus libero. Nunc vitae efficitur felis. Maecenas tellus sem, suscipit at laoreet sit amet, pretium non lorem. Integer at sem quis nisi molestie ultricies vitae ac eros. Fusce ac metus ex. Aliquam tempus ligula et lorem accumsan sodales. Phasellus finibus nibh ipsum, sed malesuada nulla blandit id. Phasellus sed pharetra quam, vel convallis ipsum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In pharetra cursus viverra. </p> </section> <script> let textToAnimate = document.getElementById('text'); let homeSection = document.getElementById('accueil'); let topSection = homeSection.offsetTop; let topText = textToAnimate.offsetTop; let endAnimation = (topText - topSection) - 20; let fillElement = document.querySelector('.fill'); window.addEventListener("scroll", function(e) { let initialOffset = topSection - window.innerHeight; if(window.scrollY >= initialOffset) { let coef = (window.scrollY - topSection) / endAnimation; coef = Math.min(Math.max(coef, 0), 1); fillElement.style.setProperty('--width', coef * 100 + '%'); } }) </script> </body> </html>
内容的提问来源于stack exchange,提问作者alex eusebio
相关产品推荐
相关产品推荐

