How to animate height with transform without squeezing content
P粉208469050
P粉208469050 2024-01-01 11:51:20
0
1
413

In my project, I have been using jQuery slideUp() to slide up an element in a 200-item list when the user clicks a button. However, CSS height animations are known to require reflow, resulting in unstable animations. The animation is an integral part of the application and I'm willing to do a lot of work to make it work and work smoothly.

I decided that CSS transform was the way to make it work smoothly since it's processed on the GPU and on some modern browsers it's even off the main thread and heavy JS work won't Affect transformation. (I do have heavy JS work).

I'm looking for a neat solution using CSS transition:transform to replicate jQuery slideUp, which just animates the height property. Below is my attempt, but it seems that scale and translate are not synced as expected.

$("button").on("click", function() {
  $(".collapsible").addClass("collapsed")
  setTimeout(function() {
    $(".collapsible").removeClass("collapsed")
  }, 5000);
});
.list-item {
  width: 400px;
  height: 100px;
  background-color: blue;
  margin-top: 10px;
  overflow-y: hidden;
}

.collapsible.collapsed .content {
  transition: transform 3s linear;
  transform: scale(1, 1) translate(0, -100%);
}

.collapsible.collapsed {
  transition: transform 3s linear;
  transform: translate(0, -50%) scale(1, 0);
}

.collapsible.collapsed ~ .list-item {
  transition: transform 3s linear;
  transform: translate(0, -100%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<button>Collapse</button>
<div class="list-item collapsible">
  <div class="content">
    Just an example <br>
    Just an example <br>
    Just an example <br>
    Just an example <br>
    Just an example <br>
  </div>
</div>
<div class="list-item">
  
</div>
<div class="list-item">
  
</div>

I made some modifications to the values ​​and made it so by changing the content transform to transform:scale(1, 3) translate(0, -50%); Its closer.

It seems I've come very close to achieving my goal, but never quite succeeded. Are there any ready-made tricks to do this?

Require:

  • It’s better not to have JS
  • Leave the main thread

P粉208469050
P粉208469050

reply all(1)
P粉005134685

After a few nights of sleep, I found a solution that fits my needs perfectly. I had to use three layers of div and make sure the inner two layers were set to height: 100%;. Then I unchecked the scale() and used transform() to slide the middle layer up.

This meets my requirements:

  • Using Transform(), it should run up to 60fps on the GPU
  • Will not use Scale() to compress content
  • Content disappears from bottom to top like jQuery SlideUp()
  • Regardless of the height of the target element, other elements below will slide up to fill the gap
  • Once the animation is triggered, JS is no longer involved

$("button").on("click", function() {
  const height = $(".collapsible").css("height");
  $(":root").css("--height", height);
  $(".collapsible").addClass("collapsed");
  setTimeout(function() {
    $(".collapsible").removeClass("collapsed");
  }, 4000);
});
:root {
  --height: unset;
}

.outer-container {
  width: 400px;
  height: fit-content;
  background-color: transparent;
  margin-top: 10px;
  overflow-y: hidden;
}

.inner-container {
  height: 100%;
  background-color: blue;
  overflow: hidden;
}

.content {
  height: 100%;
}

.collapsible.collapsed .inner-container {
  transition: transform 3s linear;
  transform: translate(0, -100%);
}

.collapsible.collapsed .content {
  transition: transform 3s linear;
  transform: translate(0, 100%);
}

.collapsible.collapsed ~ .outer-container {
  transition: transform 3s linear;
  transform: translate(0, calc((var(--height) * -1) - 10px));
}

.collapsible .inner-container {
  transition: transform .5s ease-in-out;
  transform: translate(0, 0);
}

.collapsible .content {
  transition: transform .5s ease-in-out;
  transform: translate(0, 0);
}

.collapsible ~ .outer-container {
  transition: transform .5s ease-in-out;
  transform: translate(0, 0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
<button>Collapse</button>
<div class="outer-container">
  <div class="inner-container">
    <div class="content">
      Just an example <br>
      Just an example <br>
      Just an example <br>
      Just an example <br>
    </div>
  </div>
</div>
<div class="outer-container collapsible">
  <div class="inner-container">
    <div class="content">
      Just an example <br>
      Just an example <br>
      Just an example <br>
      Just an example <br>
      Just an example <br>
    </div>
  </div>
</div>
<div class="outer-container">
  <div class="inner-container">
    <div class="content">
      Just an example <br>
      Just an example <br>
      Just an example <br>
    </div>
  </div>
</div>
<div class="outer-container">
  <div class="inner-container">
    <div class="content">
      Just an example <br>
      Just an example <br>
      Just an example <br>
      Just an example <br>
    </div>
  </div>
</div>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template