javascripthtmlcss-animationsabsolute

Best Way To Crossfade Text With a Fixed Height in an Absolute Div?


I want to crossfade several text quotes (coming from a CMS) having various lengths within a container div of a specific width. This is what I came up with, but it's 2024 and I feel like there has to be an easier way to do this, either using only CSS or not having to resort to using onResize. What I'm doing is looping through all the quotes twice: one for display and the other for size calculation - determining the tallest quote and setting the parent div to that height.

I don't want to resort to importing a gallery/carousel library or js framework as a dependency for something that seems so simple. Just wondering if anyone has any ideas on simplifying this. Thanks!


screenshot of codepen


Solution

  • You could consider using a CSS grid system. Have the .wrapper be a grid layout consisting of one single grid area. Have the quotes all occupy this same grid area. This allows them to overlap, while having the tallest one dictate the size of the grid element.

    const wrapperEl = document.getElementById('wrapper')
    
    const animTimer = setInterval(() => {
      if (!wrapperEl) {
        return
      }
    
      const active = wrapperEl.querySelector('.active')
      let next = active?.nextElementSibling
      if (!next) {
        next = active?.parentElement?.firstElementChild
      }
    
      active?.classList.remove('active')
      next?.classList.add('active')
    }, 4500)
    :root {
      --width: 70%;
    }
    
    .wrapper {
      display: grid;
      grid-template: 1fr / 1fr;
      align-items: center;
      width: var(--width);
      /* or any specific width */
      min-height: 200px;
      background-color: #efefef;
      overflow: hidden;
    }
    
    .wrapper>div {
      opacity: 0;
      grid-area: 1 / 1 / -1 / -1;
      /* padding: 20px; */
      font-size: 40px;
      font-weight: bold;
      background-color: #ccf;
      transition: opacity 0.5s;
    }
    
    .wrapper .active {
      opacity: 1;
    }
    
    blockquote {
      margin: 0;
      padding: 0;
    }
    
    cite {
      display: inline-block;
      font-size: 1.5rem;
      padding-block-start: 20px;
    }
    
    p {
      width: var(--width);
    }
    <p>
      Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site.
    </p>
    <div id="wrapper" class="wrapper">
      <div class="active">
        <blockquote>"This is a medium quote or possibly just a regular one."</blockquote>
        <cite>-Mark Twain</cite>
      </div>
      <div>
        <blockquote>"This is a short quote."</blockquote>
        <cite>-Jeb Lawrence</cite>
      </div>
      <div>
        <blockquote>"This is quite possibly the longest quote known to anyone who has lived on earth and ever knew anything about what it takes to make a good quote."</blockquote>
        <cite>-Morgan Freeman</cite>
      </div>
      <div>
        <blockquote>"This is another somewhat long quote, or depending on your point of view, a short one."</blockquote>
        <cite>-Chris Smith</cite>
      </div>
    </div>
    
    <p>
      Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site. Welcome to this web site.
    </p>