CSS/JavaScript打字动画故障:光标竖条无法跟随文本移动
打字效果光标跟随问题解决方案
问题描述
开发CSS/JavaScript打字效果时,光标竖条(.message-bar)无法跟随逐字显示的文本移动,仅闪烁动画正常工作。
解决方案
1. 修正HTML结构
移除冗余的<div class="message-bar"></div>,避免与JavaScript动态创建的元素冲突:
<!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="estilo/styles.css"> <title>Animação de digitação</title> </head> <body> <div class="container"> <div class="message-container"> <p id="message"></p> </div> <div class="image-container"> <img id="image" src="imagens/imagem1.jpeg" alt="Imagem"> </div> </div> <script src="02 script.js"></script> </body> </html>
2. 调整CSS定位规则
让光标相对于文本容器定位,确保位置计算基准正确:
* { margin: 0; padding: 0; font-family: Arial, Helvetica, sans-serif; } .container { background-color: #000000; display: flex; align-items: center; justify-content: center; height: 100vh; overflow: hidden; } .image-container { flex: 1; display: flex; justify-content: flex-end; align-items: center; padding-right: 0; margin-left: auto; } #image { width: 65%; max-width: 432px; height: auto; box-shadow: 10px 10px 20px rgba(255, 255, 255, 0.5); } .message-container { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; padding-left: 50px; margin-right: auto; } #message { color: white; font-size: 28px; text-align: left; white-space: nowrap; overflow: hidden; position: relative; /* 关键:作为光标的定位基准 */ max-width: calc(100% - 50px); line-height: 28px; /* 匹配光标高度 */ } .blink-caret { animation: blink-caret 0.75s infinite; } #image { max-width: 100%; height: auto; transition: opacity 0.5s ease-in-out; opacity: 1; } .message-bar { position: absolute; bottom: 0; left: 0; /* 初始位置在文本开头 */ width: 4px; height: 28px; background-color: #ffffff; opacity: 0.7; } @keyframes blink-caret { from, to { opacity: 0; } 50% { opacity: 1; } }
3. 优化JavaScript位置计算逻辑
使用文本实时宽度替代固定字符宽度估算,同时处理删除文本时的光标跟随:
const messages = [ "My text here", "My text here", "My text here" ]; const images = [ "imagens/imagem1.jpeg", "imagens/imagem2.jpeg", "imagens/imagem3.jpeg" ]; const messageElement = document.getElementById("message"); const imageElement = document.getElementById("image"); const messageBarElement = document.createElement("div"); messageBarElement.classList.add("message-bar"); messageElement.appendChild(messageBarElement); let currentMessageIndex = 0; function typeMessage(message) { let i = 0; messageBarElement.classList.remove("blink-caret"); const typingInterval = setInterval(() => { if (i < message.length) { messageElement.textContent += message.charAt(i); i++; // 获取当前文本实际宽度,设置光标位置 const textWidth = messageElement.getBoundingClientRect().width; messageBarElement.style.left = `${textWidth}px`; } else { clearInterval(typingInterval); messageBarElement.classList.add("blink-caret"); setTimeout(eraseMessage, 2500); } }, 50); } function eraseMessage() { let i = messageElement.textContent.length - 1; const erasingInterval = setInterval(() => { if (i >= 0) { messageElement.textContent = messageElement.textContent.slice(0, i); i--; // 删除文本时同步更新光标位置 const textWidth = messageElement.getBoundingClientRect().width; messageBarElement.style.left = `${textWidth}px`; } else { clearInterval(erasingInterval); messageBarElement.classList.remove("blink-caret"); imageElement.style.transition = "opacity 0.5s ease-in-out"; imageElement.style.opacity = 0; setTimeout(() => { currentMessageIndex = (currentMessageIndex + 1) % messages.length; imageElement.src = images[currentMessageIndex]; imageElement.style.transition = "opacity 0.5s ease-in-out"; imageElement.style.opacity = 1; setTimeout(() => { messageElement.textContent = ""; messageBarElement.style.left = "0px"; // 重置光标到开头 typeMessage(messages[currentMessageIndex]); }, 500); }, 500); } }, 30); } imageElement.src = images[currentMessageIndex]; typeMessage(messages[currentMessageIndex]);
核心修改说明
- 定位基准修正:将
#message设为position: relative,让光标相对文本容器定位,而非父级容器。 - 动态宽度计算:使用
getBoundingClientRect().width获取文本实时宽度,替代固定字符宽度估算,确保光标位置准确。 - 删除同步处理:在删除文本过程中同步更新光标位置,保持跟随效果。
- 冗余元素清理:移除HTML中静态的
message-bar,避免与JS动态创建的元素冲突。
内容的提问来源于stack exchange,提问作者Vitor Moreira
相关产品推荐
相关产品推荐

