Wednesday, October 10, 2012

Filter functionality with CSS3

Using the general sibling combinator and the :checked pseudo-class, we can toggle states of other elements by checking a checkbox or a radio button. In this tutorial we will be exploring those CSS3 properties by creating a experimental portfolio filter that will toggle the states of items of a specific type.

The idea is inspired by Roman Komarov's brilliant "Filtering elements without JS" experiment where he uses checkboxes and radio buttons for filtering colored shapes.

The Markup

Let's start with the markup. Our aim is to have four filter buttons that, once clicked, will make the respective type appear or stand out. So, we'll use some radio buttons that all have the same name since they should belong to the same group (hence only one can have the checked state). By default, we want the "all" radio button to be selected or checked. We'll add some labels for the radio buttons that we will use in order to hide the radio buttons. Clicking a label will select the radio buttons with the respective ID:

The unordered list will contain all the portfolio items as anchors with an image and a span. Each list element will have a type class that will make it possible to identify those elements and "filter" them when we click on one of the radio buttons.

The CSS

We'll be going through three example effects, but first, let's take a look at the common style.
The main section container will have a specific width:

.ff-container{
width: 564px;
margin: 10px auto 30px auto;
}

The labels will cover the radio buttons and we’ll give them a fancy gradient and some subtle box-shadows:

Since we have all our elements in one level, we use the general sibling combinator which is represented by a "tilde" (~) character, in order to reach the respective label. With this "trick" we will also get to all those different types in the portfolio list.

The inputs can be hidden, since we have our labels that will do the job:

When we hover over an anchor, we'll make the span appear from the bottom, animating its opacity with a transition.
Allright, that was all the "common" style. Now, let’s see how we can filter those elements in style!

Example 1

In the first example, we'll simply make the items that are selected (i.e. when the respective radio button is "checked") have the highest opacity.
We'll add a transition to the list item for the opacity:

Since we have the "all" type checked by default, all items will initially have the opacity 1.

Now, all the other items should get a very low opacity once we choose a type other than "all". We'll use the :not() selector to specify that the list elements that don’t have the selected type class should have an opacity of 0.1:

Example 3

The last example is just an experiment. We want to do something a bit more tricky here: upon selecting a type, we want to scale all items down and then scale only the items with the selected type back up again.

We basically want to make the other items disappear and since we cannot really animate the display property (not even with some combination of opacity), we use this little trick: when we scale the items down, we’ll also animate the width of the ones that should disappear to 0.

So, let's give the list items 0 width initially and scale them down to 0 (careful, you will want to avoid this practice for older browsers):

Remember, we are in this state initially, since we have the "all types" check by default, but we will also transition into the state, if we are currently viewing another type and go back to the "all types".

Now, when we check one specific type, the items with that type class will first transition to their initial state, first scale down and with a delay of 0.3 seconds, get a width of 0 again.

At the same time, the items that are not of the selected type (those ones that we get with the :not() selector) will have the scaleDown animation running, which will basically do the same thing: scale them down and give them a width of 0.

After 0.4 seconds, well make the selected type appear again, with the scaleUp animation:

Note that this example is very experimental and it will only work properly in browsers supporting CSS animations. In Firefox 9.0.1 the behavior is not as expected (hovering over the labels seems to falsely trigger something) but it works in Aurora 11.0a2, so it might be some kind of bug.