Next.js中实现文本适配剩余空间并保留逐行动画效果的问询
解决方案
1. 修复文本溢出的布局问题
用Tailwind的flex布局锁定文本容器的可用空间,避免溢出:
- 外层用
flex容器,图片设置自适应宽度,文本容器添加flex-1 overflow-hidden,确保只占用图片旁的剩余空间,同时限制内容溢出。 - 示例结构:
<div className="flex flex-col md:flex-row gap-4"> <img src="/your-image.jpg" alt="示例图" className="w-full md:w-1/3 object-cover" /> <div className="flex-1 overflow-hidden"> <AnimatedText text={yourContent} /> </div> </div>
这里flex-1让文本容器填充剩余空间,overflow-hidden配合默认的whitespace-normal实现文本自动换行适配。
2. 实现逐行交替方向的framer-motion动画
步骤1:拆分文本为独立行
通过临时元素计算每行可容纳的内容,确保拆分结果和实际显示一致:
步骤2:编写AnimatedText组件
import { motion } from 'framer-motion'; import { useEffect, useState } from 'react'; const AnimatedText = ({ text }) => { const [lines, setLines] = useState([]); useEffect(() => { const container = document.getElementById('text-wrapper'); if (!container) return; const words = text.split(' '); const currentLine = []; const lineList = []; // 创建临时元素计算行高 const tempEl = document.createElement('div'); tempEl.className = 'whitespace-normal'; tempEl.style.visibility = 'hidden'; tempEl.style.position = 'absolute'; container.appendChild(tempEl); words.forEach(word => { currentLine.push(word); tempEl.textContent = currentLine.join(' '); // 当临时元素高度超过容器单行列高时,拆分当前行 if (tempEl.offsetHeight > container.offsetHeight / (lineList.length + 1)) { currentLine.pop(); lineList.push(currentLine.join(' ')); currentLine.push(word); } }); currentLine.length > 0 && lineList.push(currentLine.join(' ')); container.removeChild(tempEl); setLines(lineList); }, [text]); // 监听窗口 resize,重新计算行 useEffect(() => { const recalculateLines = () => { const container = document.getElementById('text-wrapper'); if (!container) return; const words = text.split(' '); const currentLine = []; const lineList = []; const tempEl = document.createElement('div'); tempEl.className = 'whitespace-normal'; tempEl.style.visibility = 'hidden'; tempEl.style.position = 'absolute'; container.appendChild(tempEl); words.forEach(word => { currentLine.push(word); tempEl.textContent = currentLine.join(' '); if (tempEl.offsetHeight > container.offsetHeight / (lineList.length + 1)) { currentLine.pop(); lineList.push(currentLine.join(' ')); currentLine.push(word); } }); currentLine.length > 0 && lineList.push(currentLine.join(' ')); container.removeChild(tempEl); setLines(lineList); }; window.addEventListener('resize', recalculateLines); return () => window.removeEventListener('resize', recalculateLines); }, [text]); return ( <div id="text-wrapper" className="whitespace-normal"> {lines.map((line, index) => ( <motion.div key={index} initial={{ x: index % 2 === 0 ? -100 : 100, opacity: 0 }} animate={{ x: 0, opacity: 1 }} transition={{ duration: 0.6, delay: index * 0.2 }} className="mb-1" > {line} </motion.div> ))} </div> ); }; export default AnimatedText;
关键说明
- 动画逻辑:偶数行(索引从0开始)从左侧(
x: -100)滑入,奇数行从右侧(x: 100)滑入,配合透明度渐变,逐行添加延迟让动画更有层次感。 - 响应式适配:监听窗口 resize 事件,重新计算每行内容,保证窗口缩放时动画行和实际显示行一致。
内容的提问来源于stack exchange,提问作者singrium
相关产品推荐
相关产品推荐

