Building a Style Switcher with Pure CSS Using :checked

Share this article

A few years ago, web developers were unable to implement and build so many things using CSS only and without relying on JavaScript. But today CSS is mature enough that it is capable of doing powerful things without writing a single line of JavaScript. You might have also read a couple of articles about “CSS only approaches” that demonstrates the power of CSS.

When it comes to CSS-only approaches, we can’t ignore the :checked pseudo-class selector, which I’m going to use in this post. Of course, I am not the first one to write about this technique, and there have been other more extensive discussions regarding using form elements as JavaScript replacements. For example this Adobe article by Louis Lazaris and this great slideshow by Ryan Seddon.

Key Takeaways

  • The :checked pseudo-class selector in CSS can be used to build a style switcher without needing to write a line of JavaScript. It selects any radio or checkbox element that is checked or selected.
  • The :checked pseudo-class selector works in conjunction with input and label elements. The ‘for’ attribute in the label element, when clicked, selects or checks the associated input element, thus enabling the use of the :checked selector.
  • The CSS ‘position: fixed’ declaration, along with the ‘top’ and ‘right’ properties, can be used to position elements on the page. The ‘z-index’ property ensures that the labels stay on top of any other elements on the page.
  • The :checked pseudo-class selector can be used to change the background of an element, hide or show content, or apply other styles, based on user interaction with the associated label element.
  • The :checked pseudo-class selector works with the adjacent sibling selector (+) and the general sibling selector (~), allowing for interaction between different elements on the page. This technique can be used to create a variety of interactive features on a webpage.

Using :checked

In short, the :checked pseudo-class selector represents (selects) any radio or checkbox element that is checked or selected. The user can change the state of these elements by checking a checkbox or selecting a different value in a set of radio buttons.

Before we dive deeper, take a look at the final demo to get a sense of what we will be building throughout this tutorial:

See the Pen A Style Switcher with Pure CSS using :checked by SitePoint (@SitePoint) on CodePen.

Now let’s get started.

Building the Settings Box

In the demo, you should have noticed the gear icon and how, when clicked, a box with some options appears. Before we go on explaining the HTML and CSS that makes up that box, take a look at the following code:

/* we don't want the input fields to appear, all we need is the labels */
input[type="checkbox"], input[type="radio"] {
  position: absolute;
  visibility: hidden;
}

.settings-box-element {
  z-index: 10;
}

Since we are only interested in showing the labels, the above code is used to hide the checkboxes and radio buttons. Moreover, all the labels have a class of settings-box-element with a z-index property just to make sure the labels will stay on top of any other elements on the page.

Now we can break down the code that makes up the settings box. Let’s start with the gear button. Here is the HTML:

<!-- the gear icon that opens the box when you click on it -->
<input id="settings-btn" class="settings-btn" type="checkbox">
<label for="settings-btn" class="settings-box-element"></label>

And the CSS:

.settings-btn + label {
  position: fixed;
  top: 130px;
  right: 0;
  display: block;
  width: 35px;
  color: #e83737;    
  text-align: center;
  background: #fff;
  cursor: pointer;
}

If you have read an article or two about using form elements as JavaScript replacements, then you should already know that we need to use input and label elements together, so that if one of the two was removed, nothing would work. So we have a checkbox input with an id="settings-btn" and a label with a for attribute that matches the id value. I’ve also added a class of settings-btn to use for our CSS hook.

In the CSS, the label is given a position: fixed declaration with the appropriate direction properties/values (top and right).

Next is the white box that will virtually contain the buttons:

The HTML first:

<!-- the white box that contains the buttons -->
<div class="buttons-wrapper settings-box-element"></div>

And the CSS:

.buttons-wrapper {
  position: fixed;
  top: 130px;
  right: -200px; /* should match element width */
  width: 200px;
  height: 240px;
  background: #fff;
}

The box is a single div element with classes “buttons-wrapper” and “settings-box-element”. As I said earlier, the latter class is mainly used to give the elements a z-index value. The “buttons-wrapper” is used to style the div element. And as you can see, the div was given a width of 200px and a height of 240px to accommodate the 5 buttons you see in the demo. Also, the div is given a position value of fixed and the appropriate right and top properties. The only thing you need to keep in mind here is that the right property should have the same value as the width but in the negative (in order to make it disappear from the viewport).

Lets now take a look at the code for the remaining markup, that is, the 5 buttons. The comments denote the background styles that they control:

