Pushing CSS to its limit, with the checkbox hack. What could go wrong?

Disclaimer

Let me start off by saying that I’m not a professional web designer. I’m more of a backend person, and enjoy building PHP stuff more than designing everything. That being said, I’ve built quite a few websites, and I’ve learned a few cool CSS tricks along the way. Most of them probably break every web standard ever, but hey, it works. Hope you enjoy.

Before you go on, please know that most of my CSS terminology is probably wrong. This notice is here and not before the “Hope you enjoy” because I’m too lazy to reach over to my mouse right now. Now that I think about it, I could just use the arrow keys, but I already wrote this sentence. 

Checkbox Hack

The CSS checkbox hack essentially enables you to “run” certain CSS when a “button”(it’s not a real button; it’s a label styled like a button) is pressed. This works by using the CSS :checked selector, which was probably designed to change the style of a checked checkbox. But, it can also be used to change the appearance of elements upon a checkbox being pressed. But, as you may have noticed on sign up forms, clicking the label of a checkbox also checks/unchecks it, allowing us to do cool things.

I have no idea why there’s a new paragraph here. Never mind, it’s because my SEO plugin said I should. Hopefully this new paragraph makes it easier for you to read. Moving on…

Using Bootstrap, or other fancy CSS, you can style the label like a button, and hide the actual checkbox. We can then use the ~ selector(a.k.a. the “Subsequent-sibling combinator”) of the CSS to show/hide a div. You can also use it to change colors and such, but that’s not nearly as fun. One more thing I’ll be using is the ::before selector to allow us to change the text of the “button” as it’s toggled/untoggled.

Note: You can also use ::after, but it made more sense to use ::before when I wrote the CSS, so that’s what I’ll be sticking with.

This is actually a lot more useful than people think. Since it’s pure CSS, it can be used in HTML emails, and other situations where JavaScript can’t be used, such as Accelerated Mobile Pages. Speaking of Accelerated Mobile Pages, there aren’t any !important ’s in the CSS, so it should work just fine.

Set up

Before we do all of the fancy CSS stuff, let’s first set up all of the required HTML. The only external CSS we’ll be using is the Bootstrap CSS file to style the label as a button(that’s what the btn and btn-primary classes are for). You probably could just copy the code for this, but it’s easier to just include the entire CSS file. You don’t technically need any styling for the label, but it’s more obvious for users to click a button than just text.

<!DOCTYPE html>
<html>
  <head>
    <title> CSS Stuff </title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
  </head>
  <body>
    <div class="container">
    <input type="checkbox" id="toggle-1">
    <label for="toggle-1" id="label-1" class="btn btn-primary"></label>
    <div id="preview-1">
      <p> This is a preview.</p>
    </div>
    <div id="content-1">
      <p> This is the full contents of whatever you want to show</p>
    </div>
    </div>
  </body>
</html>

The input needs to be before the label so we can change the label depending on whether or not the checkbox is checked(using the CSS squiggly line thing). The order of the preview and content doesn’t really matter, but it makes sense to put the preview first. This sets up all of the HTML we need. The rest is accomplished completely via CSS. By the way, it should look something like this now:

It’s perfectly normal for everything to look broken at this stage. If you want to see the final result, just scroll to the bottom of this post. I say scroll, but this post is probably short enough for the demo to already be onscreen. Unless you’re on mobile or a small screen or something. Ok, that’s enough commentary for this section.

The Magic CSS

Well, what do you know? More commentary. I can sense the excitement.

Now, it’s time to add the CSS magic.  The first CSS snippet we’ll add is to hide the checkbox, preview, and content by default. There’s probably a better way to do this but it works, so why not.

#toggle-1, #preview-1, #content-1 {
    display: none;
}

Now, we’ll use the ::before selector for something you probably shouldn’t use it for. This will set the default contents of the “button” to “Show Content”. When the checkbox is checked, it will change to “Hide Contents” because of a snippet we add later on.

#label-1::before {
  content: "Show Contents";
}

Next, the CSS :hover selector to display the preview when the label is hovered over. We’ll add some CSS to hide this when the checkbox is toggled in a bit. You can change the color, but I recommend choosing a different color from the actual content so it’s easy to tell them apart.

#label-1:hover ~ #preview-1 {
  display: unset;
  color: gray;
}

The moment we’ve all been waiting for, the use of the :checked selector. Yay! This will unset the display: none for the content-1 class when the checkbox is checked.

#toggle-1:checked ~ #content-1 {
  display: unset;
}

If you try it out now, you’ll notice that both the preview and the content are both displayed once the checkbox is checked. That’s because when you go to click the “button”, you hover over it which shows the preview. To prevent this, we’ll just set display: none if the checkbox is checked.

#toggle-1:checked ~ #content-1 {
  display: unset;
}

Time for the last step: changing the label when the checkbox is checked to “Hide Contents”.

#toggle-1:checked ~ #label-1::before {
  content: "Hide Contents";
}

You could probably change the order of the CSS, but something will probably break if you do. But, hey, 99% of the fun of web development and design is debugging.

Result

After you’ve done everything, it should look something like this.

See the Pen CSS Checkbox Hack by NerdOfLinux (@NerdOfLinux) on CodePen.