I have created a dark theme toggle button using CSS, HTML, and JavaScript:
id("theme-btn").addEventListener("change", function() {
if (this.checked) {
qs(".box").setAttribute('style', 'background-color:#CCCCCC;')
qs(".ball").setAttribute('style', 'transform:translatex(100%);')
document.body.classList.remove("light");
document.body.classList.add("dark");
} else {
qs(".box").setAttribute('style', 'background-color:black; color:white;')
qs(".ball").setAttribute('style', 'transform:translatex(0%);')
document.body.classList.remove("dark");
document.body.classList.add("light");
}
});
// Helper functions
function id(id) {
return document.getElementById(id);
}
function qs(selectors) {
return document.querySelector(selectors);
}
body.dark {
background-color: #616161;
color: white;
}
body.light {
background-color: white;
color: black;
}
input[type="checkbox"] {
display: none;
}
.btn {
align-self: flex-end;
margin: 5px 10px;
}
.box {
display: flex;
flex-direction: column;
justify-content: center;
/* BOX-WIDTH */
width: 90px;
/* BOX-WIDTH/2 */
height: 45px;
background-color: black;
transition: all 1s ease;
position: relative;
/* BOX-WIDTH/4 */
border-radius: 22.5px;
cursor: pointer;
}
.box .ball {
/* BOX-WIDTH/2 */
width: 45px;
/* BOX-WIDTH/2 */
height: 45px;
background-color: grey;
transition: all 1s ease;
position: absolute;
border-radius: 50%;
border: 3px solid black;
}
.box .scenary {
display: flex;
flex-direction: row;
justify-content: space-between;
transition: all 1s ease;
padding: 5px 10px 0px 10px;
}
.box .scenary svg {
/* BOX-WIDTH/3 */
width: 30px;
}
<div class="btn">
<input type="checkbox" name="theme-btn" id="theme-btn">
<label for="theme-btn">
<span class="box">
<span class="ball"></span>
<span class="scenary">
<span class="moon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
</span>
<span class="sun">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</span>
</span>
</span>
</label>
</div>
As you might observe, it works quite well in this situation (i.e., width and height of box equal to 90 and 45). However, when I changed the width and height of box to 60 and 30, respectively in the CSS file, some problems popped up: (Please run the code snippet below)
- When switching to dark mode, some part of the sun image will be visible, which of course is not ideal and annoying.
- It seemed the slider path length of going right and left are different. But I couldn't figure out where did the problem come from...
As mentioned in the title, I think it would be nice to make this code snippet of dark theme toggle button to be scalable. (Preferably having variables defined in the CSS file -> I am not sue if this is possible) I.e., when one changes the width and height of the box, everything will behave properly and nicely.
I am new to web development. Any advice and help would be of great appreciation.
Code snippet with width and width of box changed to 60 and 30:
id("theme-btn").addEventListener("change", function() {
if (this.checked) {
qs(".box").setAttribute('style', 'background-color:#CCCCCC;')
qs(".ball").setAttribute('style', 'transform:translatex(100%);')
document.body.classList.remove("light");
document.body.classList.add("dark");
} else {
qs(".box").setAttribute('style', 'background-color:black; color:white;')
qs(".ball").setAttribute('style', 'transform:translatex(0%);')
document.body.classList.remove("dark");
document.body.classList.add("light");
}
});
// Helper functions
function id(id) {
return document.getElementById(id);
}
function qs(selectors) {
return document.querySelector(selectors);
}
body.dark {
background-color: #616161;
color: white;
}
body.light {
background-color: white;
color: black;
}
input[type="checkbox"] {
display: none;
}
.btn {
align-self: flex-end;
margin: 5px 10px;
}
.box {
display: flex;
flex-direction: column;
justify-content: center;
/* BOX-WIDTH */
width: 60px;
/* BOX-WIDTH/2 */
height: 30px;
background-color: black;
transition: all 1s ease;
position: relative;
/* BOX-WIDTH/4 */
border-radius: 15px;
cursor: pointer;
}
.box .ball {
/* BOX-WIDTH/2 */
width: 30px;
/* BOX-WIDTH/2 */
height: 30px;
background-color: grey;
transition: all 1s ease;
position: absolute;
border-radius: 50%;
border: 3px solid black;
}
.box .scenary {
display: flex;
flex-direction: row;
justify-content: space-between;
transition: all 1s ease;
padding: 5px 10px 0px 10px;
}
.box .scenary svg {
/* BOX-WIDTH/3 */
width: 20px;
}
<div class="btn">
<input type="checkbox" name="theme-btn" id="theme-btn">
<label for="theme-btn">
<span class="box">
<span class="ball"></span>
<span class="scenary">
<span class="moon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-moon">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
</span>
<span class="sun">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-sun">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</span>
</span>
</span>
</label>
</div>