Hi,
I’m trying to customize this switch to be able to change its size while maintaining its aspect ratio. So I replaced all the static values with dynamic ones that get calculated w.r.t. one value that I change. For example, if the original height is 34px and I change it to 20px, all the remaining values should be calculated accordingly.
The problem is that it seems my CSS calculations aren’t valid, but I have no clue what the cause could be.
HTML
<label class="switch">
<input type="checkbox">
<span class="slider round"></span>
</label>
CSS
:root {
/* Original values */
--slider-height: 34px;
--slider-width: 60px;
--slider-border-radius: 34px;
--thumb-width: 26px;
--thumb-height: 26px;
--thumb-pos-left: 4px;
--thumb-pos-bottom: 4px;
--input-blur-radius: 1px;
/* New reference value */
--slider-new-height: 20px;
}
.switch {
position: relative;
display: inline-block;
--mult: calc(var(--slider-width) * var(--slider-new-height));
width: calc(var(--mult) / var(--slider-height));
height: var(--slider-new-height);
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .2s;
transition: .2s;
}
.slider:before {
position: absolute;
content: "";
--mult1: calc(var(--thumb-height) * var(--slider-new-height));
height: calc(var(--mult1) / var(--slider-height));
--mult2: calc(var(--thumb-width) * var(--slider-new-height));
width: calc(var(--mult2) / var(--slider-height));
--mult3: calc(var(--thumb-pos-left) * var(--slider-new-height));
left: calc(var(--mult3) / var(--slider-height));
--mult4: calc(var(--thumb-pos-bottom) * var(--slider-new-height));
bottom: calc(var(--mult4) / var(--slider-height));
background-color: white;
-webkit-transition: .2s;
transition: .2s;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
--mult: calc(var(--input-blur-radius) * var(--slider-new-height));
box-shadow: 0 0 calc(var(--mult) / var(--slider-height)) #2196F3;
}
input:checked+.slider:before {
--mult1: calc(var(--thumb-width) * var(--slider-new-height));
-webkit-transform: translateX(calc(var(--mult1) / var(--slider-height)));
--mult2: calc(var(--thumb-width) * var(--slider-new-height));
-ms-transform: translateX(calc(var(--mult2) / var(--slider-height)));
--mult3: calc(var(--thumb-width) * var(--slider-new-height));
transform: translateX(calc(var(--mult3) / var(--slider-height)));
}
/* Rounded sliders */
.slider.round {
--mult: calc(var(--slider-border-radius) * var(--slider-new-height));
border-radius: calc(var(--mult) / var(--slider-height));
}
.slider.round:before {
border-radius: 50%;
}
You can find a live demo here.
Maybe if you add a space after (var
→ ( var
From the post, it seems var isn’t being recognized.
Anyways, take a look at the console too, for errors.
And maybe update the post later on.
Thanks for the suggestions
No change.
That’s the thing. Nothing shows up on the console. That’s why it’s so hard to debug!
This SO answer sheds some light. In a nutshell, at least one side of a multiplication operation needs to be a number (i.e. no dimensions). For example, calc(5px * 5)
and not calc(5px * 5px)
. Furthermore, the right hand side of a division operation also has to be a number. For example, calc(5px / 2)
and not calc(5px / 5px)
.
So in addition to making my code conform to these rules, I also got rid of the intermediate variables (i.e. --mult1
, mult2
, etc.) since I only added them in the hopes that that may have been the issue. Seeing now that this isn’t the case, I no longer need them. Putting all this together, the following snippet, for instance, goes from this:
.switch {
position: relative;
display: inline-block;
--mult: calc(var(--slider-width) * var(--slider-new-height));
width: calc(var(--mult) / var(--slider-height));
height: var(--slider-new-height);
}
to this:
/* Note that --slider-new-height and --slider-height are now numbers */
.switch {
position: relative;
display: inline-block;
width: calc((var(--slider-width) * var(--slider-new-height)) / var(--slider-height));
height: calc(var(--slider-new-height) * 1px); /* A neat way of appending a unit to a number variable */
}
Applying these changes to everything, the code becomes this:
:root {
--slider-height: 34;
--slider-width: 60px;
--slider-border-radius: 34px;
--thumb-width: 26px;
--thumb-height: 26px;
--thumb-pos-left: 4px;
--thumb-pos-bottom: 4px;
--input-blur-radius: 1px;
--slider-new-height: 20;
}
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: calc((var(--slider-width) * var(--slider-new-height)) / var(--slider-height));
height: calc(var(--slider-new-height) * 1px);
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .2s;
transition: .2s;
}
.slider:before {
position: absolute;
content: "";
height: calc((var(--thumb-height) * var(--slider-new-height)) / var(--slider-height));
width: calc((var(--thumb-width) * var(--slider-new-height)) / var(--slider-height));
left: calc((var(--thumb-pos-left) * var(--slider-new-height)) / var(--slider-height));
bottom: calc((var(--thumb-pos-bottom) * var(--slider-new-height)) / var(--slider-height));
background-color: white;
-webkit-transition: .2s;
transition: .2s;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
box-shadow: 0 0 calc((var(--input-blur-radius) * var(--slider-new-height)) / var(--slider-height)) #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(calc((var(--thumb-width) * var(--slider-new-height)) / var(--slider-height)));
-ms-transform: translateX(calc((var(--thumb-width) * var(--slider-new-height)) / var(--slider-height)));
transform: translateX(calc((var(--thumb-width) * var(--slider-new-height)) / var(--slider-height)));
}
/* Rounded sliders */
.slider.round {
border-radius: calc((var(--slider-border-radius) * var(--slider-new-height)) / var(--slider-height));
}
.slider.round:before {
border-radius: 50%;
}