You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:35:24