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

如何实现点击按钮带高度动画展开段落文本且适配响应式

实现原理说明

height: auto无法触发CSS过渡的核心原因是浏览器计算过渡差值时,无法解析auto对应的明确像素值,会直接跳过动画流程;写死固定展开高度的方案天然不支持响应式——不同视口宽度下文本换行逻辑不同,内容总高度是动态变化的,固定值必然会出现内容截断或者留白问题。

以下提供两种可直接落地的实现方案:


方案1:JS动态获取内容真实高度(最优解,适配全场景)

核心逻辑是不直接用height: auto触发展开,而是通过DOM原生属性scrollHeight拿到内容的实际渲染高度,把明确像素值设为容器高度触发过渡,动画结束后再把高度切回auto避免窗口缩放时内容被截断;折叠时先把当前auto高度转成明确像素值,下一帧再切回折叠高度,保证反向动画也能正常触发。

  • 优点:动画时长完全精准,和设置的过渡参数100%匹配;全响应式适配,窗口缩放时自动调整高度;不需要提前预估内容最大高度,适配任意长度的文本

调整后的SCSS代码

.about__body{
    @include displayFlex($direction: column, $align-item: center);
    gap: 20px;
    &-content {
        height: 60px;
        overflow: hidden;
        transition: height 400ms ease-in-out; // 只过渡height属性,性能更好
    }
}
/* 展开类不需要写height值,所有高度逻辑交给JS控制 */

调整后的JS代码

const btnAbout = document.getElementById("btn--about")
const contentAbout = document.querySelector(".about__body-content")
const COLLAPSE_HEIGHT = 60 // 和CSS里配置的折叠高度保持一致

const toggleContent = () => {
    const isExpanded = contentAbout.classList.contains('about__body-content-show')
    if (isExpanded) {
        // 折叠逻辑:先把当前auto高度转成明确像素值,否则过渡无法触发
        contentAbout.style.height = `${contentAbout.scrollHeight}px`
        // 触发重绘后下一帧设置折叠高度
        requestAnimationFrame(() => {
            contentAbout.style.height = `${COLLAPSE_HEIGHT}px`
            contentAbout.classList.remove('about__body-content-show')
        })
    } else {
        // 展开逻辑:先加展开类标记状态,再设置真实内容高度触发过渡
        contentAbout.classList.add('about__body-content-show')
        const contentRealHeight = contentAbout.scrollHeight
        contentAbout.style.height = `${contentRealHeight}px`
        // 过渡结束后把高度设为auto,适配窗口大小变化
        const onTransitionEnd = () => {
            contentAbout.style.height = 'auto'
            contentAbout.removeEventListener('transitionend', onTransitionEnd)
        }
        contentAbout.addEventListener('transitionend', onTransitionEnd)
    }
}

// 监听窗口尺寸变化,展开状态下同步更新容器高度避免截断
window.addEventListener('resize', () => {
    const isExpanded = contentAbout.classList.contains('about__body-content-show')
    if (!isExpanded) return
    // 临时取消过渡,直接更新为新的内容高度
    contentAbout.style.transition = 'none'
    contentAbout.style.height = 'auto'
    const newHeight = contentAbout.scrollHeight
    contentAbout.style.height = `${newHeight}px`
    // 恢复过渡配置
    requestAnimationFrame(() => {
        contentAbout.style.transition = 'height 400ms ease-in-out'
    })
})

btnAbout.addEventListener('click', (e) => {
    e.preventDefault()
    toggleContent()
})

方案2:纯CSS实现(无需修改JS,适合简单场景)

把过渡属性从height换成max-height,折叠状态设置max-height: 60px,展开状态设置一个一定大于内容最大可能高度的max-height值即可触发过渡,原有JS切换类的逻辑完全不需要改动。

  • 缺点:需要提前预估内容的最大高度,值设小了会截断内容,设大了动画速率会失真(浏览器按设置的max-height差值计算动画进度,不是真实内容高度);反向折叠动画速度和展开时会有细微差异

SCSS代码

.about__body{
    @include displayFlex($direction: column, $align-item: center);
    gap: 20px;
    &-content {
        max-height: 60px;
        overflow: hidden;
        transition: max-height 400ms ease-in-out;
    }
}

.about__body-content-show {
    // 根据自身内容的最大可能高度设置,比如内容最多不超过500px就填500px
    max-height: 500px;
}

可选体验优化

折叠状态可以给容器底部加半透明渐变遮罩,更明确提示用户下方还有未展示内容:

.about__body-content:not(.about__body-content-show) {
    -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
    mask-image: linear-gradient(to bottom, #000 70%, transparent 100%);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:21:46