Pure CSS Custom Checkbox and Radio Input Types - CodeProject

:

Introduction

Now a days, designers are coming up with custom styled checkboxes and radio buttons, we can do by getting images from designers to toggle the bottom and top of images to toggle the check and uncheck states. But using images is expensive in terms of performance and if images failed to download, the UI will break. So we will use pure CSS/CSS3 selectors to accomplish our design requirements.

Background

Prior to reading this tip, you should know the basics of CSS/CSS3 selectors and usage of input types checkboxes and radio buttons with labels.

Checkbox

The native checkbox will have a different rendering in different browsers based on the rendering engines that browser uses. To have the same kind of look and feel across browsers, we go with images or pure CSS selectors. In this tip, we are not going to use any images, we will completely do it with pure CSS3 selectors.

Steps to Build Custom Checkbox (CSS)

1. Hide actual checkbox input controls

[type="checkbox"]:not(:checked),
[type="checkbox"]:checked {
    position: absolute;
    left: -9999px;
}

So whether it's checked or unchecked, we hide it by making the position absolute to its parent relative container by moving it left of max value.

Now the question arises, if we hide our controls, where are we going to do our custom stuff?

Answer: We are going to take advantage of the label elements that we use for our input types.

Note: While using labels with checkbox to have checked and unchecked to work, you need to specify id for checkbox and for with label pointing to the same id of the checkbox that you want to use.

2. Make the label to be positioned relative (we do this because it's going to act as a container to the absolutely positioned elements (the box and tick mark) within it).

[type="checkbox"]:not(:checked) + label,
[type="checkbox"]:checked + label {
    position: relative;
}

Now we need to place [] box and a tick mark when checked. So we place [] before the label using :before and tick mark after the label using :after, both these will be positioned absolute to the relative container label. So we use absolute positioning and top and left to place the tick inside the [].

3. Place the box before label.

[type="checkbox"]:not(:checked) + label:before,
[type="checkbox"]:checked + label:before {
    content: '';
    position: absolute;
    left:0; 
    top: 2px;
    width: 14px; 
    height: 14px;
    border: 1px solid #aaa;
    background: #f8f8f8;
    border-radius: 3px;
}

We are having width and height of 14px, you can change the size which will suit your needs. And position it according to your requirements. It will have the following output:

https://www.codeproject.com/KB/HTML/894706/Unchecked.png

Note: It will render the same style in all browsers.

4. Place the tick mark after label (The tick mark is not an image, it is the content with font Segoe ui symbol)

[type="checkbox"]:not(:checked) + label:after,
[type="checkbox"]:checked + label:after {
    content: '?';
    position: absolute;
    top: 3px; 
    left: 0;
    font-size: 13px;
    color: green;
    font-family: "Segoe ui symbol";
    transition: all .2s;
}
Note: Segoe Ui symbol font will not come preinstalled in Mac.

5. Now we need to need to have context when checked and unchecked, so we will hide it by scaling it to 0 times its dimensions, i.e., hiding it when unchecked and scale it to 1 times of its dimension that is to show it.

[type="checkbox"]:not(:checked) + label:after {
    transform: scale(0);
}
[type="checkbox"]:checked + label:after {
    transform: scale(1);
}

So we have hidden it initially by scaling it to 0 times its dimensions and showing it on checked by scaling it 1 times of its dimensions.

Usage

<input id="myCheckBox" type="checkbox" /> 
<label for="myCheckBox" ></label>

id and for are important to have the checked and unchecked linked to the label that has context of the checkbox.

Codepen here.

Radio Input

This will be same as checkbox, just instead of checkbox type we going to have radio and instead of tick mark we are going to have a circle, and border-radius to have circle instead of box, we will have 10px border radius. But don't worry, we will go step by step for radio input also. :) But we cannot have a single radio button to see checked and unchecked, because once checked, you cannot uncheck until you select another radio option, so in this example we will have two radio buttons say male and female naming as gender.

1. Hide actual radio input types

[type="radio"]:not(:checked),
[type="radio"]:checked {
    position: absolute;
    left: -9999px;
}

2. Make label of radio button relative positioned

[type="radio"]:not(:checked) + label,
[type="radio"]:checked + label {
    position: relative;
}

3. Place radio() circle before the label

[type="radio"]:not(:checked) + label:before,
[type="radio"]:checked + label:before {
    content: '';
    position: absolute;
    left: 0;
    top: 1px;
    width: 15px;
    height: 15px;
    border: 1px solid #aaa;
    background: #f8f8f8;
    border-radius: 10px;
}

For the label not to overlap with your absolutely positioned radio buttons, have some padding-left of 25px to your labels. Your output will look like this:

[type="radio"]+label{
  padding-left:25px;
}

4. Place dot (.) after label. (The dot is a filled segoe ui symbol content.)

[type="radio"]:not(:checked) + label:after,
[type="radio"]:checked + label:after {
    content: '?';
    top: 3px;
    position: absolute;
    left: 5px;
    font-size: 8px;
    color: #000;
    font-family: "Segoe ui symbol";
    transition: all .2s;
}

5. Now hide it by scaling to 0 times its dimensions when unchecked and scale it to 1 times its dimensions to show it when checked.

[type="radio"]:not(:checked) + label:after {
    transform: scale(0);
}
[type="radio"]:checked + label:after {;
    transform: scale(1);
}

Usage

<input type="radio" name="gender" id="male" />
<label for="male">Male</label>
<input type="radio" name="gender" id="female" />
<label for="female">Female</label>

Codepen here.

The output will be like this if you select one option. This will have the same kind of rendering in all browsers.

Thanks for reading. :)