skip to Main Content

I am trying to make an image gallery that lets the user sort options by category (land, sea, animal, and more). I wrote a small example.

My goal: is that once the user selects (clicks) the category he wishes to sort by, the website will present only pictures from that specific category, while the other "unwanted" pictures will slowly disappear and move downward. Once the user changes selection, the "missing" pictures will reappear from below and go up until they reach their destination.

I did manage to make the in and out animations as well as keep the image hidden after the animation ends, but only after all relevant pictures disappear, the sorted pictures "jump" to their place instead of smoothly sliding toward their expected place.

Now I think my current problem is missing animation, but maybe I wrote something wrong in my CSS or my JS.

edit
i think i wasnt clear with my goal here, i am trying to filter out all of the photos that are not belong to the category selected and then display only the photos that belong to the category that has been choosen stacked from left to right in order in that point im stuck the images disappear but does not stack smoothly

const filterContainer = document.querySelector('.data-filters');
const photoItems = document.querySelectorAll('.photo-item');

filterContainer.addEventListener('click', (event) => {

  filterContainer.querySelector('.active-filter').classList.remove('active-filter');
  event.target.classList.add('active-filter');

  const filter = event.target.getAttribute('data-filter');

  photoItems.forEach((item) => {
    if (item.getAttribute('data-filter') == filter || filter == 'all') {
      item.classList.remove('photo-out')
      item.classList.add('photo-in')
    } else {
      item.classList.remove('photo-in')
      item.classList.add('photo-out')
    }
  })

})
.line-list li {
  display: inline-block;
  margin: 10px;
  cursor: pointer;
}

.active-filter {
  color: blue;
}

@keyframes go-out {
  0% {
    top: 0px;
    opacity: 1.0
  }
  100% {
    top: 600px;
    opacity: 0;
    display: none
  }
}

@keyframes go-in {
  100% {
    top: 0px;
    opacity: 1.0
  }
  0% {
    top: 600px;
    opacity: 0;
    display: block
  }
}

.photo-out {
  animation: go-out 1.2s forwards;
}

.photo-in {
  animation: go-in 1.2s forwards;
}
<html>

<head>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>

<body>
  <section id='photo_wall'>
    <div class='container'>
      <div class='row'>
        <div class='col-md-12 data-filters'>
          <ul class='line-list'>
            <li class='active-filter' data-filter='all'> All photos </li>
            <li data-filter='land'> Land </li>
            <li data-filter='sea'> Sea </li>
            <li data-filter='animals'> Animals </li>
          </ul>
        </div>
      </div>
      <div class='row'>
        <div class='col-md-3 photo-item p-4 photo-in' data-filter='land'>
          <img src='https://fastly.picsum.photos/id/807/200/200.jpg?hmac=Y8gayvNItiQYxP_Pd-2un9GH09XuyJdIZOQPw6K9QsI'>
        </div>
        <div class='col-md-3 col-sm-6 photo-item p-4 photo-in' data-filter='animals'>
          <img src='https://fastly.picsum.photos/id/659/200/200.jpg?hmac=kFpdD3XTBGwPUAH1tD-AiWigstjIX8WGIcyySuVQIvE' class='animals'>
        </div>
        <div class='col-md-3 col-sm-6 photo-item p-4 photo-in' data-filter='land'>
          <img src='https://fastly.picsum.photos/id/165/200/200.jpg?hmac=tQGrY9pm5ze9soSsZ5CNBt87zqnHfFwdPv_khau12Sw' class='land'>
        </div>
        <div class='col-md-3 photo-item p-4 photo-in' data-filter='sea'>
          <img src='https://fastly.picsum.photos/id/883/200/200.jpg?hmac=evNCTcW3jHI_xOnAn7LKuFH_YkA8r6WdQovmsyoM1IY' class='sea'>
        </div>
        <div class='col-md-3 photo-item p-4 photo-in' data-filter='animals'>
          <img src='https://fastly.picsum.photos/id/237/200/200.jpg?hmac=zHUGikXUDyLCCmvyww1izLK3R3k8oRYBRiTizZEdyfI' class='animals'>
        </div>
        <div class='col-md-3 photo-item p-4 photo-in' data-filter='sea'>
          <img src='https://fastly.picsum.photos/id/653/200/200.jpg?hmac=tZtho3csFdJ2rLHTTlT7WhXtDwbXgJNIIUvOQQb2dIo' class='sea'>
        </div>
      </div>
    </div>
  </section>
