Using Checkboxes to Toggle CSS and Create Click Events

by on 24th March 2013 with 19 Comments

screenshot

More and more lately I’ve seen developers utilizing tricks to create toggle states using pure CSS. This allows you to skip the JavaScript without sacrificing the interaction. How does this work? Is it an acceptable practice?

Today we’re going to examine two distinct methods for utilizing a checkbox to create a click event that swaps between two images using good old HTML and CSS. We’ll finish off with a brief discussion on semantics and the pros/cons of this technique.

Like Skinning a Cat

“You essentially create a checkbox in HTML only to hide it and steal its functionality.”

With any CSS trick, there are always a handful of different ways to accomplish the task you’re aiming to achieve. What we’ll be doing here today is learning about how to utilize checkboxes to create two states that can be toggled between using only HTML and CSS. Given that goal, we can easily come up with at least two ways to accomplish it. Even within those two main strategies, you’ll find that there are multiple roads that we could take.

Both methods involve some questionable CSS trickery. You essentially create a checkbox in HTML only to hide it and steal its functionality. The first method simply stretches the checkbox to the full size of the area that you’d like to make clickable and utilizes no label.

The second method makes use of the interesting functionality of labels associated with a checkbox. Even if you hide the checkbox itself, the label can actually be styled, positioned and clicked on to activate the toggle, giving us a completely flexible element to work with that has two possible states.

Let’s dive in and take a closer look at each of these methods.

Method 1

The first way that we’re going to attack this experiment is through making our checkbox eat up the full size of our object and then hiding it. To make this work, all you technically need is a div that contains a checkbox with a class applied. If you want to go further, you can add other attributes such as “name”. We’ll also throw in an image so we’ll have something to toggle.

This should give you a checkbox next to a big image as seen in the following image. Don’t worry about the awkward positioning, we’ll fix that with CSS.

screenshot

CSS

Now that we have some HTML, it’s time to attack this sucker with CSS. It doesn’t take much code but it is a little bit of a weird process so be sure to follow along closely.

The first thing that we want to do here is style the div. We’ll give it a height and a width to match the image that we inserted before so that the photo takes up the entire div. I’ll also give the div a background image that’s different than the other image that we used. This way if we toggle the visibility of the HTML image we’ll see this one underneath. All of this is really just a test anyway so feel free to structure it completely differently. The real focus here is how we use the checkbox to toggle between two states.

The other important part here is setting the position to relative. We’ll use absolute positioning later for the checkbox and it’s important that we set this element to relative to give the checkbox a starting point.

div {
  height: 200px;
  width: 500px;
  background: #eee url(http://lorempixum.com/500/200/city/2);
  overflow: hidden;
  position: relative;
}

Now it’s time to perform the questionable act of turning our entire image into one big checkbox. To do this, target the “toggle” class that we set up before and set the same height and width that we’ve been using all along.

Next, set the position to absolute and reset the left, top, margin and padding, just to be sure the starting point will be where we want it. This will work in tandem with our previous relative positioning so that our checkbox can now occupy the entire space of the image. To ensure that the checkbox stays on top of everything, set its z-index value to something arbitrarily high.

Finally, set the opacity of the checkbox to 0 to hide it completely. The interesting thing here is that hiding the checkbox doesn’t disable its functionality. So now when you click anywhere on the image, you’ll be toggling the checkbox on and off.

.toggle {
  height: 200px;
  width: 500px;
  position: absolute;
  top: 0;
  left: 0;
  margin: 0;
  padding: 0;
  cursor: pointer;
  z-index: 100;
  opacity: 0;
}

Our hidden checkbox is functioning, but we haven’t set it up to do anything yet. As I mentioned before, we want to toggle the opacity of the HTML image, so we can set up a selector that singles out any inputs with the “toggle” class that are checked, then use the sibling selector to target the image and set its opacity to zero. To make the effect a little nicer, toss in a simple transition.

input.toggle:checked + img {
   opacity: 0;
}

img {
  -webkit-transition: opacity 1s ease;
  -moz-transition: opacity 1s ease;
  -o-transition: opacity 1s ease;
  -ms-transition: opacity 1s ease;
  transition: opacity 1s ease;
}

Try It Out

With that, method one is all finished. Below you should be able to see a link to the CodePen page. Check it out and then come back here for the rest!

Demo: Click here to see it on CodePen.

Method 2

With the first method out of the way, it’s time to explore method #2, which involves the use of a checkbox label. This is added directly before the input. Notice that the “for” value matches the ID for the checkbox. We’ll also toss both images into our HTML this go around just to switch things up.

CSS

Once again, we’ll start by adding some basic styles to the div. There’s nothing really special here, just some dimensions and positioning.

div {
  width: 500px;
  height: 260px;
  overflow: hidden;
  position: relative;
}

