In this article, we will learn how to use HTML and CSS to make a Gmail like checkbox. But before we jump right into the topic, there are a few key concepts I want to cover first to make sure we are on the same page.
You can easily follow along by coding on Codepen. You can do that by clicking Start Coding
button on the top left of Codepen home page.
Basic
Here are a few things we need to know first to better understand how to make a Gmail like checkbox. You don't need to fully understand each thing below. Having a basic idea of them is good enough. And don't dive too deep yet when you are linked to the documents on MDN. It may be a lot easier than you think when we start building the checkbox.
Input elements
There is an element called input in HTML. We use it to collect information from users. There are many types of them.
For example:
<input type="text">
The appearance of input
might look different than yours based on the browser you are using, because browsers have their own default styles for input elements.
on Codepen"/>
We can add some text to describe what information we want to collect from users. There is an attribute called placeholder that we can use on <input type="text">
element to provide a brief hint.
Name: <input type="text" placeholder="John Doe">
The value of placeholder
attribute will appear inside the input box.
Pseudo-elements
A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s).
we can style the input's placeholder like this
input::placeholder {
color: blue;
}
The text color of placeholder is set to blue.
Pseudo-classes
A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s).
input:hover
style input when input is hovered. input:hover::placeholder
style input's placeholder when input is hovered.
input:hover::placeholder {
color: red;
}
We are styling the hover
state, which requires a pointer to move on top of the element. Input's placeholder remains color: blue
unless we move the pointer on top of it to trigger its hover state, then color: red
will be applied.
Positioned element
When we set position
to a valid value other than static
, the element we select becomes a positioned element.
Here is what will happen when we set position
to absolute
The element is removed from the normal document flow, and no space is created for the element in the page layout. It is positioned relative to its closest positioned ancestor, if any; otherwise, it is placed relative to the initial containing block. Its final position is determined by the values of
top
,right
,bottom
, andleft
.
Normal flow is the default behavior how browsers place our elements. For example, the block elements are placed top to bottom and content(texts) are placed left to right.
<div>
<div class="child">Hello</div>
<div>World</div>
</div>
.child {
color: red;
}
div
by default is block element, so they are placed top to bottom. The texts inside of divs are placed left to right.
When we set div.child
to position: absolute;
, it no longer takes up space in the normal flow, as it doesn't exist.
.child {
position: absolute;
}
The div
that has content "World" is now placed at where div.child
would be. Because div.child
is now taken out of flow, the "World" div will act like it should be placed first.
Containing block
We can control the position of a positioned element by defining top
, right
, left
, and bottom
. The offset will be relative to the element's closest containing block.
.child {
position: absolute;
right: 0;
}
When we set right: 0;
, as you can see, the .child
div is now at the right edge of the document. The reason that .child
is not positioned relative to .parent
div is because if a positioned element does not have a positioned ancestor, its containing block will be the initial containing block, which has the dimensions of the viewport.
we can make .parent
div to be a positioned element so .child
can be positioned relative to .parent
div. Again, the value of position that is other than static
can set a element to positioned element.
.parent {
position: relative;
}
.parent
div is now a positioned ancestor of .child
div. .parent
div becomes the containing block of .child
div, so setting top
right
left
bottom
on .child
div will now be relative to .parent div
How checkbox is made on Gmail?
Let's take a look at how checkbox looks like on Gmail and explore how it is made.
As you can see, when the pointer is close enough to the checkbox's bottom, left, top, except right, a circular clickable gray area will appear. That clickable gray area can toggle checkbox status.
Inspect element with DevTools
DevTools allow us to do a bunch of stuff that help us develop. We can use it to inspect element on the screen. Press F12 to open DevTools panel(if F12 doesn't work for you, try google how to open DevTools panel)
Click the icon at the top left corner of DevTools panel then move our pointer to the element we want to inspect. We don't need to precisely click on the one we want. We can hover over elements to find which one we want.
As shown in the image, it seems that the checkbox we are looking for is a div, and it has two pseudo elements ::before
and ::after
. When selecting ::before
, we don't see it but it has a size 0*0, which means it is rendered. The div after ::before
is set to display: none
, so when selecting it, we don't see its size because browser doesn't render it. When selecting ::after
, we can see its size covers the checkbox div.
Something you may have noticed is that the area of ::after
seems to match the area that we could trigger the circular clickable area of checkbox.
We can change ::after
size to confirm this.
Because pseudo-element is part of an element, it still belongs to that element. In this case, hovering on ::after
is actually hovering on the checkbox div.
Next, we can explore where that circle comes from. We have learned that :hover
style only applied when the :hover
state is triggered. So we can select the elements one by one and see whose style changes on hover.
As we can see, the styles of checkbox div and ::before
have :hover
styles applied when hovering.
We can use DevTools to force element state rather than manually trigger a state. Force the checkbox div to be hover state so we can easily examine the styles applied by :hover
. The circle we are looking for seems to be the ::before
. Again, we can change its style to confirm that.
The circle comes from ::before
has a initial size of 0*0, which is the result of setting transform: scale(0)
. When hover style applied, its size becomes 40*40, which is the result of setting transform: scale(1)
.
Actually, We have gathered enough information to make a similar checkbox. We can use the native checkbox input element in HTML to build one. In order you are curious, the checkbox on Gmail is a fully custom checkbox. The checkbox div has a background image as the box. When the checkbox div is checked, the background image becomes a checked box.
Let's start building
TODO:
- A checkbox
- A visible circular clickable area
- An invisible area that can make the circle appear
- Make it look nicer
A checkbox
First, we create a checkbox.
<input type="checkbox" class="gmail-checkbox" />
That's all we need to do to have a functional checkbox.
A visible circular clickable area
Let's make a ::before
equal to the checkbox size first. content: ''
is necessary to create a ::before
or ::after
pseudo-element. position: absolute
make it a positioned element , so we can set top
right
bottom
left
on it. inset: 0
is a shorthand as setting top: 0
right: 0
bottom: 0
left: 0
at once.
.gmail-checkbox::before {
content: '';
position: absolute;
inset: 0;
background-color: red;
opacity: 0.5;
}
I add background-color
and opacity
to illustrate a problem we have. The problem is that the ::before
expand across the whole screen, because its containing block is the initial containing block which has the dimensions of the viewport.
We want top
right
bottom
left
on ::before
to be relative to the checkbox not the viewport. We need to make the checkbox a positioned element, so the containing block of ::before
can be the checkbox instead of the initial containing block.
.gmail-checkbox {
position: relative;
}
Checkbox becomes the containing block of ::before
.
transform: scale(3)
makes ::before
larger and border-radius: 50%
makes it rounded.
.gmail-checkbox::before {
border-radius: 50%;
transform: scale(3);
}
Clicking on the red circle can toggle checkbox. We have learned that pseudo-element ::before
is part of an element, so we are actually clicking on the checkbox.
We want to hide ::before
the circle and only show it when hovering on the checkbox.
.gmail-checkbox::before {
opacity: 0;
transform: scale(0);
}
.gmail-checkbox:hover::before {
transform: scale(3);
opacity: 0.5;
}
Currently, we have to hover exactly on the visible checkbox area to show ::before
the clickable circle.
An invisible area that can make the circle appear
We can make an invisible area as an extend of the checkbox to make it easier to be triggered hover state.
.gmail-checkbox::after {
content: '';
position: absolute;
inset: 0;
transform: scale(3);
}
I add background-color
and opacity
to illustrate the area of ::after
. Hovering on ::after
is actually hovering on the element it belongs to, so
Make it look nicer
Add transition to the circle.
.gmail-checkbox:hover::before {
transform: scale(3);
opacity: 0.5;
transition: transform opacity;
transition-duration: 0.3s;
}
You may notice the color on ::before
is coving the checkbox. That's because it is stacked on top of the checkbox. We can use z-index on positioned elements to control how elements are overlapped, but it is out of scope of this tutorial so we won't discuss it.
In our case, the color from ::before
should be light , otherwise the checkbox won't be visible. We can use accent-color to change checkbox color.
Final result
HTML
<input type="checkbox" class="gmail-checkbox" />
CSS
.gmail-checkbox {
position: relative;
accent-color: red;
}
.gmail-checkbox::before {
content: '';
position: absolute;
inset: 0;
background-color: red;
opacity: 0;
transform: scale(0);
border-radius: 50%;
}
.gmail-checkbox:hover::before {
transform: scale(3);
opacity: 0.1;
transition: transform opacity;
transition-duration: 0.3s;
}
.gmail-checkbox::after {
content: '';
position: absolute;
inset: 0;
transform: scale(3);
}
Wrap up
First, we look at a few CSS fundamentals. Then, we inspect the checkbox on Gmail to see how it is made. Finally, we make a similar checkbox with all the knowledge we learn so far.
This article is meant for the beginners so I tried my best to break things down and I repeated a few things purposely because these fundamentals are not easy to understand. After having an overall idea, you can look for the materials you want to learn more.
I hope you find this article useful and I am welcome for any feedback. Thank you :D
Top comments (0)