</body>

</html>

3

Answers


  1. Not trivial.
    Perhaps play with this

    @keyframes go-out {
      0% {
        transform: translateX(0);
        opacity: 1.0;
      }
      100% {
        transform: translateX(-100%); /* Move left by its own width */
        opacity: 0;
      }
    }
    
    @keyframes go-in {
      0% {
        transform: translateX(-100%); /* Start left by its own width */
        opacity: 0;
      }
      100% {
        transform: translateX(0);
        opacity: 1.0;
      }
    }
    
    const filterContainer = document.querySelector('.data-filters');
    const photoItems = document.querySelectorAll('.photo-item');
    
    filterContainer.addEventListener('click', (event) => {
    
      filterContainer.querySelector('.active-filter').classList.remove('active-filter');
      event.target.classList.add('active-filter');
    
      const filter = event.target.getAttribute('data-filter');
    
      photoItems.forEach((item) => {
        if (item.getAttribute('data-filter') == filter || filter == 'all') {
          item.classList.remove('photo-out')
          item.classList.add('photo-in')
        } else {
          item.classList.remove('photo-in')
          item.classList.add('photo-out')
        }
      })
    
    })
    .line-list li {
      display: inline-block;
      margin: 10px;
      cursor: pointer;
    }
    
    .active-filter {
      color: blue;
    }
    
    @keyframes go-out {
      0% {
        transform: translateX(0);
        opacity: 1.0;
      }
      100% {
        transform: translateX(-100%); /* Move left by its own width */
        opacity: 0;
      }
    }
    
    @keyframes go-in {
      0% {
        transform: translateX(-100%); /* Start left by its own width */
        opacity: 0;
      }
      100% {
        transform: translateX(0);
        opacity: 1.0;
      }
    }
    
    
    
    .photo-out {
      animation: go-out 1.2s forwards;
    }
    
    .photo-in {
      animation: go-in 1.2s forwards;
    }
    <html>
    
    <head>
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    </head>
    
    <body>
      <section id='photo_wall'>
        <div class='container'>
          <div class='row'>
            <div class='col-md-12 data-filters'>
              <ul class='line-list'>
                <li class='active-filter' data-filter='all'> All photos </li>
                <li data-filter='land'> Land </li>
                <li data-filter='sea'> Sea </li>
                <li data-filter='animals'> Animals </li>
              </ul>
            </div>
          </div>
          <div class='row'>
            <div class='col-md-3 photo-item p-4 photo-in' data-filter='land'>
              <img src='https://fastly.picsum.photos/id/807/200/200.jpg?hmac=Y8gayvNItiQYxP_Pd-2un9GH09XuyJdIZOQPw6K9QsI'>
            </div>
            <div class='col-md-3 col-sm-6 photo-item p-4 photo-in' data-filter='animals'>
              <img src='https://fastly.picsum.photos/id/659/200/200.jpg?hmac=kFpdD3XTBGwPUAH1tD-AiWigstjIX8WGIcyySuVQIvE' class='animals'>
            </div>
            <div class='col-md-3 col-sm-6 photo-item p-4 photo-in' data-filter='land'>
              <img src='https://fastly.picsum.photos/id/165/200/200.jpg?hmac=tQGrY9pm5ze9soSsZ5CNBt87zqnHfFwdPv_khau12Sw' class='land'>
            </div>
            <div class='col-md-3 photo-item p-4 photo-in' data-filter='sea'>
              <img src='https://fastly.picsum.photos/id/883/200/200.jpg?hmac=evNCTcW3jHI_xOnAn7LKuFH_YkA8r6WdQovmsyoM1IY' class='sea'>
            </div>
            <div class='col-md-3 photo-item p-4 photo-in' data-filter='animals'>
              <img src='https://fastly.picsum.photos/id/237/200/200.jpg?hmac=zHUGikXUDyLCCmvyww1izLK3R3k8oRYBRiTizZEdyfI' class='animals'>
            </div>
            <div class='col-md-3 photo-item p-4 photo-in' data-filter='sea'>
              <img src='https://fastly.picsum.photos/id/653/200/200.jpg?hmac=tZtho3csFdJ2rLHTTlT7WhXtDwbXgJNIIUvOQQb2dIo' class='sea'>
            </div>
          </div>
        </div>
      </section>
    </body>
    
    </html>
    Login or Signup to reply.
  2. I think the problem is in your event handling.
    You have to condition it to your list items only.
    You have to exclude <ul> and parent <div>.

    const filterContainer = document.querySelector('.data-filters');
    const photoItems = document.querySelectorAll('.photo-item');
    
    filterContainer.addEventListener('click', (event) => {
      const targetElement = event.target;
    
      // Condition for <li>s.
      if ('filter' in targetElement.dataset) {        
        filterContainer.querySelector('.active-filter').classList.remove('active-filter');
        event.target.classList.add('active-filter');
        
        const filter = event.target.getAttribute('data-filter');
      
        photoItems.forEach((item) => {
          if(item.getAttribute('data-filter') == filter || filter == 'all'){
            item.classList.remove('photo-out')
            item.classList.add('photo-in')
          } else {
            item.classList.remove('photo-in')
            item.classList.add('photo-out')
          }
        })
      }
    })
    .line-list li {
      display: inline-block;
      margin: 10px;
      cursor:pointer;
    }
    
    .active-filter {
      color:blue;
    }
    
    @keyframes go-out {
      0%   {top:0px;opacity:1.0}
      100% {top:600px;opacity:0;display:none}
    }
    
    @keyframes go-in {
      100%   {top:0px;opacity:1.0}
      0% {top:600px;opacity:0;display:block}
    }
    
    .photo-out {
      animation: go-out 1.2s forwards;
    }
    
    .photo-in {
      animation: go-in 1.2s forwards;
    }
    <html>
      <head>
          <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
      </head>
      <body>
      <section id='photo_wall'>
        <div class='container'>
          <div class='row'>
            <div class='col-md-12 data-filters'>
              <ul class='line-list'>
                <li class='active-filter' data-filter='all'> All photos </li>
                <li data-filter='land'> Land </li> 
                <li data-filter='sea'> Sea </li> 
                <li data-filter='animals'> Animals </li> 
              </ul>
            </div>
          </div>
          <div class='row'>
            <div class='col-md-3 photo-item p-4 photo-in' data-filter='land'>
              <img src='https://fastly.picsum.photos/id/807/200/200.jpg?hmac=Y8gayvNItiQYxP_Pd-2un9GH09XuyJdIZOQPw6K9QsI'>
            </div>
            <div class='col-md-3 col-sm-6 photo-item p-4 photo-in' data-filter='animals'>
              <img src='https://fastly.picsum.photos/id/659/200/200.jpg?hmac=kFpdD3XTBGwPUAH1tD-AiWigstjIX8WGIcyySuVQIvE' class='animals'>
            </div>
             <div class='col-md-3 col-sm-6 photo-item p-4 photo-in' data-filter='land'>
              <img src='https://fastly.picsum.photos/id/165/200/200.jpg?hmac=tQGrY9pm5ze9soSsZ5CNBt87zqnHfFwdPv_khau12Sw' class='land'>
            </div>
            <div class='col-md-3 photo-item p-4 photo-in' data-filter='sea'>
                <img src='https://fastly.picsum.photos/id/883/200/200.jpg?hmac=evNCTcW3jHI_xOnAn7LKuFH_YkA8r6WdQovmsyoM1IY' class='sea'>
               </div>
              <div class='col-md-3 photo-item p-4 photo-in' data-filter='animals'>
                <img src='https://fastly.picsum.photos/id/237/200/200.jpg?hmac=zHUGikXUDyLCCmvyww1izLK3R3k8oRYBRiTizZEdyfI' class='animals'>
                </div>
              <div class='col-md-3 photo-item p-4 photo-in' data-filter='sea'>
                <img src='https://fastly.picsum.photos/id/653/200/200.jpg?hmac=tZtho3csFdJ2rLHTTlT7WhXtDwbXgJNIIUvOQQb2dIo' class='sea'>
                </div>
          </div>
        </div>
      </section>
      </body>
    </html>
    Login or Signup to reply.
  3. I cannot think of a way of smoothly minimising the cols in the Bootstrap environment.

    This snippet therefore uses just inline-block.

    The elements always stay in the order they are given in the HTML, but when not on show they have width 0, meaning those elements which are on show will be side by side. And width is an animatable CSS property.

    To get the falling image effect therefore the images are held as backgrounds to pseudo before elements of the parent divs rather than as an img element. These pseudo elements can be made to fall (and rise) without affecting the layout as they are position absolute.

    They fall, then their divs are animated down to 0px width.

    const filterContainer = document.querySelector('.data-filters');
    const photoItems = document.querySelectorAll('.photo-item');
    
    filterContainer.addEventListener('click', (event) => {
    
      filterContainer.querySelector('.active-filter').classList.remove('active-filter');
      event.target.classList.add('active-filter');
    
      const filter = event.target.getAttribute('data-filter');
    
      photoItems.forEach((item) => {
        if (item.getAttribute('data-filter') == filter || filter == 'all') {
          item.classList.remove('photo-out')
          item.classList.add('photo-in')
        } else {
          item.classList.remove('photo-in')
          item.classList.add('photo-out')
        }
      })
    
    })
    .line-list li {
      display: inline-block;
      margin: 10px;
      cursor: pointer;
    }
    
    .active-filter {
      color: blue;
    }
    
    @keyframes go-out {
      0% {
        top: 0px;
        opacity: 1.0;
      }
      100% {
        top: 600px;
        opacity: 0;
      }
    }
    
    @keyframes go-in {
      100% {
        top: 0px;
        opacity: 1.0
      }
      0% {
        top: 600px;
        opacity: 0;
      }
    }
    
    .row:last-child>div.photo-out::before {
      animation: go-out 1.2s forwards linear;
      background-color: blue;
      ;
    }
    
    .row:last-child>div.photo-in::before {
      animation: go-in 1.2s forwards linear;
    }
    
    .row:last-child>div {
      display: inline-block;
      position: relative;
      width: 200px;
      height: 200px;
    }
    
    .row:last-child>div.photo-in {
      animation: fullwidth 1.2s linear forwards;
    }
    
    .row:last-child>div.photo-out {
      animation: zerowidth 1.2s linear forwards;
      animation-delay: 1.2s;
    }
    
    @keyframes fullwidth {
      from {
        width: 0;
      }
      to {
        width: 200px;
      }
    }
    
    @keyframes zerowidth {
      to {
        width: 0;
      }
    }
    
    .row:last-child>div::before {
      width: 200px;
      height: 100%;
      top: 0;
      left: 0;
      position: absolute;
      content: '';
      background-image: var(--bg)
    }
    <html>
    
    <head>
      <style>
    
      </style>
    </head>
    
    <body>
      <section id='photo_wall'>
        <div class='container'>
          <div class='row'>
            <div class='data-filters'>
              <ul class='line-list'>
                <li class='active-filter' data-filter='all'> All photos </li>
                <li data-filter='land'> Land </li>
                <li data-filter='sea'> Sea </li>
                <li data-filter='animals'> Animals </li>
              </ul>
            </div>
          </div>
          <div class='row'>
            <div class='photo-item' data-filter='land' style="--bg: url(https://fastly.picsum.photos/id/807/200/200.jpg?hmac=Y8gayvNItiQYxP_Pd-2un9GH09XuyJdIZOQPw6K9QsI);" class='land'>
            </div>
            <div class='photo-item' data-filter='animals' style="--bg:  url(https://fastly.picsum.photos/id/659/200/200.jpg?hmac=kFpdD3XTBGwPUAH1tD-AiWigstjIX8WGIcyySuVQIvE);" class='animals'>
            </div>
            <div class='photo-item' data-filter='land' style="--bg: url(https://fastly.picsum.photos/id/165/200/200.jpg?hmac=tQGrY9pm5ze9soSsZ5CNBt87zqnHfFwdPv_khau12Sw);" class='land'>
            </div>
            <div class='photo-item' data-filter='sea' style="--bg: url(https://fastly.picsum.photos/id/883/200/200.jpg?hmac=evNCTcW3jHI_xOnAn7LKuFH_YkA8r6WdQovmsyoM1IY);" class='sea'>
            </div>
            <div class='photo-item' data-filter='animals' style="--bg: url(https://fastly.picsum.photos/id/237/200/200.jpg?hmac=zHUGikXUDyLCCmvyww1izLK3R3k8oRYBRiTizZEdyfI);" class='animals'>
            </div>
            <div class='photo-item' data-filter='sea' style="--bg: url(https://fastly.picsum.photos/id/653/200/200.jpg?hmac=tZtho3csFdJ2rLHTTlT7WhXtDwbXgJNIIUvOQQb2dIo);" class='sea'>
            </div>
          </div>
        </div>
      </section>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search