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

React组件中CSS Transition动画不生效,需实现内容展开推挤下方元素

问题:CSS Transition高度过渡动画不生效,高度瞬间切换

我用React实现了一个展开/收起组件:通过按钮切换div的height样式属性(0和100%),已经给该div配置了CSS Transition属性,但实际效果是高度瞬间切换,过渡时长只起到了延迟作用,没有预期的平滑动画。

试过用position: fixed能实现动画,但会导致内容覆盖下方元素,我需要展开时能推挤下面的内容。

组件代码

const Component = () => {
  const [isOpen, setOpen] = useState(false);

  return (  
    <div>
      <button onClick={() => setOpen(!isOpen)}>Show Content</button>
      <div className="content" style={{ height: isOpen ? "100%" : 0 }}>
        <p>Content</p>
      </div>
    </div>
  );
};

CSS代码

.content {
  height: 0;
  overflow: hidden;
  transition: height ease 0.5s;
  border-style: solid;
}

解决方法

原因

CSS Transition无法在0和100%这类百分比高度值之间计算过渡动画——因为浏览器无法确定100%对应的具体像素高度(除非父元素有固定高度),所以只能直接跳变。

方案1:使用内容实际像素高度切换

通过Ref获取内容的实际高度,用具体像素值代替百分比来触发过渡:

import { useState, useRef, useEffect } from 'react';

const Component = () => {
  const [isOpen, setOpen] = useState(false);
  const contentRef = useRef(null);
  const [contentHeight, setContentHeight] = useState(0);

  useEffect(() => {
    if (isOpen) {
      // 展开时获取内容实际高度
      setContentHeight(`${contentRef.current.scrollHeight}px`);
    } else {
      // 收起时先设置为实际高度,再延迟设为0触发过渡
      setContentHeight(`${contentRef.current.scrollHeight}px`);
      const timer = setTimeout(() => {
        setContentHeight(0);
      }, 10);
      return () => clearTimeout(timer);
    }
  }, [isOpen]);

  return (  
    <div>
      <button onClick={() => setOpen(!isOpen)}>Show Content</button>
      <div 
        ref={contentRef}
        className="content" 
        style={{ height: contentHeight }}
      >
        <p>Content</p>
        <p>可以添加更多内容测试效果</p>
      </div>
    </div>
  );
};

CSS保持原代码不变即可。

方案2:用max-height替代height

设置一个足够大的max-height值,通过切换max-height实现过渡(更简单但需注意max-height的取值):

.content {
  max-height: 0;
  overflow: hidden;
  transition: max-height ease 0.5s;
  border-style: solid;
}
.content.open {
  max-height: 500px; /* 设一个比内容最大高度大的数值 */
}
const Component = () => {
  const [isOpen, setOpen] = useState(false);

  return (  
    <div>
      <button onClick={() => setOpen(!isOpen)}>Show Content</button>
      <div className={`content ${isOpen ? 'open' : ''}`}>
        <p>Content</p>
      </div>
    </div>
  );
};

注意:max-height的值不要设得过大,否则动画前半段会显得很快(因为大部分高度是空白),尽量贴近内容的实际最大高度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:05:38