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

如何让可折叠容器响应Transition属性?我的实现为何无平滑效果?

问题:实现Obsidian式平滑折叠容器失败,过渡效果生硬

我想做一个类似Obsidian Callouts的可点击折叠容器,核心要实现平滑展开/收起的过渡效果。通过控制台查看Obsidian的HTML,发现它是动态修改内容div的样式:

  • 展开状态:style=""
  • 收起状态:style="display:none"
  • 展开过渡中:style="overflow-y: clip; height: 98px; transition: all 100ms cubic-bezier(0.02, 0.01, 0.47, 1) 0s;"
  • 收起过渡中:style="overflow-y: clip; height: 0px; transition: all 100ms cubic-bezier(0.02, 0.01, 0.47, 1) 0s;"

我发现它的高度会根据内容自动调整,于是用纯JS/CSS/HTML写了个简易版本,但切换时过渡效果还是很生硬,是不是我对Transition属性的理解有误?

我的代码如下:

代码片段

JavaScript

const Body = document.body
const FoldableContainer = document.createElement("div")
const FoldableHeader = document.createElement("div")
const FoldableContent = document.createElement("div")

FoldableHeader.innerHTML = "Clikc To Open"
FoldableHeader.addEventListener("click", ()=>{
    FoldableContainer.classList.toggle("open")
    if(FoldableContainer.classList.contains("open")){
        FoldableContent.style.display = "inline"
        FoldableContent.style.height = "300px"
    }else{
        FoldableContent.style.display = "none"
        FoldableContent.style.height = "0px"
    }
    
})
FoldableContainer.className = "Container"
FoldableContainer.style.height = "auto"
FoldableContainer.style.padding = "50px"
FoldableContainer.style.width = "200px"
FoldableContainer.style.background = "#affaf7"
FoldableContainer.appendChild(FoldableHeader)

FoldableContent.innerHTML = "I am Text!. Infact im so much text that i make the Folable Container Div Larger!"
FoldableContent.style.backgroundColor = "#8fbdbb"
FoldableContent.style.transition = "all 1s"
FoldableContent.style.display = "none"
FoldableContent.style.height = "0px"
FoldableContainer.appendChild(FoldableContent)


Body.appendChild(FoldableContainer)

CSS

html {
    background-color: #FFFFFF;
    display: flex;
    justify-content: center;
}
div{
    user-select: none;
    transition: all 1s;
}

HTML

<!doctype html>

<html>
    <head>
        <link rel ="stylesheet" href="styles.css">
    </head>
    <body></body>
    <script src="script.js"></script>
</html>

解决方案

你的问题核心在于错误使用了display: none——CSS过渡对display属性无效,一旦设置display: none,元素会立刻消失,过渡效果根本没机会触发。另外,硬写固定高度300px,也没法像Obsidian那样自适应内容高度。

修正思路:

  1. 抛弃display: none,用height: 0配合overflow: hidden实现收起状态,让过渡能作用在height属性上。
  2. 展开时不要写固定高度,先获取内容的真实高度,再把这个值设为元素的height,实现自适应。
  3. 收起时把height设回0即可。

下面是修正后的代码:

修正后的JavaScript

const Body = document.body
const FoldableContainer = document.createElement("div")
const FoldableHeader = document.createElement("div")
const FoldableContent = document.createElement("div")

FoldableHeader.innerHTML = "Click To Open"
FoldableHeader.addEventListener("click", ()=>{
    FoldableContainer.classList.toggle("open")
    if(FoldableContainer.classList.contains("open")){
        // 获取内容的真实高度(包括溢出部分)
        const contentHeight = FoldableContent.scrollHeight + "px"
        FoldableContent.style.height = contentHeight
    }else{
        FoldableContent.style.height = "0px"
    }
})

// 容器样式
FoldableContainer.className = "Container"
FoldableContainer.style.padding = "50px"
FoldableContainer.style.width = "200px"
FoldableContainer.style.background = "#affaf7"
FoldableContainer.appendChild(FoldableHeader)

// 内容区域样式
FoldableContent.innerHTML = "I am Text! In fact I'm so much text that I make the Foldable Container Div Larger! 这里可以加更多测试文本,看看自适应效果如何..."
FoldableContent.style.backgroundColor = "#8fbdbb"
FoldableContent.style.transition = "height 0.3s cubic-bezier(0.02, 0.01, 0.47, 1)"
FoldableContent.style.height = "0px"
FoldableContent.style.overflow = "hidden" // 关键:隐藏溢出内容,避免高度为0时内容外露
FoldableContainer.appendChild(FoldableContent)

Body.appendChild(FoldableContainer)

修正后的CSS(简化版)

html {
    background-color: #FFFFFF;
    display: flex;
    justify-content: center;
    padding-top: 50px;
}
div{
    user-select: none;
}
.Container {
    transition: all 0.3s;
}

额外说明

  • 使用scrollHeight获取元素的真实内容高度,确保展开时能完美适配内容长度。
  • 把过渡属性明确指定为height,比all更高效,避免不必要的属性过渡。
  • 保留Obsidian的缓动函数cubic-bezier(0.02, 0.01, 0.47, 1),让过渡效果更贴近原版。
  • 收起时元素只是高度变为0,并没有消失,所以过渡能正常触发,实现平滑动画。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 18:56:21