Now for something new. Remember that this method involves utilizing the checkbox label instead of the checkbox itself. To do this, set the display to block and give it some dimensions. We included the text “Click Me” in the HTML above so we’ll need to style that as well. Essentially, we’re just transforming the label to give it the look of a button.

On hover, I changed up the colors and added the pointer cursor to further the idea that it’s a clickable element.

label {
  display: block;
  height: 50px;
  width: 200px;
  background: #eee;
  text-align: center;
  font: 14px/50px Helvetica, Verdana, sans-serif;
  margin-bottom: 10px;
}

label:hover {
  background: #232323;
  color: #fff;
  cursor: pointer;
}

Now it’s time to hide the checkbox again, but we’re going to go about it a little differently this go around just to show you that we can. By assigning absolute positioning and some crazy positioning values, we shoot the actual checkbox out of view. Remember, this works because we can still click the label element to pull off the toggle.

input#toggle {
   position: absolute;
   top: -9999px;
   left: -9999px;
}

To finish this version up, we need three more style blocks. The first positions the second image directly under the first image. From here, we’re using the same code that we did last time to change the opacity on toggle and add in a nice transition.

.bkg {
  position: absolute;
  top: 60px;
  left: 0;
  z-index: -100;
}

input#toggle:checked + img {
  opacity: 0;
}

img {
  -webkit-transition: opacity 1s ease;
  -moz-transition: opacity 1s ease;
  -o-transition: opacity 1s ease;
  -ms-transition: opacity 1s ease;
  transition: opacity 1s ease;
}

Try It Out

We’ve finished the second method now, try it out below by clicking the link.

Demo: Click here to see it on CodePen.

Isn’t This JavaScript’s Job?

Without a doubt, this is some fun stuff. With only a wee bit of CSS and HTML, we were able to create a nice little click event. The benefits here are clear: brief code, no JavaScript, ease of implementation, etc.

Unfortunately, both of the methods that we went over above are quite taboo in some circles. This is because they’re both really a bastardization of the checkbox element. We’re not really using the element “semantically,” meaning how it was truly meant to be used, instead we’re just stealing its functionality and wrapping it around other objects.

So how bad is this offense? It depends on who you talk to. An old school coder will tell you that this is bad news. Use JavaScript dummy, that’s what it’s for! Despite this, many of the more impressive CSS tutorials published online recently utilize tricks similar to this (one variation uses radio buttons instead), though they do so without really explaining it in depth. Some of these are so awesome, you simply can’t resist throwing semantics to the wind and blowing past what you previously though possible with only CSS.

With this article I sought to explain how this technique is working on a basic level and point out that it’s, at the very least, considered controversial.

Should I Use This More Often?

I write CSS tutorials for a living. Every single day I try to think of great things that I can teach you. Methods like these present an interesting dilemma. They open up such great possibilities for making amazing pure CSS demos. However, some might consider it a waste of time given the questionable semantic application.

Here I throw it back to you, the Design Shack readers. What do you think? Should I show you cool stuff, even if it makes some semantic sacrifices? Do you want to see some more cool demos built with the two methods outlined in this article? How could you improve this trick? I’d love to hear your thoughts!

Comments & Discussion

