Build an Animated Radio Button Using HTML and CSS || FREE Source Code
Introduction
In today's blog post, we're going to explore how to create an engaging and interactive animated radio button interface using HTML and CSS. This project is not only a fun way to enhance user experience but also a great opportunity to practice your front-end development skills. Let's dive in and see how we can implement this step by step.
Download
To use this project, simply copy or download the source code. You can also access the code via the Telegram channel CodeWithAarzoo.
Step 1:
Setting Up the HTML Structure
We start by creating the basic HTML structure for our project. This includes the necessary elements such as <form>
, <input>
, and <label>
. Each radio button represents an option, in this case, HTML, CSS, and JavaScript.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Meta tags for defining character set, browser compatibility, and viewport settings -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Linking external stylesheet -->
<link rel="stylesheet" href="style.css">
<!-- Title of the webpage -->
<title>Animated Radio Button</title>
</head>
<body>
<!-- Form for selecting radio buttons -->
<form>
<!-- Radio button for HTML -->
<input id="a" type="radio" name="hopping" value="a" checked>
<label for="a"><span></span>HTML</label>
<!-- Radio button for CSS -->
<input id="b" type="radio" name="hopping" value="b">
<label for="b"><span></span>CSS</label>
<!-- Radio button for JavaScript -->
<input id="c" type="radio" name="hopping" value="c">
<label for="c"><span></span>JavaScript</label>
<!-- Animated worm -->
<div class="worm">
<!-- Worm segments -->
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
<div class="worm__segment"></div>
</div>
</form>
</body>
</html>
Step 2:
Styling with CSS
Now, let's style our radio button interface using CSS. We'll define the layout, colors, transitions, and animations to achieve the desired effect.
/*
Reset styles to remove default padding, margin, and borders,
and ensure elements are sized correctly with box-sizing.
*/
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
/*
Set the base font size using a responsive calculation based on viewport width.
*/
:root {
font-size: calc(32px + (40 - 32) * (100vw - 320px) / (1024 - 320));
}
/*
Styling for the body element, including background color, font, and layout.
*/
body {
background: #e3e4e8;
color: #17181c;
display: flex;
font: 1em Hind, sans-serif;
height: 100vh;
line-height: 1.5;
padding: 1.5em 0;
}
/*
Styling for the form element, positioning it in the center of the page.
*/
form {
display: block;
margin: auto;
max-width: 10em;
position: relative;
}
/*
Styling for input elements, hiding them from view.
*/
input {
position: fixed;
top: -1.5em;
left: -1.5em;
}
/*
Styling for labels, providing interactivity and visual feedback.
*/
label {
cursor: pointer;
display: block;
font-weight: bold;
text-shadow: 0 0.1em 0.1em rgba(0, 0, 0, 0.2);
transition: color 0.2s cubic-bezier(0.45, 0.05, 0.55, 0.95);
}
/*
Style for label elements except the last one, adding spacing.
*/
label:not(:last-of-type) {
margin-bottom: 1.5em;
}
/*
Styling for the span within labels, creating a visual indicator.
*/
label span {
box-shadow: 0 0 0 0.2em currentColor inset, 0 0.2em 0.2em rgba(0, 0, 0, 0.2),
0 0.3em 0.2em rgba(0, 0, 0, 0.2) inset;
display: inline-block;
margin-right: 0.5em;
vertical-align: bottom;
width: 1.5em;
height: 1.5em;
transition: transform 0.2s cubic-bezier(0.5, 0, 0.5, 2),
box-shadow 0.2s cubic-bezier(0.45, 0.05, 0.55, 0.95),
color 0.2s cubic-bezier(0.45, 0.05, 0.55, 0.95);
}
label span,
.worm__segment:before {
border-radius: 50%;
}
/*
Styling for checked inputs and their corresponding labels.
*/
input:checked+label,
input:checked+label span,
.worm__segment:before {
color: #43aaff;
}
/*
Styling for checked input labels and their corresponding spans with transition delay.
*/
input:checked+label,
input:checked+label span {
transition-delay: 0.4s;
}
/*
Styling for checked input spans with transformation.
*/
input:checked+label span {
transform: scale(1.2);
}
/*
Styling for the worm element.
*/
.worm {
top: 0.375em;
left: 0.375em;
}
/*
Styling for the worm and its segments.
*/
.worm,
.worm__segment {
position: absolute;
}
/*
Styling for individual segments of the worm.
*/
.worm__segment {
top: 0;
left: 0;
width: 0.75em;
height: 0.75em;
transition: transform 0.4s cubic-bezier(0.45, 0.05, 0.55, 0.95);
}
/*
Styling for the pseudo element used in worm segments.
*/
.worm__segment:before {
animation-duration: 0.4s;
animation-timing-function: cubic-bezier(0.45, 0.05, 0.55, 0.95);
background: currentColor;
content: "";
display: block;
width: 100%;
height: 100%;
}
/*
Styling for the first and last segments of the worm.
*/
.worm__segment:first-child:before,
.worm__segment:last-child:before {
box-shadow: 0 0 1em 0 currentColor;
}
.worm__segment:nth-child(2) {
transition-delay: 0.004s;
}
.worm__segment:nth-child(2):before {
animation-delay: 0.004s;
}
.worm__segment:nth-child(3) {
transition-delay: 0.008s;
}
.worm__segment:nth-child(3):before {
animation-delay: 0.008s;
}
.worm__segment:nth-child(4) {
transition-delay: 0.012s;
}
.worm__segment:nth-child(4):before {
animation-delay: 0.012s;
}
.worm__segment:nth-child(5) {
transition-delay: 0.016s;
}
.worm__segment:nth-child(5):before {
animation-delay: 0.016s;
}
.worm__segment:nth-child(6) {
transition-delay: 0.02s;
}
.worm__segment:nth-child(6):before {
animation-delay: 0.02s;
}
.worm__segment:nth-child(7) {
transition-delay: 0.024s;
}
.worm__segment:nth-child(7):before {
animation-delay: 0.024s;
}
.worm__segment:nth-child(8) {
transition-delay: 0.028s;
}
.worm__segment:nth-child(8):before {
animation-delay: 0.028s;
}
.worm__segment:nth-child(9) {
transition-delay: 0.032s;
}
.worm__segment:nth-child(9):before {
animation-delay: 0.032s;
}
.worm__segment:nth-child(10) {
transition-delay: 0.036s;
}
.worm__segment:nth-child(10):before {
animation-delay: 0.036s;
}
.worm__segment:nth-child(11) {
transition-delay: 0.04s;
}
.worm__segment:nth-child(11):before {
animation-delay: 0.04s;
}
.worm__segment:nth-child(12) {
transition-delay: 0.044s;
}
.worm__segment:nth-child(12):before {
animation-delay: 0.044s;
}
.worm__segment:nth-child(13) {
transition-delay: 0.048s;
}
.worm__segment:nth-child(13):before {
animation-delay: 0.048s;
}
.worm__segment:nth-child(14) {
transition-delay: 0.052s;
}
.worm__segment:nth-child(14):before {
animation-delay: 0.052s;
}
.worm__segment:nth-child(15) {
transition-delay: 0.056s;
}
.worm__segment:nth-child(15):before {
animation-delay: 0.056s;
}
.worm__segment:nth-child(16) {
transition-delay: 0.06s;
}
.worm__segment:nth-child(16):before {
animation-delay: 0.06s;
}
.worm__segment:nth-child(17) {
transition-delay: 0.064s;
}
.worm__segment:nth-child(17):before {
animation-delay: 0.064s;
}
.worm__segment:nth-child(18) {
transition-delay: 0.068s;
}
.worm__segment:nth-child(18):before {
animation-delay: 0.068s;
}
.worm__segment:nth-child(19) {
transition-delay: 0.072s;
}
.worm__segment:nth-child(19):before {
animation-delay: 0.072s;
}
.worm__segment:nth-child(20) {
transition-delay: 0.076s;
}
.worm__segment:nth-child(20):before {
animation-delay: 0.076s;
}
.worm__segment:nth-child(21) {
transition-delay: 0.08s;
}
.worm__segment:nth-child(21):before {
animation-delay: 0.08s;
}
.worm__segment:nth-child(22) {
transition-delay: 0.084s;
}
.worm__segment:nth-child(22):before {
animation-delay: 0.084s;
}
.worm__segment:nth-child(23) {
transition-delay: 0.088s;
}
.worm__segment:nth-child(23):before {
animation-delay: 0.088s;
}
.worm__segment:nth-child(24) {
transition-delay: 0.092s;
}
.worm__segment:nth-child(24):before {
animation-delay: 0.092s;
}
.worm__segment:nth-child(25) {
transition-delay: 0.096s;
}
.worm__segment:nth-child(25):before {
animation-delay: 0.096s;
}
.worm__segment:nth-child(26) {
transition-delay: 0.1s;
}
.worm__segment:nth-child(26):before {
animation-delay: 0.1s;
}
.worm__segment:nth-child(27) {
transition-delay: 0.104s;
}
.worm__segment:nth-child(27):before {
animation-delay: 0.104s;
}
.worm__segment:nth-child(28) {
transition-delay: 0.108s;
}
.worm__segment:nth-child(28):before {
animation-delay: 0.108s;
}
.worm__segment:nth-child(29) {
transition-delay: 0.112s;
}
.worm__segment:nth-child(29):before {
animation-delay: 0.112s;
}
.worm__segment:nth-child(30) {
transition-delay: 0.116s;
}
.worm__segment:nth-child(30):before {
animation-delay: 0.116s;
}
/*
Styling and animation for various worm hops based on input states.
*/
input:nth-of-type(1):checked~.worm .worm__segment:before {
animation-name: hop1;
}
Step 3:
Adding Animation with CSS
To make our radio button interface more engaging, we'll add animations to simulate hopping motion when an option is selected.
@keyframes hop1 {
from,
to {
transform: translateX(0);
}
50% {
transform: translateX(-1.5em);
}
}
input:nth-of-type(2):checked~.worm .worm__segment {
transform: translateY(3em);
}
input:nth-of-type(2):checked~.worm .worm__segment:before {
animation-name: hop2;
}
@keyframes hop2 {
from,
to {
transform: translateX(0);
}
50% {
transform: translateX(-1.5em);
}
}
input:nth-of-type(3):checked~.worm .worm__segment {
transform: translateY(6em);
}
input:nth-of-type(3):checked~.worm .worm__segment:before {
animation-name: hop3;
}
@keyframes hop3 {
from,
to {
transform: translateX(0);
}
50% {
transform: translateX(-1.5em);
}
}
/*
Dark mode styling for the body and checked elements.
*/
@media screen and (prefers-color-scheme: dark) {
body {
background: #17181c;
color: #e3e4e8;
}
input:checked+label,
input:checked+label span,
.worm__segment:before {
color: #43aaff;
}
}
Conclusion
Congratulations! You've successfully created an animated radio button interface using HTML and CSS. This project not only enhances user interaction but also serves as a valuable learning experience for front-end development. Feel free to customize and expand upon this project to further hone your skills. Happy coding!
This project is part of my #100DaysOfCode challenge. If you found this tutorial helpful, connect with me on social media Aarzoo, and check out more coding content on my YouTube Channel.
Stay tuned for more coding adventures! Happy coding! ๐