You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现适配任意字符数的动态CSS打字机效果

如何实现适配任意字符数的动态CSS打字机效果

这个手动数字符改CSS的痛点我太懂了——要是有几十段内容要做这个效果,每段都要数字符、改硬编码的数字,简直是重复劳动的噩梦。下面给你两种实用方案,从基础动态适配到视口懒加载优化,完美解决这个问题:


方案一:基础动态适配(页面加载时自动适配所有段落)

核心思路是用JavaScript获取每个段落的字符长度,注入CSS变量,让CSS动画自动读取变量值,不用再硬编码数字。

完整代码示例

HTML(统一类名方便批量控制)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dynamic Typewriter</title>
    <link rel="stylesheet" href="type.css">
</head>
<body>
    <div class="wrapper">
        <p class="typewriter">This is a dynamic typing test for English text.</p>
        <p class="typewriter">这是一段中文测试文本,不用手动数字符也能适配效果</p>
        <p class="typewriter">Short line!</p>
    </div>
    <script src="type.js"></script>
</body>
</html>

CSS(用CSS变量替代硬编码数值)

.wrapper {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    gap: 2rem;
    align-items: center;
    justify-content: center;
    padding: 2rem;
}

.typewriter {
    font-family: monospace;
    font-size: 1.2rem;
    border-right: 3px solid #000;
    white-space: nowrap;
    overflow: hidden;
    width: 0;
    /* 用CSS变量控制动画参数 */
    animation: blink 0.5s infinite step-end;
    animation-play-state: paused;
}

/* 只有当元素被激活时,才播放打字动画 */
.typewriter.active {
    animation: 
        typing calc(var(--typing-speed) * var(--char-count)) steps(var(--char-count)),
        blink 0.5s infinite step-end;
    animation-play-state: running;
}

@keyframes blink {
    0%, 100% { border-color: transparent; }
    50% { border-color: #000; }
}

@keyframes typing {
    to { width: var(--char-count)ch; }
}

JavaScript(注入动态CSS变量)

document.addEventListener('DOMContentLoaded', () => {
    // 选中所有需要打字机效果的元素
    const typewriterEls = document.querySelectorAll('.typewriter');

    typewriterEls.forEach(el => {
        // 计算文本字符数(trim()可去掉首尾空白,按需选择)
        const charCount = el.textContent.trim().length;
        // 设置字符数字量
        el.style.setProperty('--char-count', charCount);
        // 设置单字符打字时长(比如0.15秒/字符,总时长自动计算)
        el.style.setProperty('--typing-speed', 0.15);
        // 激活动画
        el.classList.add('active');
    });
});

代码说明

  1. 给所有目标段落加.typewriter类,统一管理样式
  2. CSS用var(--char-count)替代原来的硬编码数字,通过calc()结合单字符时长,让长/短文本的打字速度保持一致
  3. JS在DOM加载完成后,自动遍历每个元素,计算字符长度并注入CSS变量,完全实现动态适配

方案二:视口触发的懒加载优化(适合长页面)

如果你的页面内容很多,一开始就给所有元素加动画会浪费性能。可以用Intersection Observer API,让元素进入视口才开始打字动画:

修改后的JavaScript代码

document.addEventListener('DOMContentLoaded', () => {
    const typewriterEls = document.querySelectorAll('.typewriter');

    // 创建视口观察器
    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const el = entry.target;
                const charCount = el.textContent.trim().length;
                el.style.setProperty('--char-count', charCount);
                el.style.setProperty('--typing-speed', 0.15);
                el.classList.add('active');
                // 触发后取消观察,避免重复执行
                observer.unobserve(el);
            }
        });
    }, { threshold: 0.1 }); // 元素10%进入视口时触发

    // 开始观察所有目标元素
    typewriterEls.forEach(el => observer.observe(el));
});

特殊字符/中文适配小技巧

如果你的文本包含中文、emoji等特殊字符,ch单位可能会出现宽度偏差(因为1ch是当前字体下"0"的宽度,中文通常占2ch)。这时候可以改用元素的实际宽度来适配:

  1. 把CSS的打字动画改成:
@keyframes typing {
    to { width: var(--element-width)px; }
}
  1. JS里用scrollWidth获取元素实际宽度:
// 替换原来的charCount计算逻辑
const elementWidth = el.scrollWidth;
el.style.setProperty('--element-width', elementWidth);
// 同时steps的参数可以用charCount,不影响打字的分步效果
el.style.setProperty('--char-count', el.textContent.trim().length);

额外注意事项

  • 如果文本是动态加载的(比如AJAX获取),需要在文本加载完成后,重新调用一次变量注入的逻辑(可以把这部分代码封装成函数,方便复用)
  • 可以根据需求调整--typing-speed的值,数值越小打字速度越快
  • 若要支持多行文本打字效果,只需要把white-space: nowrap改成white-space: pre-wrap,同时调整动画的width100%即可(不过多行打字的逻辑会更复杂,建议单段落单独处理)

这样一来,不管你有多少段内容,只要加个.typewriter类,就能自动适配打字机效果,再也不用手动数字符啦! 🎉

火山引擎 最新活动