19 Comments

  • http://www.twitter.com/chsweb Jono

    One approach I found to be really great is one taken by Dan Cederholm in his book “Web Standards Solutions.” He shows multiple ways to code a solution, starting with the wrong way, and iteratively improving it until it is done based on web standards, including semantic markup.

    I could see your approach working very well in a Spy vs. Spy, or Point and Counter Point format.

  • http://mishunov.me Denys Mishunov

    Hi Joshua,

    Thanks for the article. I am all taken by the idea of using (or should I say ‘abusing’) the checkboxes for tricks like these.
    Definitely using checkboxes for anything other than checking in a form sounds like a misuse of the element. On the other hand, it’s a really nice way to avoid JS if needed. Only yesterday I have created two demos where I use the second Method, mentioned in this article:

    http://codepen.io/mishunov/pen/3 . This one is showing how the checkbox is absolutely not abused – it’s a list of options presented in a nice way
    http://codepen.io/mishunov/pen/5. Kids, don’t use your checkboxes this way. It was evening and I had a headache… you know…

    One more demo I have made months ago using the same technique
    http://mishunov.me/lab/path-navigation

    In all of the demos no JS has been used and almost no images.
    Clearly, using checkboxes for these tricks is dirty, but as the first link shows, it is not necessarily a misusing.

    • nico

      impressive examples! thanks for sharing and thanks Joshua for the inspiring article.

      could you please point me to an article were i can study your usage of the “&” in css? i have never seen something like this, you don’t even close declarations with a “}” but put an “&” and keep writing css! what’s that?!!!

      thanks for your help…please!

  • http://mishunov.me Denys Mishunov

    And about your question in the last paragraph – definitely yes, show us tricks even if they are dirty assuming you mention your concerns about the semantics as you did here. It’s up to the developers to evaluate decisions they make in their work. If they know how to do it the dirty way, it doesn’t mean they must do it this way. So, yeah, keep them coming!

  • http://oirsworld.com Stev Newbury

    I think you should continue to offer tutorials like this; it’s interesting and demonstrates what CSS can do if you think slightly outside of the box! Some people don’t like JavaScript – even if it is “supposed to” perform these tricks, so a CSS alternative could be beneficial to some.

    Yes, semantics aren’t adhered to and yes that’s a problem, but – it’s an experiment!

  • Francisco

    These tutorials are fantastic, definitely keep’em comming. For a beginner like me, it’s great to learn these tricks (specially since i’m kinda repelled by javascript). But i’m still in the learning process.

  • dj

    In FF, your second demo, the “click me” merely jumps me to the top of the page. Don’t think that’s what it’s supposed to do.

    I don’t mind, and in fact enjoy, sometimes reading tuts “on the edge” or a bit “out of the box” AS LONG AS the author isn’t so lazy that he doesn’t identify them as such AND has taken the time to delineate which browsers the technique WILL and WON’T work in so I can make informed decisions. Otherwise, I think I’d just as soon not read them. “Best Practices” are often seen so trivial that they are quickly dumped in favor of something “cool”; but, they save the entire web community a lot of grief and should be the integrity of a “job well done” for which we all strive. Knowing this kind of stuff is great and gives “color” and excitement to our craft; but its usage should be informed by knowledge of the things I mentioned.

  • http://www.layerform.com Edd Biel

    Forgive my poor observation, but i cant seem to see a Demo button anywhere? I really want to see the capabilities of this technique.

  • Cyn

    @dj re: FF “click me”… Actually, the image DOES change. It’s just that after the shock of moving to the top of the document, it’s easy to miss that the image switched. That might not be a bad thing… I can see potential for it. But try it again, taking note of which image was in the window before and after the click. HTH!

  • Cyn

    re: Should you do more CSS “re-purposing” tuts? YESSSSS!

    Our web design structure is just another form of communication and just as language shifts and morphs and adapts to our real-world communication needs, so will our design structure.

    Not everyone wants to program in Javascript and would rather be in control of their own design… rather than having to wait for some jscript programmer to think of the same need you have and then write it and then offer it free as open source.

    I’d rather be responsible for myself, thank you. And having someone knowledgeable, like you, who is willing to share your expertise in exchange for our time on your site… WOW… that is a blessing! THANKS!

  • Andrew Scott

    This is **NASTY** & not in anyway Semantic. It would be much better to use proper image elements than setting background on other elements.

    If you really don’t want to use any JavaScript to achieve this just use the #Fragment it would br much more semantic, and thus all round better for the web.

  • http://www.sitebee.co.uk Chris

    Very nice indeed, do you have any live demos? I never saw any links to any.

  • http://www.geekality.net Torleif

    Maybe this could be used to toggle form elements?

    input.optionals + div.more-options {
    display: none;
    input.optionals:checked + div.more-options {
    display:block;
    }

    Should work, as I think input fields with display:none are to be ignored when posting… perhaps… :p

  • Bsz

    Nice tutorial, well explained. I like it.

  • http://mishunov.me Denys Mishunov

    Ouch, Code Pen changed the way they generate URLs, so my links are not valid anymore. You can find the real links in my profile there. Sorry for that.

  • AntoxaGray

    While it’s nice trick, I can’t see where it could be used. So I click on image and it changes, now what?

    • Bryan

      Uses? Tab controls:
      1) UL of LI of labels of tab titles
      2) Hidden radio inputs preceding DIV blocks
      3) All DIVs hidden by default; shown when their radio is :checked

      Until you have to support IE6&7 anyway.

  • http://andersschmidt.com/ Anders Schmidt Hansen

    Thanks for a yet another great article Joshua! It’s a very interesting concept / “trick”, regardless of how unsemantic some find it. We’re all creative people here, and diving into new, strange techniques should just be applauded imho. That’s how we push forward, I think.

    I’ve looked at your example (along with some other resources) and after experimenting with combining radio buttons with sibling selectors and transitions, I’ve constructed an example where CSS mimicks the smooth AJAX-ish load ins, but completely without jQuery. It could work for very simple, information-related sites or teaser sites. And it would only need one html page; the index!

    You can see the example here: http://codepen.io/FingerFeat/full/tckKz

    I’ve tested it in Chrome/Safari so far.

    Keep up the good work!

  • Sara

    I’ve seen some authors use this method and I kinda understood the main idea behind it but this clarifies it completely, thank you for this article it was most helpful. And yes, please do keep such tutorials coming up, I can’t wait for more :)

Subscribe
Membership
About the Author