Search code examples
javascripthtmlcsscss-transitionssticky

CSS transition fails when class of sticky element changes


I want to do a transition when the element gets sticky. But it can't be done with this below code.

const content = document.querySelector('.contents');
const initalPos = content.offsetTop;

window.addEventListener("scroll", () => {
  if(content.offsetTop > initalPos) {
    content.classList.add('stuck');
  } else {
    content.classList.remove('stuck');
  }
});
body {
  height: 300vh;
}

.contents {
  margin-top: 50px;
  border: 1px solid black;
  position: sticky;
  top: 0;
  transition: height 3s;
}

.stuck {
  height: 100px;
  background-color: green;
}
<div class="contents">
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. 
</div>

I think apply the CSS transition correctly, what did I miss?


Solution

  • You gotta have an initial fixed height for the transition to work, yet if you don't want this, you can set it programmatically after it's been calculated like this

    const content = document.querySelector('.contents');
    const initalPos = content.offsetTop;
    content.style.height = content.clientHeight + 'px';
    
    window.addEventListener("scroll", () => {
      content.classList.toggle('stuck', content.offsetTop > initalPos);
    });
    body {
      height: 300vh;
    }
    
    .contents {
      margin-top: 50px;
      border: 1px solid black;
      position: sticky;
      top: 0;
      transition: height 3s;
    }
    
    .stuck {
      height: 100px !important;
      background-color: green;
    }
    <div class="contents">
      Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. 
    </div>