Hey Programmers! In this post, we will make an emoji Toggle switch with HTML & CSS without using JavaScript. This project will show you how you can add a touch of fun in your web application.
We will use cool CSS properties like box-shadow, CSS gradient, rotate & transform. I will explain important concepts that are used in this code so that you can create such projects on your own.
Also Read: Light & Day Mode Toggle Switch With HTML & CSS
At the end of this post, I will share the entire source code of this emoji toggle switch project so that you can run this project on your local machine.
Also Read: Simple Minimal Toggle Switch with HTML & CSS
The HTML provides the structure for the Emoji toggle switch, which includes a checkbox input, emoji faces for on/off states, and a label.
<label class="switch">
<span class="switch__wrapper">
<input class="switch__input" type="checkbox" role="switch">
<span class="switch__emoji">
<span class="switch__emoji-face switch__emoji-face--sad">
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-mouth"></span>
</span>
<span class="switch__emoji-face">
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-mouth"></span>
</span>
</span>
</span>
<span class="switch__label">Power</span>
</label>
<label class="switch">
: Acts as the container for the toggle switch.<span class="switch__wrapper">
: Wraps the input and emoji elements.<input class="switch__input" type="checkbox" role="switch">
: The checkbox input, styled and controlled via CSS.<span class="switch__emoji">
: Container for emoji faces that represent different states.<span class="switch__emoji-face switch__emoji-face--sad">
: Represents the “off” state with sad face features.
<span class="switch__emoji-eye"></span>
: Represents the eyes.<span class="switch__emoji-mouth"></span>
: Represents the mouth.<span class="switch__emoji-face">
: Represents the “on” state with happy face features.<span class="switch__label">
: Adds a label for accessibility.Also Read: Night & Day Mode Toggle Switch with HTML & CSS
The CSS styles the toggle switch, defining its size, appearance, and animations. It also provides support for both light and dark themes.
These styles reset default browser styles and set up CSS variables for easy customization.
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--bg: #e8e3e3;
--fg: #1c1717;
--trans-dur: 0.5s;
--trans-timing1: cubic-bezier(0.65, 0, 0.35, 1);
--trans-timing2: cubic-bezier(0.65, 0, 0.35, 1.5);
font-size: calc(56px + (120 - 56) * (100vw - 280px) / (3840 - 280));
}
:root
: Defines CSS variables for colors, transition durations, and font scaling based on viewport width.These styles set the background and text color for the body and inputs, ensuring they transition smoothly.
body, input {
color: var(--fg);
font: 1em/1.5 sans-serif;
transition: background-color var(--trans-dur) var(--trans-timing1), color var(--trans-dur) var(--trans-timing1);
}
body {
background-color: var(--bg);
display: flex;
height: 100vh;
}
body
: Sets the background color and ensures the content is vertically centered.transition
: Smooth transitions for color and background changes.This class defines the basic layout for the switch, including centering it on the page.
.switch {
display: flex;
margin: auto;
}
display: flex
: Enables flexible layout for the container.margin: auto
: Centers the switch horizontally and vertically.This class styles the container for the emoji faces, including positioning, size, and shadow effects.
.switch__emoji {
box-shadow: 0.25em 0.25em 0.125em #000;
overflow: hidden;
pointer-events: none;
top: 0.25em;
left: 0.25em;
width: 1em;
height: 1em;
}
box-shadow
: Adds a shadow for a 3D effect.pointer-events: none
: Prevents user interactions with the emoji faces.These styles adjust positioning for right-to-left languages.
[dir="rtl"] .switch__emoji {
right: 0.25em;
left: auto;
}
[dir="rtl"]
: Ensures proper positioning for RTL languages by switching left to right.These styles handle common properties for the emoji and its parts, such as display, position, and border-radius.
.switch__emoji, .switch__emoji:before, .switch__emoji:after, .switch__emoji-eye, .switch__emoji-mouth, .switch__emoji-face {
display: block;
position: absolute;
}
.switch__emoji, .switch__emoji:before, .switch__emoji:after, .switch__emoji-eye, .switch__emoji-mouth {
border-radius: 50%;
}
border-radius: 50%
: Creates circular shapes for the emoji elements.These styles create the base layers for the emoji, giving it a yellow color and a 3D effect.
.switch__emoji:before {
background-color: #f2c40d;
box-shadow: -0.25em -0.25em 0.25em #c29d0a inset, 0.1875em 0.1875em 0.25em #f9e286 inset;
}
.switch__emoji:after {
box-shadow: 0 0 0.125em 0.0625em rgba(245, 208, 61, 0.5) inset;
}
background-color: #f2c40d
: Gives the emoji a yellow color.box-shadow
: Adds shadows for a 3D effect.These styles control the emoji faces’ transitions and 3D effects, making them switch smoothly.
.switch__emoji, .switch__emoji-face {
transform-style: preserve-3d;
transition: transform var(--trans-dur) var(--trans-timing2);
}
transform-style: preserve-3d
: Ensures 3D transforms are applied to child elements.These classes define the styles for the eyes and mouth of the emoji, including their positions, sizes, and colors.
.switch__emoji-eye {
border: 0.0625em solid #1c1717;
border-right-color: transparent;
border-bottom-color: transparent;
top: 50%;
left: 50%;
width: 0.25em;
height: 0.25em;
transform: translate(-50%, -50%) rotateY(-22.5deg) translateZ(0.5em) rotateZ(45deg);
}
.switch__emoji-mouth {
background-image: radial-gradient(100% 100% at 50% 100%, #f2180d 20%, #f5463d 33%, rgba(245, 70, 61, 0) 35%), radial-gradient(100% 100% at 75% 113%, #000 26%, rgba(0, 0, 0, 0) 35%), linear-gradient(rgba(0, 0, 0, 0) 50%, #000 50% 55%, #1c1717 65%);
top: 50%;
left: 50%;
width: 0.5em;
height: 0.5em;
transform: translate(-50%, -50%) rotateX(-15deg) translateZ(0.5em);
}
border
: Defines the border style for the eyes.background-image
: Creates a gradient for the mouth to simulate depth.These classes apply different rotations to the emoji faces, creating a flipping effect.
.switch__emoji-face {
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: rotateY(0);
}
.switch__emoji-face + .switch__emoji-face {
transform: rotateY(-180deg);
}
transform: rotateY(0)
: Sets the initial rotation for the faces.transform: rotateY(-180deg)
: Rotates the second face to create the flipping effect.These styles are specific to the sad face, giving it different eyes and a sad mouth.
.switch__emoji-face--sad .switch__emoji-eye {
background-color: #1c1717;
border: 0;
width: 0.1875em;
height: 0.1875em;
}
.switch__emoji-face--sad .switch__emoji-mouth {
background-image: none;
border: 0.0625em solid transparent;
border-top-color: #1c1717;
transform: translate(-50%, 0) rotateX(-20deg) translateZ(0.5em);
}
background-color: #1c1717
: Colors the sad eyes black.border-top-color: #1c1717
: Creates a sad mouth using the border.These styles customize the input element and label for the toggle switch.
.switch__input, .switch__label {
-webkit-tap-highlight-color: transparent;
}
.switch__input {
background-color: #d1c7c7;
border-radius: 0.75em;
box-shadow: 0.0625em 0.0625em 0.0625em #fff inset, -0.0625em -0.0625em 0.0625em #d1c7c7 inset, 0 0 0 0.125em #e8e3e3 inset, 0.25em 0.25em 0.125em rgba(0, 0, 0, 0.3) inset, 0.0625em 0.0625em 0.0625em rgba(0, 0, 0, 0.3);
cursor: pointer;
display: block;
width: 2.5em;
height: 1.5em;
-webkit-appearance: none;
appearance: none;
transition: background-color var(--trans-dur) var(--trans-timing1), box-shadow var(--trans-dur) var(--trans-timing1);
}
-webkit-tap-highlight-color: transparent
: Removes tap highlights for mobile browsers.background-color
: Sets the default background color for the switch.These styles apply when the switch is checked, changing its appearance and moving the emoji.
.switch__input:checked {
background-color: #0ac213;
}
.switch__input:checked + .switch__emoji {
transform: translateX(100%);
}
.switch__input:checked + .switch__emoji .switch__emoji-face {
transform: rotateY(179.99deg);
}
.switch__input:checked + .switch__emoji .switch__emoji-face + .switch__emoji-face {
transform: rotateY(0);
}
background-color: #0ac213
: Changes the switch color to green when checked.transform: translateX(100%)
: Moves the emoji to the right when checked.These styles adjust the switch for dark mode, ensuring good contrast and visibility.
@media (prefers-color-scheme: dark) {
:root {
--bg: #1c1717;
--fg: #e8e3e3;
}
.switch__input {
background-color: #382e2e;
box-shadow: 0.0625em 0.0625em 0.0625em #463939 inset, -0.0625em -0.0625em 0.0625em #382e2e inset, 0 0 0 0.125em #544545 inset, 0.25em 0.25em 0.125em rgba(0, 0, 0, 0.3) inset, 0.0625em 0.0625em 0.0625em rgba(0, 0, 0, 0.3);
}
}
@media (prefers-color-scheme: dark)
: Applies dark mode styles based on user preferences.HTML:
<label class="switch">
<span class="switch__wrapper">
<input class="switch__input" type="checkbox" role="switch">
<span class="switch__emoji">
<span class="switch__emoji-face switch__emoji-face--sad">
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-mouth"></span>
</span>
<span class="switch__emoji-face">
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-eye"></span>
<span class="switch__emoji-mouth"></span>
</span>
</span>
</span>
<span class="switch__label">Power</span>
</label>
CSS:
<style>
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--bg: #e8e3e3;
--fg: #1c1717;
--trans-dur: 0.5s;
--trans-timing1: cubic-bezier(0.65, 0, 0.35, 1);
--trans-timing2: cubic-bezier(0.65, 0, 0.35, 1.5);
font-size: calc(56px + (120 - 56) * (100vw - 280px) / (3840 - 280));
}
body, input {
color: var(--fg);
font: 1em/1.5 sans-serif;
transition: background-color var(--trans-dur) var(--trans-timing1), color var(--trans-dur) var(--trans-timing1);
}
body {
background-color: var(--bg);
display: flex;
height: 100vh;
}
.switch {
display: flex;
margin: auto;
}
.switch__emoji {
box-shadow: 0.25em 0.25em 0.125em #000;
overflow: hidden;
pointer-events: none;
top: 0.25em;
left: 0.25em;
width: 1em;
height: 1em;
}
[dir="rtl"] .switch__emoji {
right: 0.25em;
left: auto;
}
.switch__emoji, .switch__emoji:before, .switch__emoji:after, .switch__emoji-eye, .switch__emoji-mouth, .switch__emoji-face {
display: block;
position: absolute;
}
.switch__emoji, .switch__emoji:before, .switch__emoji:after, .switch__emoji-eye, .switch__emoji-mouth {
border-radius: 50%;
}
.switch__emoji:before, .switch__emoji:after {
content: "";
width: 100%;
height: 100%;
transform: translateZ(0);
}
.switch__emoji:before {
background-color: #f2c40d;
box-shadow: -0.25em -0.25em 0.25em #c29d0a inset, 0.1875em 0.1875em 0.25em #f9e286 inset;
}
.switch__emoji:after {
box-shadow: 0 0 0.125em 0.0625em rgba(245, 208, 61, 0.5) inset;
}
.switch__emoji, .switch__emoji-face {
transform-style: preserve-3d;
transition: transform var(--trans-dur) var(--trans-timing2);
}
.switch__emoji-eye, .switch__emoji-mouth {
backface-visibility: hidden;
}
.switch__emoji-eye {
border: 0.0625em solid #1c1717;
border-right-color: transparent;
border-bottom-color: transparent;
border-radius: 50%;
top: 50%;
left: 50%;
width: 0.25em;
height: 0.25em;
transform: translate(-50%, -50%) rotateY(-22.5deg) translateZ(0.5em) rotateZ(45deg);
}
.switch__emoji-eye + .switch__emoji-eye {
transform: translate(-50%, -50%) rotateY(22.5deg) translateZ(0.5em) rotateZ(45deg);
}
.switch__emoji-mouth {
background-image: radial-gradient(100% 100% at 50% 100%, #f2180d 20%, #f5463d 33%, rgba(245, 70, 61, 0) 35%), radial-gradient(100% 100% at 75% 113%, #000 26%, rgba(0, 0, 0, 0) 35%), linear-gradient(rgba(0, 0, 0, 0) 50%, #000 50% 55%, #1c1717 65%);
top: 50%;
left: 50%;
width: 0.5em;
height: 0.5em;
transform: translate(-50%, -50%) rotateX(-15deg) translateZ(0.5em);
}
.switch__emoji-face {
top: 0;
left: 0;
width: 100%;
height: 100%;
transform: rotateY(0);
}
.switch__emoji-face + .switch__emoji-face {
transform: rotateY(-180deg);
}
.switch__emoji-face--sad .switch__emoji-eye {
background-color: #1c1717;
border: 0;
width: 0.1875em;
height: 0.1875em;
}
.switch__emoji-face--sad .switch__emoji-mouth {
background-image: none;
border: 0.0625em solid transparent;
border-top-color: #1c1717;
transform: translate(-50%, 0) rotateX(-20deg) translateZ(0.5em);
}
.switch__input, .switch__label {
-webkit-tap-highlight-color: transparent;
}
.switch__input {
background-color: #d1c7c7;
border-radius: 0.75em;
box-shadow: 0.0625em 0.0625em 0.0625em #fff inset, -0.0625em -0.0625em 0.0625em #d1c7c7 inset, 0 0 0 0.125em #e8e3e3 inset, 0.25em 0.25em 0.125em rgba(0, 0, 0, 0.3) inset, 0.0625em 0.0625em 0.0625em rgba(0, 0, 0, 0.3);
cursor: pointer;
display: block;
width: 2.5em;
height: 1.5em;
-webkit-appearance: none;
appearance: none;
transition: background-color var(--trans-dur) var(--trans-timing1), box-shadow var(--trans-dur) var(--trans-timing1);
}
.switch__input:checked {
background-color: #0ac213;
}
.switch__input:checked + .switch__emoji {
transform: translateX(100%);
}
[dir="rtl"] .switch__input:checked + .switch__emoji {
transform: translateX(-100%);
}
.switch__input:checked + .switch__emoji .switch__emoji-face {
transform: rotateY(179.99deg);
}
[dir="rtl"] .switch__input:checked + .switch__emoji .switch__emoji-face {
transform: rotateY(-179.99deg);
}
.switch__input:checked + .switch__emoji .switch__emoji-face + .switch__emoji-face {
transform: rotateY(0);
}
[dir="rtl"] .switch__input:checked + .switch__emoji .switch__emoji-face + .switch__emoji-face {
transform: rotateY(-360deg);
}
.switch__label, .switch__wrapper {
display: block;
}
.switch__label {
margin-inline-start: 0.5em;
overflow: hidden;
position: absolute;
width: 1px;
height: 1px;
}
.switch__wrapper {
position: relative;
}
/* Dark theme */
@media (prefers-color-scheme: dark) {
:root {
--bg: #1c1717;
--fg: #e8e3e3;
}
.switch__input {
background-color: #382e2e;
box-shadow: 0.0625em 0.0625em 0.0625em #463939 inset, -0.0625em -0.0625em 0.0625em #382e2e inset, 0 0 0 0.125em #544545 inset, 0.25em 0.25em 0.125em rgba(0, 0, 0, 0.3) inset, 0.0625em 0.0625em 0.0625em rgba(0, 0, 0, 0.3);
}
}
</style>
Last Updated: June 18, 2024