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

如何为Read More/Read Less功能添加过渡动画效果?

问题描述

我写了一个函数,通过计算两个div的高度差得到参考高度,以此设置div高度来隐藏部分段落文本;点击「Read More」展开内容,点击「Read Less」收起。但给div加展开收起的过渡效果时遇到问题,用textElement.style.transition = 'height 2s ease'完全没效果。附上我的HTML、CSS、JavaScript代码,求告知错误原因和其他实现过渡缓动效果的方法。


原始代码

HTML

<section class="productInfo">
  <div id="x">Breadcrumbs</div>
  <div class="product-name">Name</div>
  <div class="price"></div>
  <div class="product-descrip">
    <h2 id="y">Description</h2>
    <div class="text cut-off show-more-height toggle">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id ultricies ligula. Duis quam nisi, tristique vitae vestibulum in, lobortis at sapien. Nullam porttitor congue elementum. Suspendisse nec ornare metus, non molestie massa. Proin ut sem ullamcorper, fermentum leo sed, hendrerit risus. Phasellus fringilla magna non mauris sodales, ac maximus turpis volutpat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent maximus luctus diam. Nulla quam magna, efficitur in orci at, dignissim suscipit elit. Etiam consequat congue massa, eget suscipit lacus lobortis ullamcorper.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id ultricies ligula. Duis quam nisi, tristique vitae vestibulum in, lobortis at sapien. Nullam porttitor congue elementum. Suspendisse nec ornare metus, non molestie massa. Proin ut sem ullamcorper, fermentum leo sed, hendrerit risus. Phasellus fringilla magna non mauris sodales, ac maximus turpis volutpat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent maximus luctus diam. Nulla quam magna, efficitur in orci at, dignissim suscipit elit. Etiam consequat congue massa, eget suscipit lacus lobortis ullamcorper.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id ultricies ligula. Duis quam nisi, tristique vitae vestibulum in, lobortis at sapien. Nullam porttitor congue elementum. Suspendisse nec ornare metus, non molestie massa. Proin ut sem ullamcorper, fermentum leo sed, hendrerit risus. Phasellus fringilla magna non mauris sodales, ac maximus turpis volutpat. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent maximus luctus diam. Nulla quam magna, efficitur in orci at, dignissim suscipit elit. Etiam consequat congue massa, eget suscipit lacus lobortis ullamcorper.</p>
    </div>
    <div class="flex test">
            <h2 class="dropdown-header show-more">Read More</h2>
           
          </div>
  </div>
</section>

CSS

.productInfo {
  text-align: center;
}

.text {
  transition: height 2s ease;
}
.cut-off {
    --mask: linear-gradient(
            to bottom,
            rgba(0, 0, 0, 1) 0,
            rgba(0, 0, 0, 1) 60%,
            rgba(0, 0, 0, 0) 95%,
            rgba(0, 0, 0, 0) 0
        )
        100% 50% / 100% 100% repeat-x;

    -webkit-mask: var(--mask);
     mask: var(--mask);
}

JavaScript

distY = y.offsetTop - x.offsetTop;
// alert(Math.floor(distY));
console.log(Math.floor(distY));
window.addEventListener("load", function () {
    var x = document.getElementById("x");
    var y = document.getElementById("y");
    var target = document.querySelector(".show-more-height");
    var showMoreButton = document.querySelector(".test");
    var updatedHeight;

    function adjustHeight() {
        var referenceHeight = y.offsetTop - x.offsetTop;
        console.log(referenceHeight);
        if (referenceHeight <= 50) {
            updatedHeight = referenceHeight + "px";
            target.style.height = updatedHeight;
        } else {
            updatedHeight = referenceHeight + "px";
            target.style.height = updatedHeight;
        }

        return updatedHeight;
    }

    adjustHeight();

    // window.addEventListener('resize', adjustHeight);

    // Read more event
    var showMoreButton = document.querySelector(".show-more");
    var textElement = document.querySelector(".text");
    var adjHeight = adjustHeight();

    showMoreButton.addEventListener("click", function () {
        if (textElement.classList.contains("show-more-height")) {
            showMoreButton.textContent = "Read Less";
            textElement.style.height = null;
            textElement.style.transition = 'max-height 2s ease';
          target.style.transition = 'max-height 2s ease';
            target.classList.remove("cut-off");
        } else {
            showMoreButton.textContent = "Read More";
            textElement.style.height = adjHeight;
            textElement.style.transition = 'max-height 2s ease';
            target.style.transition = 'max-height 2s ease';
            console.log(adjHeight)
            target.classList.add("cut-off");
        }

        textElement.classList.toggle("show-more-height");
    });
});

错误原因分析
  1. 过渡属性不匹配+auto高度无法过渡:CSS里给.text设置的是height过渡,但JS里切换时直接把height设为null(元素回到auto高度),而CSS过渡不支持auto值的动画,这是核心问题。
  2. 过渡时机错误:你在点击事件里才动态添加过渡样式,此时元素的高度变化已经触发,过渡无法生效;同时操作textElement和target两个元素的过渡,容易造成冲突。
  3. 遮罩与动画不同步:cut-off类的遮罩效果会突然出现/消失,和高度变化节奏不一致,视觉上显得突兀。

修复方案(基于max-height实现平滑过渡)

步骤1:修改CSS

统一用max-height实现过渡,同时给遮罩也加上过渡效果,确保视觉同步:

.productInfo {
  text-align: center;
}

.text {
  max-height: 50px; /* 初始高度,后续由JS动态修改 */
  overflow: hidden;
  transition: max-height 0.6s ease, mask 0.6s ease; /* 同时过渡高度和遮罩 */
}

/* 展开状态的类 */
.text.expanded {
  max-height: 2000px; /* 设置足够大的值,确保容纳所有内容 */
}

.cut-off {
  --mask: linear-gradient(
          to bottom,
          rgba(0, 0, 0, 1) 0,
          rgba(0, 0, 0, 1) 60%,
          rgba(0, 0, 0, 0) 95%,
          rgba(0, 0, 0, 0) 0
      )
      100% 50% / 100% 100% repeat-x;

  -webkit-mask: var(--mask);
  mask: var(--mask);
}

/* 展开时移除遮罩 */
.text.expanded.cut-off {
  -webkit-mask: none;
  mask: none;
}

步骤2:优化JavaScript

改用类切换控制状态,避免直接操作style,同时正确计算初始高度:

window.addEventListener("load", function () {
    const x = document.getElementById("x");
    const y = document.getElementById("y");
    const textElement = document.querySelector(".text");
    const showMoreButton = document.querySelector(".show-more");
    
    // 计算参考高度并设置初始max-height
    function setInitialHeight() {
        const referenceHeight = y.offsetTop - x.offsetTop;
        textElement.style.maxHeight = `${referenceHeight}px`;
        return referenceHeight;
    }
    
    setInitialHeight();
    
    // 点击事件处理
    showMoreButton.addEventListener("click", function () {
        const isExpanded = textElement.classList.toggle("expanded");
        
        // 切换按钮文字和遮罩类
        showMoreButton.textContent = isExpanded ? "Read Less" : "Read More";
        textElement.classList.toggle("cut-off", !isExpanded);
    });

    // 可选:窗口 resize 时重新计算高度
    // window.addEventListener('resize', setInitialHeight);
});

关键改进点

  • 用类切换代替直接修改style,代码更简洁,过渡时机更准确
  • 用max-height代替height,解决auto高度无法过渡的问题
  • 把mask属性加入过渡,让遮罩和高度变化同步,视觉更流畅
  • 避免重复选择DOM元素,提升性能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:24:59