Creating useful interactive elements using only CSS, or "The Checkbox Hack"

This is a particularly useful little trick which makes use of CSS’s sibling selector (~) as well as the pseudo-class :checked on an HTML checkbox.

The purpose behind this is to create buttons that can be used to toggle CSS “states” without the need for additional javascript.

The following demo & code demonstrates this principle in action. Click the button to see it working.

See the Pen the “Checkbox Hack” trick by Robin Metcalfe (@solarisedesign) on CodePen.

This works by using the sibling selector, ~ to target an element on the same level as the checkbox, and apply one particular set of rules based on the status of the :checked pseudo-class. As you can see from the code, you can also use :not(:checked) to target the inactive state.

Using the following code as the basis,

.checkbox:checked ~ .target .descendant {
    /* Apply some CSS to .descendant in .target
       whenever the checkbox is _active_ */

.checkbox:not(:checked) ~ .target .descendant {
    /* Apply some CSS to .descendant in .target
       whenever the checkbox is _inactive_ */

you can see how this allows you to control the state of any descendant of the .target element, opening up possibilities for many complex interactions. Another code demo on my site, Impossible Isometrics has been built using this as the basis for the button interactions.

It’s also required to include the label element, otherwise Firefox doesn’t render this method properly.


There are some limitations to this. It does restrict you in the structure of your HTML. The checkbox does need to live on the same level and within the same parent element as the element you wish to “control”

Internet Explorer 8 also doesn’t support the :checked pseudo-class. This is something you could add a Javascript workaround for though, using something like selectivizr

It also gets quite complex if you’re trying to perform complex animations, and you might be better off using Javascript for more complicated things.

However, it is useful for things like responsive menus on websites, or other situations where you need some complex functionality without relying on Javascript.

Further testing

As a fun extra exercise (woo! fun extra work. yay) see if it’s possible to do something similar to the above but with the select element, to allow for multiple states