My latest project involves creating a toggle button for switching between light and dark themes 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>
The functionality of the toggle button is great with a box
width of 90
and height
of 45
. However, upon changing the dimensions to 60
and 30
respectively, issues arise when transitioning to dark mode:
- In dark mode, part of the sun image becomes visible, which is not ideal.
- There seems to be an inconsistency in the path length when sliding left and right, but I can't pinpoint the source of the problem.
To address these challenges, I am looking to make this code more scalable in terms of design adjustments. It would be beneficial to have variables defined in the CSS file for easy customization as per different dimensions. Any guidance or suggestions from experienced developers are highly appreciated.
Updated code snippet below reflects changes made to the width
and height
attributes of the box
:
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>