Exploring the CSS “checkbox hack” Further

By now, you’ve probably heard of the CSS “checkbox hack” as a way of using pure CSS to do JavaScript-like things. One of the most common ways I’ve seen it used is to have an off-canvas navigation, which Val wrote about a few weeks ago.

For those unfamiliar

The idea is that you associate the label and the form element by assigning the same name of the “for” attribute of the label as that of the “id” attribute of the form element itself. By placing the input in our markup beside an element we’d like to style differently, and then visually hiding it, we can use a combination of more advanced CSS selectors to do some jedi mind tricks. Namely, we’ll be using the “:checked” pseudo-selector on our input to indicate that we only want something styled when this particular input is checked. This alone, however, does not do much, as that would only allow us to style that particular input. To make this a more expressive “function”, we need to use the sibling selector “+”, which selects adjacent elements.

I’ve made examples of some of the more advanced uses of the checkbox hack, including some CSS tabs, and a CSS accordion, two features normally reserved for the likes of jQuery and DOM manipulation. Today, I’d like to go through the process of creating one of the less-seen uses of the checkbox hack – the CSS sorter.

Recommended: [Mini Tutorial] How to overwrite Magento Default Styles: reset.css

What is a CSS Sorter

The CSS sorter uses the same principles as the checkbox hack, but with a slight variation – we’re going to be using the “following” selector (which, quite frankly, I’m not sure if that’s the proper name, but the actual selector looks like “~”). This selector will target any specified element following another specified element (for example, ul ~ p would target any <p> tags that followed an unordered list), which is essential to this sorter working.

The Set up

The setup is quite simple, we start with some basic markup – 16 images for this example, all with different things common between them.

<div class="wrapper">
  <h1>Only show me pictures of:</h1>
  <input type="checkbox" name="controllers" id="murraycontroller">
  <label class="murraycontroller" for="murraycontroller">Bill Murray</label>
  <input type="checkbox" name="controllers" id="dogecontroller">
  <label class="dogecontroller" for="dogecontroller">Doge</label>
  <input type="checkbox" name="controllers" id="vanillacontroller">
  <label class="vanillacontroller" for="vanillacontroller">Vanilla Ice</label>
  <input type="checkbox" name="controllers" id="catcontroller">	
  <label class="catcontroller" for="catcontroller">Cats</label>

  <img src="http://www.fillmurray.com/200/200" alt="" class="photo billmurray">
  <img src="http://www.placedoge.com/200/200" alt="" class="photo doge">
  <img src="http://www.fillmurray.com/200/200" alt="" class="photo billmurray">
  <img src="http://www.placedoge.com/200/200" alt="" class="photo doge">
  <img src="http://www.nicenicejpg.com/200/200" alt="" class="photo vanillaice">
  <img src="http://www.placekitten.com/200/200" alt="" class="photo cat">
  <img src="http://www.fillmurray.com/200/200" alt="" class="photo billmurray">
  <img src="http://www.nicenicejpg.com/200/200" alt="" class="photo vanillaice">
  <img src="http://www.fillmurray.com/200/200" alt="" class="photo billmurray">
  <img src="http://www.placedoge.com/200/200" alt="" class="photo doge">
  <img src="http://www.nicenicejpg.com/200/200" alt="" class="photo vanillaice">
  <img src="http://www.fillmurray.com/200/200" alt="" class="photo billmurray">
  <img src="http://www.nicenicejpg.com/200/200" alt="" class="photo vanillaice">
  <img src="http://www.placedoge.com/200/200" alt="" class="photo doge">
  <img src="http://www.placekitten.com/200/200" alt="" class="photo cat">
  <img src="http://www.fillmurray.com/200/200" alt="" class="photo billmurray">
</div>

See the Pen Ajimv by Simon Proudfoot (@proudfeet) on CodePen.

As you can see, the markup isn’t anything worth writing home about. Indeed, the power of this example comes from the use of the all-important CSS selectors we talked about earlier. As mentioned, we formed a connection between the label and corresponding input by associating the “for” attribute of the label with the “id” attribute of the actual element. This association means that when the label is clicked, it will act as a “controller” for the input. Using this combination, we can then use the “:checked” selector in tandem with the “~” (following) selector to find elements on a page with certain attributes. Allow me to illustrate:

input {
    display: none;
	}

	input:checked ~ img {
    display: none;
	}

	#murraycontroller:checked ~ .billmurray {
    display: inline-block;
	}

	#dogecontroller:checked ~ .doge {
    display: inline-block;
	}

	#vanillacontroller:checked ~ .vanillaice {
    display: inline-block;
	}

	#catcontroller:checked ~ .cat {
    display: inline-block;
	}

See the Pen Ajimv by Simon Proudfoot (@proudfeet) on CodePen.

For this to work correctly, we must use specific labels to control specific elements on the page, hence the heavy use of id’s and classes in our example. The way the above example works is by identifying elements on the page with specific attributes (for example, an image with a class of “billmurray”), and styling it differently depending on whether or not a specific element preceding it (a label with an id of “murraycontroller”) is checked. In our example, we’re going to hide those specific images if the above conditions are true.

After a quick touch-up and beautifying, we can quickly end up with something like this:

See the Pen CSS Sorter by Simon Proudfoot (@proudfeet) on CodePen.

Using this technique was more a thought exercise than anything, as I know many people feel that using techniques like the checkbox hack undermines the semantic meaning of elements. While there is certainly a case to be made for such an argument, it’s hard to argue against the performance boost that things like the checkbox hack can give to a website, especially with respect to responsive design.