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

Next.js自定义Accordion向上收起正常但向下展开无动画问题

问题分析与修复方案

你的问题核心在于**display: none直接切换会打断CSS过渡动画**:展开时你直接将元素从display: none改为block,浏览器不会计算transform的过渡过程,而是直接渲染最终状态;而收起时你用setTimeout延迟设置display: none,动画已经完成,所以能正常生效。

修复步骤

1. 调整JS逻辑,确保展开时先渲染初始状态再触发动画

移除手动控制display的冗余代码,改用requestAnimationFrame让浏览器先渲染元素的初始隐藏状态,再执行展开动画;收起时等待动画完成后再隐藏元素。

修改后的JS代码:

import { useState, useRef } from "react";
import styles from "./AsideCheckout.module.css";

const AsideCheckout = (props) => {
    const [isExpanded, setIsExpanded] = useState(false);
    const asideRef = useRef(null);

    const toggleAccordion = () => {
        if (!isExpanded) {
            // 展开:先让元素可见,等待浏览器渲染初始transform状态
            asideRef.current.style.display = "block";
            requestAnimationFrame(() => {
                setIsExpanded(true);
            });
        } else {
            // 收起:先触发动画,完成后再隐藏元素
            setIsExpanded(false);
            setTimeout(() => {
                asideRef.current.style.display = "none";
            }, 700); // 时长和CSS过渡时间保持一致
        }
    };

    return (
        <>
            <div className={styles.aside_accordion_button} onClick={toggleAccordion}>
                <button>CLICK</button>
            </div>
            <aside 
                ref={asideRef} 
                className={`${styles.aside_checkout} ${isExpanded ? styles.aside_show_checkout : ""}`}
                style={{ display: isExpanded ? "block" : undefined }}
            >
                ... aside content etc
            </aside>
        </>
    );
};

export default AsideCheckout;

2. 简化CSS,保留核心过渡逻辑

将初始隐藏的display: none写在默认类里,无需手动在JS初始化:

.aside_checkout {
    grid-column: 1;
    grid-row: -2;
    overflow-y: hidden;
    transform: translateY(-100%);
    transition: transform 0.7s ease-in-out;
    display: none; /* 初始隐藏,不占用页面空间 */
}

.aside_show_checkout {
    transform: translateY(0);
    transition: transform 0.7s ease-out;
}

.aside_accordion_button {
    grid-row: -3;
    display: flex;
    /* 其他自定义样式 */
}

修复原理

  • 展开时:先设置display: block让元素进入DOM流,此时元素处于transform: translateY(-100%)的隐藏状态;通过requestAnimationFrame等待浏览器完成这一帧渲染后,再添加展开类,浏览器会自动计算从-100%到0的过渡动画。
  • 收起时:先移除展开类触发收起动画,等待动画完成后再设置display: none,既保证动画流畅,又能让元素收起后不占用空间,下方内容自动上移。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:17:51