使用纯JS动画最大高度?

时间:2017-06-09 23:24:26

标签: javascript html css css3

我想为div的高度设置动画。这通常通过动画max-height属性在CSS中完成。

但是我需要在JS中这样做。 div中填充了频繁更改的动态内容,因此事先不知道实际高度。

这是一个jsfiddle:https://jsfiddle.net/vpknxuk8/

var box = document.getElementById("box");
var button = document.getElementById("button");
var expanded = true;

button.addEventListener('click', function() {
    if (expanded) {
        box.style.maxHeight = 0;
        expanded = false;
    } else {
        box.style.maxHeight = "";
        expanded = true;
    }
});
#box {
  margin-top: 20px;
  border: 1px solid black;
  background-color: #4f88ff;
  width: 200px;
  transition: max-height 0.25s linear;
  overflow: hidden;
}
<button id="button">Click</button>

<div id="box">
  Hello World<br>
  This is dynamic content<br>
  The actual height won't be known ahead of time
</div>

该框应在高度0和默认高度之间转换,但由于某种原因,它不是动画。

StackOverflow上此问题的唯一其他版本属于仅CSS解决方案或jQuery解决方案。

5 个答案:

答案 0 :(得分:8)

不要 使用max-height ......好吧,除非您想采用仅限CSS 草率产生延迟差距问题的解决方案 - ......这就是为什么你首先复发JS的原因......

所以请使用heighttransition: height代替

首先是一个演示,而不是一些代码解释:)

&#13;
&#13;
function slidetoggle() {

  var EL = document.getElementById( this.dataset.slidetoggle ),
      ch = EL.clientHeight,
      sh = EL.scrollHeight,
      isCollapsed = !ch,
      noHeightSet = !EL.style.height;

  EL.style.height = (isCollapsed || noHeightSet ? sh : 0) +"px";
  if(noHeightSet) return slidetoggle.bind(this)();

}


document.querySelector("[data-slidetoggle]").addEventListener('click', slidetoggle);
&#13;
#box {
  overflow: hidden;
  margin-top: 20px;
  border: 1px solid #000;
  background-color: #4f88ff;
  width: 200px;
  transition: height 0.5s;
}
&#13;
<button data-slidetoggle="box">Click</button>

<div id="box">
  Hello World<br>
  This is dynamic content<br>
  The actual height won't be<br>
  known ahead of time
</div>
&#13;
&#13;
&#13;

解释和一些背景:

如果我们不设置初始高度,CSS高度转换就无法工作 所以基本上点击 - 如果这样的高度不存在,我们需要通过JS设置它 设置此类高度后,转换仍然无效,因为浏览器没有时间计算此类元素的框模型 - 过渡:

// Say the element is expanded.
// We need a height to transition-from
EL.height = calculatedHeight +"px";  // set CSS height to the calculated value
// Transition to 0px height....
EL.height = 0 +"px";
// NO DEAL. our element just snapped to 0 without transition

因此我们需要驻留某种回调 一种常见(通常是不准确的)回调是setTimeout

// Say the element is expanded.
// We need a height to transition-from
EL.height = calculatedHeight +"px";  // set CSS height to the calculated value
// Transition to 0px height giving the browser some ready-state hack
setTimeout(function() {
    // Eventually the box model will be calculated 
    EL.height = 0 +"px";
}, 0);   // <<< PROBLEM: Should we use 0 ? 10? 100? 1000? 
// and our element beautifully transitioned to 0 height.
// Eventually :(

创建此类回调的一种更好方法是在设置初始元素高度后绑定相同的函数:

function slidetoggle() {

      // Get the target ID element by reading the data attribute
  var EL = document.getElementById( this.dataset.slidetoggle ),
      // Calculate clientHeight. Even if element has no CSS height set,
      // clientHeight will hold the actual calculated height
      ch = EL.clientHeight,
      // Get scrollHeight - if element is collapsed, scrollHeight is the 
      // height we'll animate-to.
      sh = EL.scrollHeight,
      // isCollapsed if ch === 0 (or in other words !ch)
      isCollapsed = !ch,
      // If no CSS height set set a flag.
      noHeightSet = !EL.style.height;

  // set height!! CSS transition will do the animation job for us.
  // Just... hey, if initially we did not specified any CSS height,
  // we first need to set it in order to see the transition actually happen!
  EL.style.height = (isCollapsed || noHeightSet ? sh : 0) +"px";
  // if that was the case, we need to bind another slidetoggle, since the first 
  // was just used to set the initial CSS height.
  if(noHeightSet) return slidetoggle.bind(this)();

}

// Assign a click handler to any [data-slidetoggle] element
document.querySelector("[data-slidetoggle]").addEventListener('click', slidetoggle);

提示:如果您需要 paddings ,我的建议是将您的内容包装到另一个子框中 - 使用填充。

上面的代码是一个概念性和最小的代码 - 有很多改进空间,但希望你有这个想法。

答案 1 :(得分:1)

  

我首先通过检测我的元素的基础height来尝试它并使用它来处理transition,因为transition需要height才能工作。

&#13;
&#13;
var box = document.getElementById("box");
var button = document.getElementById("button");
var expanded = true;

var height = box.offsetHeight;
box.style.height = height+"px";

button.addEventListener('click', function() {
    if (expanded) {
        box.style.height = 0;
        expanded = false;
    } else {
        box.style.height = height+"px";
        expanded = true;
    }
});
&#13;
#box {
  margin-top: 20px;
  border: 1px solid black;
  background-color: #4f88ff;
  width: 300px;
  transition: height 0.25s;
  overflow: hidden;
}
&#13;
<button id="button">
Click
</button>

<div id="box">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
</div>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

试试这个:

var box = document.getElementById("box");
var button = document.getElementById("button");

//get your dynamic div's height:
var clientHeight = document.getElementById('box').clientHeight;
var expanded = true;
//define max-height property your div before collapse it. 
//otherwise it collapse without transition.
box.style.maxHeight = clientHeight+"px";
button.addEventListener('click', function() {
    if (expanded) {
        box.style.maxHeight = 0;
        expanded = false;
    } else {
        //set height
        box.style.maxHeight = clientHeight+"px";
        expanded = true;
    }
});

您可以使用.scrollHeight.offsetHeight代替.clientHeight,具体取决于具体情况。有关这些属性的详细信息,请查看此评论:https://stackoverflow.com/a/22675563/7776015

答案 3 :(得分:0)

遵循这些原则可以解决问题:

<div id="box">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
</div>
#box {
  margin-top: 20px;
  border: 1px solid black;
  background-color: #4f88ff;
  height:0px;
  width: 300px;
  transition: height 0.25s;
  overflow: hidden;
}

在请求动画帧时执行逻辑:

 requestAnimationFrame(function () {
    let boxDiv = document.getElementById("box");
    boxDiv.style.height = "200px";
   });

答案 4 :(得分:-1)

您有两个选择:

  • 转换边框和填充,使它们全部折叠在一起。

  • 将目标div包装在一个新容器中,并为其高度设置动画。你需要溢出:隐藏;。