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

如何为可伸缩的span元素实现单View Transition过渡效果?

解决View Transition API过渡仅作用于目标文本的问题

当前你的过渡效果会覆盖整个页面,核心原因是:

  1. 全局的::view-transition-old(*)/::view-transition-new(*)选择器会匹配所有过渡元素,没有限定范围;
  2. 目标文本容器没有设置合适的布局属性,导致过渡伪元素默认继承全屏尺寸。

以下是修正后的实现方案,确保过渡仅作用于目标文本:

修正后的CSS

/* 让目标文本容器以inline-block布局,过渡基于文本实际尺寸 */
.terminal-inverted {
    display: inline-block;
    position: relative;
    overflow: hidden;
    background: #000;
    color: #fff;
    padding: 2px 4px;
}

/* 仅匹配我们自定义的view-transition-name前缀(t_)的过渡元素 */
::view-transition-old([view-transition-name^="t_"]),
::view-transition-new([view-transition-name^="t_"]) {
    height: auto;
    width: auto;
    max-width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background: inherit;
    color: inherit;
}

@keyframes transition-out {
    from {
        max-width: 100%;
        opacity: 1;
        white-space: nowrap;
    }
    to {
        max-width: 0;
        opacity: 0;
        white-space: nowrap;
        overflow: hidden;
    }
}

@keyframes transition-in {
    from {
        max-width: 0;
        opacity: 0;
        white-space: nowrap;
        overflow: hidden;
    }
    to {
        max-width: 100%;
        opacity: 1;
        white-space: nowrap;
    }
}

/* 为旧元素和新元素分别绑定动画 */
::view-transition-old([view-transition-name^="t_"]) {
    animation: 0.5s transition-out ease forwards;
}

::view-transition-new([view-transition-name^="t_"]) {
    animation: 0.5s transition-in ease forwards;
}

简化版核心JS(直接操作DOM)

let id = 0;
const container = document.getElementById('text-container');

async function animate(messages, time) {
    const messagesCopy = [...messages];
    const empty = createTextElement(' ');
    const first = createTextElement(messagesCopy.shift());
    
    if (document.startViewTransition) {
        container.appendChild(empty);
        let currentElement = empty;
        
        // 首次过渡:空文本 → 第一个内容
        const transitionInit = document.startViewTransition(() => {
            container.replaceChild(first, currentElement);
            currentElement = first;
        });
        await transitionInit.finished;
        await delay(time);
        
        // 循环切换后续内容
        for (const message of messagesCopy) {
            // 先过渡到空
            const emptyElement = createTextElement(' ');
            const transitionOut = document.startViewTransition(() => {
                container.replaceChild(emptyElement, currentElement);
                currentElement = emptyElement;
            });
            await transitionOut.finished;
            
            // 再过渡到目标文本
            const targetElement = createTextElement(message);
            const transitionIn = document.startViewTransition(() => {
                container.replaceChild(targetElement, currentElement);
                currentElement = targetElement;
            });
            await transitionIn.finished;
            await delay(time);
        }
    } else {
        // 降级处理:无过渡直接切换
        let currentElement = createTextElement(messagesCopy.shift());
        container.appendChild(currentElement);
        await delay(time);
        
        for (const message of messagesCopy) {
            const targetElement = createTextElement(message);
            container.replaceChild(targetElement, currentElement);
            currentElement = targetElement;
            await delay(time);
        }
    }
    id++;
}

// 创建带唯一view-transition-name的文本元素
function createTextElement(text) {
    const span = document.createElement('span');
    span.className = 'terminal-inverted';
    span.style.viewTransitionName = `t_${id}`;
    span.textContent = text;
    return span;
}

// 通用延迟函数
function delay(time) {
    return new Promise(resolve => setTimeout(resolve, time));
}

// 启动演示
animate(['Hello', 'View Transition', 'API', 'Custom Demo'], 1500);

关键调整说明

  • 布局约束:给文本容器设置display: inline-block,让过渡伪元素的尺寸贴合文本实际宽度,而非全屏。
  • 精准选择:使用[view-transition-name^="t_"]属性选择器,仅对我们自定义命名的过渡元素生效,避免影响全局。
  • 动画优化:添加white-space: nowrap和overflow: hidden,防止文本在过渡过程中换行,保证动画的流畅性。
  • 定位控制:将过渡伪元素设为absolute,相对于原文本容器定位,确保过渡效果完全覆盖目标文本区域。

内容的提问来源于stack exchange,提问作者jcubic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 15:27:49