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" />
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:
Not really an animation, in the sense that there is no change in the property value. This is achieved setting 2 different keyframes with the same value.
The same animation for both the checked and the unchecked states. If we change the animation name, the animation will be replayed every time that we change states. To allow for this, I set an animation that has 2 different parts, one that has the element rotated and another with the element unrotated. We use one part or the other changing the direction from normal to reverse. And setting an initial delay that makes it use only the last half.
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.
Does it need to connect to an external style sheet? You may be able to get away with a <style> tag in the html file itself. If not, make sure that the <link> is in the header so that it loads first, enabling the CSS to be applied as soon as the page loads.
Bit hackish but satisfies the css only requirement.
Do a one time "animation" on the elements with checked attribute:
input.flipCheckbox[checked]{
animation-name: fakeRotate;
animation-duration: 0.1s;
animation-iteration-count: 1;
}
#keyframes fakeRotate {
from {
transform: rotatey(180deg);
}
to {
transform: rotatey(180deg);
}
}
Related
I want my button to first fade in then I want the hover effects to take place after the button has faded in.
The code can be found here. What can I do to activate the hover effects after the button has faded in.
here is the HTML code for the button:
discover our tours
and here is the css code:
.btn:link,
.btn:visited{
text-decoration: none;
text-transform: uppercase;
padding: 15px 40px;
display: inline-block;
border-radius: 30px;
opacity: 0;
animation: fadeIn 1s ease-out;
animation-delay: 1s;
animation-fill-mode: forwards;
}
.btn:hover{
transform: translateY(-3px);
}
.btn:active{
transform: translateY(-1px);
}
.btn-white{
background-color: red;
color: white;
}
#keyframes fadeIn{
0%{
opacity: 0;
transform: translateY(-30px);
}
100%{
opacity: 1;
transform: translate(0);
}
}
the entire code can also be viewed here https://codepen.io/mohits0631/pen/QWjJJEb
animation-fill-mode: forwards sets your transform function based on the end of your animation which cant be overwritten. thats the reason only translate function isn't working there. During hover function you could manually set the animation-fill-mode to none and then set opacity to 1. Hope this works :)
According to the docs,
Only elements positioned by the box model can be transformed. As a rule of thumb, an element is positioned by the box model if it has display: block.
I modified your code to check:
.btn:hover{
transform: translateY(-3px);
color: green;
}
The transform did not work but the color worked, so I did
.btn:hover{
display:block;
transform: translateY(-3px);
color: green;
}
and it worked
I created a menu that slides in on hover.
When i move the mouse away from the menu it doesn't return to the pre hover state even though I've specified the container width and height so anywhere the mouse moves outside that it should return.
#menucontrol {
width:500px;
height: 800px;
}
#menucontrol:hover #navdiv {
left: 23px;
transition: all .3s ease-in-out;
opacity: 1.0;
}
#menucontrol:hover #dashes {
transform: rotate(360deg);
transition: all .3s ease-in-out;
opacity: 0;
}
#navdiv {
position: absolute;
top: 68px;
left:-55px;
z-index:999999;
opacity: 0;
width: 555px;
transition: all .3s ease-in-out;
}
The reason this is happening is that your #menucontrol div is taking up the entire page except for the area of your logo. I would suggest trying the :hover psuedo element on your #dashes id. I also noticed your z-indexes are set on some elements and not others. I think this could also be causing you some issues. Without seeing your html it is hard to duplicate and make changes to help you solve this issue.
I am rotating an object with CSS upon hovering, and would like for it to remain in it's new position as you unhover it. I have searched around, but the only thing I could find is css :hover rotate element and keep the new position, which seems to go above and beyond.
Is this effect possible to achieve purely with CSS? I want the icon to remain at the 180 position once you stop hovering.
I used this code:
i.fa.fa-globe:hover {
color: #e9204f;
transition: 0.9s;
transform: rotatey(180deg);
}
Also it's a font-awesome icon if this makes any difference.
Edit - The easy CSS solution for everyone else who needs it (taken from the comments):
.lovernehovermarket i.fa.fa-rocket {
transform: rotate(0deg);
transition: transform 999s;
}
I had a circular icon that I wanted to rotate on every hover, not just the first, and not rotate when un-hovered.
Original
I saw this problem when I had CSS that looked like this
.icon {
transition: transform 0.5s;
}
.icon:hover {
transform: rotate(90deg);
}
Solution
The simple solution was to put the transition inside the :hover psuedo class
.icon:hover {
transition: transform 0.5s;
transform: rotate(90deg);
}
Boom, done!
This works because I was originally setting the transition to be 0.5s by default. In this case, that means both forward and backward. By putting the transition property inside the hover, I have a 0.5s transition when hover is activated, but a 0s transition (the default) when the icon is un-hovered. Having a 0s hover means it just instantly snaps back to position, invisibly to the viewer.
I you want a pure CSS solution, you can set a transtion time to go back to the base state quite high.
It's not for ever, but it's pretty close for most users:
.test {
display: inline-block;
margin: 10px;
background-color: tomato;
transform: rotate(0deg);
transition: transform 999s 999s;
}
.test:hover {
transform: rotate(90deg);
transition: transform 0.5s;
}
<div class="test">TEST</div>
You also need an initial transform state in the regular CSS of your element, so that it can transform between two defined states:
.rotate {
width: 20px;
height: 100px;
background: blue;
transition: 0.9s;
transform: rotate(0deg);
}
.rotate:hover {
transform: rotate(180deg);
}
body {
padding: 100px;
}
<div class="rotate"></div>
If you want to maintain the rotated state, you may have to use a little JQuery to check when the transition ends and change the class so it doesn't revert back to its original state on blur.
This way the div is rotated once and then its class is changed to maintain the rotated state.
$('.rotate').hover(function () {
$(this).addClass("animate");
$(this).one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend',
function(e) {
$(this).removeClass('rotate').addClass('rotated');
});
});
.rotate {
width: 100px;
height: 100px;
background: gold;
transition-property: transform;
transition-duration: 1.5s;
transition-timing-function: linear;
}
.animate {
animation: rotate 1s linear;
transform: rotate(180deg);
animation-play-state: running;
}
.rotated
{
width: 100px;
height: 100px;
background: gold;
transform: rotate(180deg);
}
body {
padding: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="rotate">some text</div>
Use an animation, and apply it using JS event listener, when the element is hovered (mouseover event). When the element is hovered for the 1st time, remove the event listener:
var rect = document.querySelector('.rectangle')
function rotate() {
this.classList.add('rotate');
rect.removeEventListener('mouseover', rotate);
}
rect.addEventListener('mouseover', rotate);
.rectangle {
width: 100px;
height: 100px;
background: gold;
}
.rotate {
animation: rotate 0.5s linear;
}
#keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(180deg);
}
}
body {
padding: 30px;
}
<div class="rectangle"></div>
What worked for me was to put the transform not on hover but on the main css.
not:
#gear {
width: 3vh;
height: auto;
cursor: pointer;
&:hover {
transform: rotate(45deg);
transition: transform 200ms;
}
}
but
#gear {
width: 3vh;
height: auto;
cursor: pointer;
transition: transform 200ms;
&:hover {
transform: rotate(45deg);
}
}
Once I start animating, on Chrome I get a ripple effect. My circle transform scales up. On Firefox, that exact same animation is ignored for some reason.
$("#animate").click(function() {
$("#square").toggleClass("animate");
$("#fab").toggleClass("ripple");
});
#keyframes ripple {
from {
transform: scale(0)
}
to {
transform: scale(20)
}
}
#square {
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
border: 1px solid red;
transition: background 0.1s linear 0.6s, transform 1s;
transform: rotate(0deg);
}
#fab {
position: absolute;
width: 56px;
height: 56px;
border-radius: 50%;
background: #4FB5AB;
top: 122px;
right: 0;
transform: scale(1);
transition: transform 1s;
}
.ripple {
animation: ripple 1s 0.5s;
transform: scale(20) !important;
/*Duration - delay */
transition: transform 0s 1s !important;
}
.animate {
transform: rotate(90deg) !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="square">
<div id="fab"></div>
</div>
<br />
<button id="animate">animate</button>
CodePen Demo
Before I start explaining the problem with your code, here is a word of caution - Do not use transitions and animations together. They generally end up causing problems like the one faced here.
When an animation is specified on an element, it will take complete control over the properties that are being animated unless there is a rule with !important setting. If !important setting is used then that rule takes precedence over the animation. (but unfortunately Chrome and Firefox seem to be handling this case differently).
As per W3C Spec:
CSS Animations affect computed property values. During the execution of an animation, the computed value for a property is controlled by the animation. This overrides the value specified in the normal styling system. Animations override all normal rules, but are overriden by !important rules.
emphasis is mine
In your code, there were two problems and they are as follows:
Within .ripple selector, you were specifying the transition-duration as 0s, which means, there is no transition at all and that the change of transform is an instant one. As explained in the W3C Spec, Firefox seems to be (correctly) giving the control to the rule with !important setting (that is, the transform and transition within .ripple selector) and so it transitions the state change immediately after the specified 1s delay+. Chrome lets animation take control and thus produces the effect you are looking for.
Firefox seems to animate the element quicker than Chrome does and so while a duration of 1s is enough for the animation in Chrome, FF needs it to be 2s to be slower and show the effect.
+ - You can further verify this by removing the !important settings on the rules. Once !important is removed, the animation would take control.
$("#animate").click(function() {
$("#square").toggleClass("animate");
$("#fab").toggleClass("ripple");
});
#keyframes ripple {
from {
transform: scale(0)
}
to {
transform: scale(20)
}
}
#square {
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
border: 1px solid red;
transition: background 0.1s linear 0.6s, transform 1s;
transform: rotate(0deg);
}
#fab {
position: absolute;
width: 56px;
height: 56px;
border-radius: 50%;
background: #4FB5AB;
top: 122px;
right: 0;
transform: scale(1);
transition: transform 1s;
}
#fab.ripple {
animation: ripple 2s 1s;
transform: scale(20);
/*Duration - delay */
transition: transform 1s 1s;
}
#square.animate {
transform: rotate(90deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="square">
<div id="fab"></div>
</div>
<br />
<button id="animate">animate</button>
Finally, please do not use !important unless it is mandatory. Instead just make the selector more specific. In the snippet, I have made it more specific by using the #id.class format.
I am afraid there are similar questions to this but I didn’t found a concrete solution, so I created a fiddle:
http://jsfiddle.net/Garavani/yrnjaf69/2/
<div class= "category_item">
<div class= "cat_button">
<span class="title_cat">TEXT</span>
</div>
</div>
CSS:
.category_item {
position: absolute;
background-color: #999;
top: 100px;
left: 50px;
width: 200px;
height: 200px;
/* seems to be overwriten by animation keyframes */
-webkit-transition: -webkit-transform 0.215s ease-in-out;
transition: transform 0.215s ease-in-out;
cursor: pointer;
}
.category_item:hover {
-webkit-animation-name: easeBack;
animation-name: easeBack;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes easeBack {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
50% {
-webkit-transform: translateY(-50px);
transform: translateY(-50px);
}
100% {
-webkit-transform: translateY(-30px);
transform: translateY(-30px);
}
}
.cat_button {
position: absolute;
width: 200px;
height: 55px;
bottom: 0;
border: 2px solid #fff;
color: #fff;
-webkit-transition: background 0.215s ease-in-out, border 0.215s ease-in-out, color 0.215s ease-in-out;
transition: background 0.215s ease-in-out, border 0.215s ease-in-out, color 0.215s ease-in-out;
}
.category_item:hover .cat_button {
background: #fff;
border-color: #fff;
color: #511c5b;
}
In this (simplified) animation everything works fine except for when the mouse leaves the entire box. The animation starts from it original state, but abruptly.
The basic transition time (and ease) is ignored because it seems the keyframes have higher importance and overwrite it.
What I need is the keyframe animation triggering AND when the mouse leaves it should turn back to the original state smoothly.
Is there a solution for this
1) in pure CSS
2) maybe with some little javascript only?
Thanks in advance for help and ideas!
EDIT:
After implementing the solution offered kindly by Toni this is the correct fiddle:
http://jsfiddle.net/yrnjaf69/40/
Thanks again Toni!
EDIT 2:
Sadly, yet, there is one question left. The part with the keyframes is not executed on Firefox even though I added all the -moz- vendors, too, in this fiddle:
http://jsfiddle.net/dr6Ld0wL/1/
Why?
PS: As far as I tested for now it works even in Opera (Beta). Only browser resisting is Firefox
EDIT 3:
The correct (working) code is now in this fiddle:
http://jsfiddle.net/dr6Ld0wL/16/
The keyframes also need to be explicitly divided in vendor prefixes. Jesus Christ. Those prefixes…
Here is a jsfiddle that achieves this.
.demo-hover {
position: relative;
margin: 100px;
animation: complexProcessReversed 2s ease-in forwards;
width: 160px;
height: 160px;
background-color: #88d;
}
.demo-hover:hover {
animation: complexProcess 2s ease-in forwards;
width: 100px;
height: 100px;
background-color: #732;
}
#keyframes complexProcess {
/* keyframes */
}
#keyframes complexProcessReversed {
/* keyframes (opposite) */
}
The animation out is assigned in the css in the main class, then the hover state kicks in on hover and css re-applies the original class properties on unhover.
The animation does trigger backwards on page load, so you might like to think of tweaking your animation to take this into account, like this example, pinched from this answer. Alternatively, use javascript (or jquery), like this example where the animations are triggered by adding and removing classes to the target using jquery:
JavaScript
$('.demo-hover').hover(
function() {
// mouse in
$(this).removeClass('forwards--reversed').addClass('forwards');
},
function() {
// mouse out
$(this).removeClass('forwards').addClass('forwards--reversed');
}
);
CSS
.forwards {
animation: complexProcess 2s ease-in forwards;
width: 100px;
height: 100px;
background-color: #732;
}
.forwards--reversed {
animation: complexProcessReversed 2s ease-in forwards;
width: 160px;
height: 160px;
background-color: #88d;
}
Also, I'd use #keyframe or transition. Use transition if you just need a simple even change from n to m but when things are more complex, such as one thing changing evenly over 100% but another thing not starting until 50% off the animation has played, then use a #keyframe
Using both will cause confusion, especially if you're trying to animate the same properties.
Finally css vendor prefixes are required