I have a custom checkbox that is filled with transitions for border, color, etc. as well as for 3d transformation to flip it over. If the checkbox is unchecked it looks fine and transitions nicely between states, however, if the checkbox is given the checked attribute on dom load then it has to spin into place and the checkbox is visible on the backface.
NOTE: Although I link the JsFiddle so you can see the code the issue is not happening in the fiddle. It only happens if the style is linked via style sheet.
https://jsfiddle.net/tj2djeej/
/* Radio & Checkbox */
input.flipCheckbox {
-webkit-transition: transform .5s linear 0s;
-webkit-transform-style: preserve-3d;
-webkit-appearance: none;
-webkit-transform: rotatey(0deg);
-webkit-perspective: 800;
-webkit-transform-style: preserve-3d;
box-sizing: border-box;
position: relative;
outline: none;
width: 26px;
height: 26px;
border: 3px solid #C15649;
cursor: pointer;
}
input.flipCheckbox:checked {
-webkit-transform: rotatey(180deg);
}
input.flipCheckbox:after {
-webkit-transform: rotatey(-180deg);
-webkit-transition: color 0s linear .25s, -webkit-text-stroke-color 0s linear .25s;
-webkit-text-stroke-color: transparent;
cursor: pointer;
line-height: 26px;
font-size: 14px;
width: 26px;
height: 26px;
position: absolute;
z-index: 1;
top: -3px;
left: -3px;
color: transparent;
text-align: center;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: transparent;
}
input.flipCheckbox:checked:after {
color: #C15649;
-webkit-text-stroke-color: #C15649;
}
input.flipCheckbox:after {
content: "\2713";
}
<input type="checkbox" class="flipCheckbox" />
<input type="checkbox" checked class="flipCheckbox" />
onload and once the document is loaded remove the class to trigger all transition on all elements as specified in your css. Here is a reverse solution: Make your html layout and set the css accordingly to your final result (with all the transformation you want). Set the transition property to your liking.
To trigger an element's transition, toggle a class name on that element that triggers it. To pause an element's transition, use getComputedStyle and getPropertyValue at the point in the transition you want to pause it. Then set those CSS properties of that element equal to those values you just got.
If you just want to hide the checkmark when unchecked, there's backface-visibility: hidden
.
input.flipCheckbox:after {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
This should simplify a lot of things for you. For one, you no longer need to animate the checkmark's color from transparent.
The :focus and :hover pseudo-classes should work well for your needs. Just move your transition rule from input.flipCheckbox
to a new rule-set:
input.flipCheckbox:focus, body:hover input.flipCheckbox {
-webkit-transition: transform .5s linear 0s;
}
Since the checkbox is not focused on page load the transition doesn't occur, yet when the user checks the check box it gains focus allowing the transition to occur. The only downside is if the checkbox uses focus before the animation completes. Like when a user is using just the keyboard and tabs away too quickly. That's where :hover
steps in. Since :hover
is applied to body
(html
or any other parent would work as well) as long as the cursor is on the page, the transition still occurs.
You could just use one or the other, but the two together covers everything except if the cursor is off the page and the user tabs away too quickly.
As you said, the issues doesn't occur in online editors, but here's the full code anyways.
input.flipCheckbox {
-webkit-transform-style: preserve-3d;
-webkit-appearance:none;
-webkit-transform: rotatey(0deg);
-webkit-perspective: 800;
-webkit-transform-style: preserve-3d;
box-sizing: border-box;
position:relative;
outline:none;
width: 26px;
height:26px;
border: 3px solid #C15649;
cursor: pointer;
}
input.flipCheckbox:focus, body:hover input.flipCheckbox {
-webkit-transition: transform .5s linear 0s;
}
input.flipCheckbox:checked {
-webkit-transform: rotatey(180deg);
}
input.flipCheckbox:after {
-webkit-transform: rotatey(-180deg);
-webkit-transition: color 0s linear .25s, -webkit-text-stroke-color 0s linear .25s;
-webkit-text-stroke-color: transparent;
cursor: pointer;
line-height:26px;
font-size:14px;
width:26px;
height:26px;
position: absolute;
z-index: 1;
top:-3px;
left:-3px;
color:transparent;
text-align: center;
-webkit-text-stroke-width: 2px;
-webkit-text-stroke-color: transparent;
}
input.flipCheckbox:checked:after {
color: #C15649;
-webkit-text-stroke-color: #C15649;
}
input.flipCheckbox:after {
content:"\2713";
}
<input type="checkbox" class="flipCheckbox"/>
<input type="checkbox" checked class="flipCheckbox"/>
You could set an animation on the element, that changes the element state at its own speed.
The trick here is to get an animation that is:
I Have tried to reproduce your scenario via javascript, redenring the elemnt and setting the check state afterwards. I don't know for sure if this is equivalent to it.
On the snippet press the button and it will alternate rendering the element from scratch, once in the checked state and another in the unchecked
var ele;
var checked = true;
function reload() {
var oldele = document.getElementById("test");
ele = oldele.cloneNode(true);
oldele.parentNode.replaceChild(ele, oldele);
setTimeout(check, 1);
}
function check() {
ele.checked = checked;
checked = !checked;
}
.test {
width: 100px;
height: 100px;
transition: transform 0.5s;
transform: rotateY(180deg);
animation-name: still;
animation-duration: 0.2s;
animation-iteration-count: 1;
animation-direction: normal;
animation-delay: -0.11s;
}
button {
margin: 20px;
}
.test:checked {
transform: rotateY(0deg);
animation-direction: reverse;
}
input {
animation-name: "";
}
@keyframes still {
from, 49.9% {
transform: rotateY(0deg);
}
50%,
to {
transform: rotateY(180deg);
}
}
<input type="checkbox" class="test" id="test" />
<button onclick="reload()">Load</button>
It seems to be a bug with Chrome/Webkit. At least in my version of Chrome and Safari, the behavior I have is the following:
Without any script tag in the html or a script tag before the css link or a completely empty script tag, and without any input elements, there is no transition happening on div, or other non input elements.
Without any script tag in the html or a script tag before the css link or a completely empty script tag, as soon as there's one input element (whichever type), then all elements that have a style that doesn't match default value are transitioned.
If you add a script tag after the css link with at least a space inside it, then no transition occurs on load on any element.
So it looks like input elements trigger some kind of layout refresh, that strangely does not occur when a script is there. Maybe simply because of a delay somewhere in the parsing, or a condition that is wrongly set somewhere. At least this is the behavior I have with Chrome and Safari.
So you can simply add :
<script> </script> <!-- the space is important -->
after you link element, and you won't get the behavior you describe. It is not a css solution, but the problem doesn't seem to be with your CSS, so I'm posting it anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With