<!-- background styles -->
<!-- light background (#eaeaea) -->
<input id="light-layout" class="light-layout" type="radio" name="layout" checked>
<label for="light-layout" class="layout-buttons settings-box-element">
Light Background</label>

<!-- dark background (#494949) -->
<input id="dark-layout" class="dark-layout" type="radio" name="layout">
<label for="dark-layout" class="layout-buttons settings-box-element">
Dark Background
</label>

<!-- image background -->
<input id="image-layout" class="image-layout" type="radio" name="layout">
<label for="image-layout" class="layout-buttons settings-box-element">
Image Background</label>

<!-- pattern background -->    
<input id="pattern-layout" class="pattern-layout" type="radio" name="layout">
<label for="pattern-layout" class="layout-buttons settings-box-element">
Pattern Background</label>

<!-- hide/show content -->
<input id="hide-show-content" class="hide-show-content" type="checkbox">
<label for="hide-show-content" class="layout-buttons settings-box-element">
Hide/Show content</label>

And here is the CSS:

.layout-buttons {
  display: block;
  width: 150px;
  padding: 10px 0;
  text-align: center;
  border: 2px solid black;
  box-sizing: border-box;
  font-size: 0.875em;
  cursor: pointer;
}

.light-layout + label {
  position: fixed;
  top: 140px;
  right: -150px;
}

.dark-layout + label {
  position: fixed;
  top: 185px;
  right: -150px;
}

.image-layout + label {
  position: fixed;
  top: 230px;
  right: -150px;
}

.pattern-layout + label {
  position: fixed;
  top: 275px;
  right: -150px;
}

.hide-show-content + label {
  position: fixed;
  top: 320px;
  right: -150px;
}

Notice that the first checkbox was given the “checked” attribute. That is because we want it to be the one highlighted by default.

Every input field has an id and every label has a for attribute that matches the id for one of the input fields. And as you may or may not know, the secret behind such a technique is the for attribute, because when a label with a for attribute is clicked, the element that is associated with that particular label will be selected/checked and this therefore allows us to use the :checked selector.

All the above labels have a class of “layout-buttons”. This class is used to give the buttons the default and the common styles such as width, padding, borders, etc. The other classes are used to add the unique styles to each. And as you saw for the gear icon and the white box, the position property is used with the value fixed and the appropriate top and right properties. Note that the top value for every label is 45px greater than the one before it; this is to make the buttons stack above each other nicely and without overlaps. Note also that the right property value is the same as the width of the buttons but in negative.

Now take a look at the last part of our CSS code:

input[type="radio"]:checked + label {
  background: #e83737;
  color: #fff;
  border-color: #e83737;
}

The above CSS is used to change the default styles of the label associated with the selected radio button (we have 4 radio buttons). I used the adjacent sibling selector to target every label that is preceded by an input field of type “radio”. So as you can see, the background and border properties were given the value #e83737 (a reddish color) and the color property the value #fff. Nothing really fancy or complex.

The remaining elements in the HTML will be wrapped inside a div:

<div class="main-wrapper">
  <div class="content">
    <h1>Cool stuff with CSS only!</h1>
    <p>Lorem ipsum dolor sit amet...</p>
  </div>
</div>

Notice in the above code that I positioned every element of the settings box independently where I could just wrap them all inside a div or section element and position this one single element, therefore making things simpler. This is done simply because you can’t select a parent element, only a sibling.

So in this case, all the main content is wrapped inside a div with class="main-wrapper". And as you will see later, to be able to change the styles for this div, we will need to select that div by writing something similar to this:

input[type="checkbox"]:checked ~ main-wrapper {
  /* some styles here */
}

Here I’m using the general sibling selector to select the main div, which is the only way to do that.

Clicking the Gear Icon

Clicking the gear icon should make the settings box appear. Here is the code to make that happen:

.settings-btn:checked + label {
  right: 200px; /* match width of .buttons-wrapper */
}

.settings-btn:checked ~ .buttons-wrapper {
  right: 0;
}

.settings-btn:checked ~ .layout-buttons {
  right: 30px;
}

When the user clicks on the gear icon, the checkbox with id="settings-btn" will be selected, and here comes the magic. Once the gear icon is clicked, the following will happen:

  1. Using the adjacent sibling selector (+), the label that comes immediately after that checkbox will be selected and then moved 200 pixels from the right of the viewport.

  2. Using the general sibling selector ~, the elements with classes “buttons-wrapper” and “layout-buttons” will be selected and then moved so that they are 0 pixels and 30 pixels, respectively, from the right of the viewport.

Both the adjacent sibling selector and the general sibling selector are indispensable here as this technique will not work without them.

Changing the background

Let me remind you of the HTML code for the radio buttons:

<!-- background styles -->
<!-- light background (#eaeaea) -->
<input id="light-layout" class="light-layout" type="radio" name="layout" checked>
<label for="light-layout" class="layout-buttons settings-box-element">
Light Background</label>

<!-- Plus 3 other radio buttons/labels... -->

The background that we will be changing is the background of the .main-wrapper element. Here is the CSS:

.light-layout:checked ~ .main-wrapper {
  background: #eaeaea;
}
.dark-layout:checked ~ .main-wrapper {
  background: #494949;
}
.image-layout:checked ~ .main-wrapper {
  background: url(image url) no-repeat center 0 fixed;
}
.pattern-layout:checked ~ .main-wrapper {
  background: url(images/pattern1.png) repeat;
}

You can see that in the HTML we have 4 input elements of type="radio" and 4 labels. When any of the labels is clicked, the input that is associated with that particular label will be selected and therefore matched by the :checked pseudo-class. Then, depending on which label is clicked, one of the above four styles will be applied to the main wrapper.

Hiding/Showing content

For the show/hide element, I’m using a checkbox:

<!-- hide/show content -->
<input id="hide-show-content" class="hide-show-content" type="checkbox">
<label for="hide-show-content" class="layout-buttons settings-box-element">
Hide/Show content</label>

And here is the CSS:

.hide-show-content:checked ~ .main-wrapper .content {
  display: none;
}

In this case, we tell the browser to select the element with class="content" and set it to display: none” when the user clicks on the associated label, therefore selecting the checkbox.

Conclusion

There are many other things you can do using this selector technique and the limit is your own creativity. If this technique is new to you, I hope this article can serve as a starting point for you to experiment with other possibilities.

Below you’ll find the completed demo:

See the Pen A Style Switcher with Pure CSS using :checked by SitePoint (@SitePoint) on CodePen.

Frequently Asked Questions (FAQs) about Building a Style Switcher with Pure CSS Using Checked

What is the purpose of the :checked pseudo-class in CSS?

The :checked pseudo-class in CSS is a user interface pseudo-class, which is used to select and style checkboxes, radio buttons, or option elements that have been selected by the user. It is a powerful tool that allows developers to create interactive and dynamic web pages without the need for JavaScript. For instance, it can be used to create a style switcher, where users can change the appearance of a webpage by selecting different options.

How does the :checked pseudo-class work?

The :checked pseudo-class works by selecting the HTML elements that are currently selected or checked. It is typically used with form elements like checkboxes or radio buttons. When a user selects or checks one of these elements, the :checked pseudo-class becomes active and applies the specified CSS styles to that element. This can be used to highlight the selected option, show or hide content, or even change the entire layout of a webpage.

Can I use the :checked pseudo-class with other HTML elements?

The :checked pseudo-class is primarily used with form elements like checkboxes, radio buttons, and option elements. However, it can also be used with other elements in combination with the HTML5 attribute ‘contenteditable’. This allows you to create interactive content that can be edited by the user, and style it differently when it is in the ‘checked’ or ‘selected’ state.

How can I use the :checked pseudo-class to create a style switcher?

To create a style switcher using the :checked pseudo-class, you would first need to create a form with radio buttons or checkboxes for each style option. Then, in your CSS, you would use the :checked pseudo-class to apply different styles depending on which option is selected. This could involve changing the color scheme, font, layout, or any other aspect of the webpage’s appearance.

Can I use the :checked pseudo-class to create dynamic content?

Yes, the :checked pseudo-class can be used to create dynamic content. By combining it with other CSS selectors and properties, you can show or hide content, change the layout, or create interactive features based on the user’s selections. This can greatly enhance the user experience and make your web pages more engaging and interactive.

Is it possible to use the :checked pseudo-class without JavaScript?

Yes, one of the main advantages of the :checked pseudo-class is that it allows you to create interactive features without the need for JavaScript. While JavaScript is a powerful tool for web development, it can also be complex and difficult to use. The :checked pseudo-class provides a simpler alternative for creating interactive content.

How is the :checked pseudo-class supported in different browsers?

The :checked pseudo-class is widely supported in all modern browsers, including Chrome, Firefox, Safari, and Edge. However, it is not supported in Internet Explorer 8 or earlier versions. Therefore, if you need to support these older browsers, you may need to use a JavaScript-based solution instead.

Can I use the :checked pseudo-class to style checkboxes and radio buttons?

Yes, the :checked pseudo-class can be used to style checkboxes and radio buttons. By default, these form elements have a very basic appearance, but with the :checked pseudo-class, you can customize their appearance to match the rest of your website. You can change the color, size, shape, and even the animation of these elements when they are selected.

What are some common use cases for the :checked pseudo-class?

The :checked pseudo-class is commonly used to create interactive features like style switchers, accordions, tabs, and modals. It can also be used to style form elements like checkboxes and radio buttons, or to create editable content with the ‘contenteditable’ attribute. Its ability to react to user input makes it a powerful tool for enhancing the user experience.

Are there any limitations or drawbacks to using the :checked pseudo-class?

While the :checked pseudo-class is a powerful tool, it does have some limitations. It can only select elements that are currently selected or checked, so it cannot be used to style elements based on other states or conditions. Additionally, it is not supported in Internet Explorer 8 or earlier versions. Despite these limitations, it is still a valuable tool for creating interactive and dynamic web content.

Omar WraikatOmar Wraikat
View Author

Omar is a Computer Engineering student who will graduate in the next year. He is also passionate about web technologies like HTML, CSS and JavaScript.

AdvancedCSSLouisL
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week