Building a Filtering Component with CSS Animations & jQuery

Share this article

Some months ago, I wrote an article about MixItUp, a popular jQuery plugin for filtering and sorting. In today’s article, I’ll show you how to build your own simple filterable component with jQuery and CSS animations.

Without further ado, let’s get started!

Setting Up the HTML

As a first step, I’ll show you the HTML structure of the component. Consider the following markup:

<div class="cta filter">
  <a class="all active" data-filter="all" href="#" role="button">Show All</a>
  <a class="green" data-filter="green" href="#" role="button">Show Green Boxes</a>
  <a class="blue" data-filter="blue" href="#" role="button">Show Blue Boxes</a>
  <a class="red" data-filter="red" href="#" role="button">Show Red Boxes</a>
</div>

<div class="boxes">
  <a class="red" data-category="red" href="#">Box1</a>
  <a class="green" data-category="green" href="#">Box2</a>
  <a class="blue" data-category="blue" href="#">Box3</a>

 <!-- other anchor/boxes here ... -->

</div>

Notice that I’ve set up some pretty basic markup. Here’s an explanation of it:

  • First, I’ve defined the filter buttons and the elements that I want to filter (we’ll call them target elements).
  • Next, I’ve grouped the target elements into three categories (blue, green, and red) and I gave them the data-category attribute. The value of this attribute determines the category that each element belongs to.
  • I’ve also assigned the data-filter attribute to the filter buttons. The value of this attribute specifies the desired filter category. For instance, the button with the data-filter="red" attribute/value will only show the elements that belong to the red category. On the other hand, the button with data-filter="all" will show all the elements.

Now that you’ve had an overview of the required HTML, we can move on to explore the CSS.

Setting Up the CSS

Each time a filter category is active, its corresponding filter button receives the active class. By default, the button with the data-filter="all" attribute gets this class.

Box with active class

Here are the associated styles:

.filter a {
  position: relative;
}

.filter a.active:before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  display: inline-block;
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 15px 15px 0 0;
  border-color: #333 transparent transparent transparent;
}

In addition, I’m going to use flexbox to create the layout for the target elements.

Using flexbox for the layout

See the related styles below:

.boxes {
  display: flex;
  flex-wrap: wrap;
}

.boxes a {
  width: 23%;
  border: 2px solid #333;
  margin: 0 1% 20px 1%;
  line-height: 60px;
}

Lastly, I’m defining two different CSS keyframe animations that I’ll use later on to reveal the elements:

@keyframes zoom-in {
  0% {
   transform: scale(.1);
  }
  100% {
    transform: none;
  }
}

@keyframes rotate-right {
  0% {
    transform: translate(-100%) rotate(-100deg);
  }
  100% {
    transform: none;
  }
}

.is-animated {
  animation: .6s zoom-in;
  // animation: .6s rotate-right; 
}

With the markup and CSS in place, we can start building the JavaScript/jQuery.

Setting Up the jQuery

Have a look at the code below, after which I’ll explain what’s happening:

var $filters = $('.filter [data-filter]'),
    $boxes = $('.boxes [data-category]');

$filters.on('click', function(e) {
  e.preventDefault();
  var $this = $(this);
  $filters.removeClass('active');
  $this.addClass('active');

  var $filterColor = $this.attr('data-filter');

  if ($filterColor == 'all') {
    $boxes.removeClass('is-animated')
      .fadeOut().promise().done(function() {
        $boxes.addClass('is-animated').fadeIn();
      });
  } else {
    $boxes.removeClass('is-animated')
      .fadeOut().promise().done(function() {
        $boxes.filter('[data-category = "' + $filterColor + '"]')
          .addClass('is-animated').fadeIn();
      });
  }
});

Each time a filter button is clicked, the following happens:

  • The active class is removed from all buttons and assigned only to the selected button.
  • The value of the button’s data-filter attribute is retrieved and evaluated.
  • If the value of data-filter is all, all elements should appear. To do so, I first hide them and then, when all elements become hidden, I show them using the rotate-right or zoom-in CSS animations.
  • If the value is not all, the target elements of the corresponding category should appear. To do so, I first hide all elements and then, when all of them become hidden, I show only the elements of the associated category using the rotate-right or zoom-in CSS animations.

At this point, it’s important to clarify one thing. Notice the syntax for the fadeOut() method in the above code. It looks as follows:

$boxes.fadeOut().promise().done(function() {
  // callback's body
});

You’re probably more familiar with this syntax though:

$boxes.fadeOut(function() {
  // callback's body
});

These declarations have different meanings:

  • In the first case, the callback is executed only after all target elements become hidden. You can learn more info about this approach by visiting the promise() section of jQuery’s docs.
  • In the second case, the callback is fired multiple times. Specifically, it’s executed each time an element becomes hidden.

The demo below uses the zoom-in animation:

See the Pen A sorting/filtering component with CSS and jQuery (with zoom animation) by SitePoint (@SitePoint) on CodePen.

And this demo uses the rotate-right animation:

See the Pen A sorting/filtering component with CSS and jQuery (with rotate animation) by SitePoint (@SitePoint) on CodePen.

Of course, the aforementioned CSS animations are optional. If you don’t like these specific animations, feel free to remove them and reveal the elements using only jQuery’s fadeIn() method.

Now that you understand how the component works, I’ll show you how to create a different variation of it.

Animating Elements Sequentially

Until now, you may have noticed that all elements appear at the same time. I’ll now modify the code to show them sequentially:

$filters.on('click', function(e) {

  // same code as above here

  if ($filterColor == 'all') {
    $boxes.removeClass('is-animated')
      .fadeOut().finish().promise().done(function() {
        $boxes.each(function(i) {
          $(this).addClass('is-animated').delay((i++) * 200).fadeIn();
        });
      });
  } else {
    $boxes.removeClass('is-animated')
      .fadeOut().finish().promise().done(function() {
        $boxes.filter('[data-category = "' + $filterColor + '"]').each(function(i) {
          $(this).addClass('is-animated').delay((i++) * 200).fadeIn();
        });
      });
  }
});

The code above looks similar to the previous one but there are a few distinct differences:

  • First, I use the each() method to iterate through the target elements. Plus, as it loops, I’m getting the index of the current element (which is zero-based) and multiplying it by a number (e.g. 200). The derived number is passed as an argument to the delay method. This number indicates the amount of milliseconds that each element should wait before fading in.
  • Next, I use the finish() method to stop the currently-running animations for the selected elements under specific cases. To understand its usage, here’s a scenario: Click on a filter button and then, before all elements appear, click on the button again. You’ll notice that all elements disappear. Similarly, run this test again after removing the two instances of this method. In such a case, you’ll see that the elements receive some undesired effects. Sometimes calling this method properly can be tricky. For this example, I had to experiment a bit until I found where I should place it.

The demo below animates the filtered elements sequentially using the zoom-in animation:

See the Pen Sequential filtering/sorting component with CSS & jQuery by SitePoint (@SitePoint) on CodePen.

The demo below animates the filtered elements sequentially using the rotate-right animation:

See the Pen Sequential filtering/sorting with CSS and jQuery by SitePoint (@SitePoint) on CodePen.

Conclusion

This same component could be built without jQuery and may have better performance, but the ability to use jQuery’s fadeIn() and fadeOut() methods allows for simpler code that takes advantage of certain features available to jQuery.

Let me know in the comments if you have a different solution, or a way to improve the code.

Frequently Asked Questions (FAQs) about Building a Filtering Component with CSS Animations & jQuery

How can I add more filters to the component?

Adding more filters to the component is quite straightforward. You need to define the new filter in your CSS and then add the corresponding functionality in your jQuery code. For instance, if you want to add a ‘grayscale’ filter, you would first define it in your CSS like this:

.filter-grayscale {
filter: grayscale(100%);
}

Then, in your jQuery code, you would add a new case to your switch statement to handle the new filter:

switch(filter) {
// existing cases...
case 'grayscale':
$container.addClass('filter-grayscale');
break;
// ...
}

Remember to add a button or some other UI element that allows the user to activate the new filter.

Can I use this filtering component with other JavaScript libraries?

Yes, you can use this filtering component with other JavaScript libraries. jQuery is designed to be compatible with other libraries. You just need to make sure that there are no conflicts between the different libraries. If there are conflicts, you can use jQuery’s noConflict() method to avoid them. This method releases the hold on the `= shortcut identifier, which allows other libraries to use it. You can then use jQuery’s full name to call its methods.

How can I animate the transition between filters?

Animating the transition between filters can be achieved by using CSS transitions. You need to add a transition property to the element you want to animate. This property specifies the CSS property to transition, the duration of the transition, the timing function, and the delay before the transition starts. For example, if you want to animate the transition of the filter property over 1 second, you would add the following CSS:

.container {
transition: filter 1s;
}

Then, when you change the filter using jQuery, the transition will be animated.

Can I use this filtering component on multiple elements on the same page?

Yes, you can use this filtering component on multiple elements on the same page. You just need to make sure that each element has a unique ID or class that you can use to select it with jQuery. Then, you can apply the filtering component to each element individually.

How can I make the filters responsive?

Making the filters responsive involves adjusting the CSS and jQuery code based on the size of the viewport. You can use CSS media queries to apply different styles for different viewport sizes. In your jQuery code, you can use the $(window).resize() method to execute code when the window is resized. You can then adjust the filters based on the new size of the window.

Can I use CSS animations without jQuery?

Yes, you can use CSS animations without jQuery. CSS animations are a feature of CSS and do not require any JavaScript. However, jQuery can make it easier to manage and control animations, especially if you have complex animations or if you want to animate elements in response to user actions.

How can I add a custom filter?

Adding a custom filter involves defining a new CSS class with the desired filter effect and then adding the corresponding functionality in your jQuery code. The process is similar to adding more filters, as described in the answer to question 1.

Can I use this filtering component with dynamic content?

Yes, you can use this filtering component with dynamic content. You just need to make sure that the filtering component is applied to the content after it has been loaded. You can do this by calling the filtering component in the callback function of your AJAX request or in the $(document).ready() function if you are loading the content when the page loads.

How can I optimize the performance of the filtering component?

Optimizing the performance of the filtering component can involve several strategies. One strategy is to minimize the number of DOM manipulations. Each time you add or remove a class with jQuery, it causes the browser to recalculate the layout, which can be expensive. To minimize this, you can group your changes together and make them all at once. Another strategy is to use CSS transitions instead of jQuery animations, as CSS transitions are generally more performant.

Can I use this filtering component with a backend database?

Yes, you can use this filtering component with a backend database. You would need to make an AJAX request to the server to retrieve the data from the database, and then use jQuery to apply the filtering component to the data. This would allow you to filter data based on criteria stored in the database.

George MartsoukosGeorge Martsoukos
View Author

George is a freelance web developer and an enthusiast writer for some of the largest web development magazines in the world (SitePoint, Tuts+). He loves anything related to the Web and he is addicted to learning new technologies every day.

css animationjQueryLouisL
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week