I have blog post with set of images that are enlarged on hover. My problem is that when i enlarge element and it overlaps with other image that is later in page render order then the next image is on top of the enlarged one.
The easy way to stop this is to give some kind of z-index on :hover pseudo selector. But then i have very pesky problem when just after I stop hovering my image then next one is on top of it for fraction of second.
You can see behaviour in this imgur album or on jsfiddle(hover first image)
In short i have following css for hovering effect:
.photo-exp
{
position: relative;
transition: all .4s ease-in-out;
/* some properties deleted which have no connection to hovering effect */
}
.photo-exp:hover
{
transform: scale(1.7);
z-index : 10;
}
It would be very easy to have same effect with javascript and setTimeout function.
But i would like to avoid javascript solution and have some CSS workaround which will change slowly z-index in time after hovering ends.
I tried CSS transition but it is not working
I tried to eddit this snippet but i could not get it working in the way that i wanted.
You need to assign a new transition-delay property, and remove it as soon as the hover begins. That way the z-index can persist for some time even after the mouse is gone. It's a little counter-intuitive; I would expect that the delay should be added on hover and removed off-hover but the opposite works on chrome:
.expander {
position: absolute;
left: 50%; top: 50%;
width: 100px; height: 100px;
margin-top: -50px; margin-left: -50px;
z-index: 1;
transition: transform 400ms 0ms, z-index 0ms 400ms; /* That final "400ms" delays the z-index transition! */
}
.expander:hover {
transform: scale(1.8);
z-index: 2; /* A hovered expander is always on top */
transition: transform 400ms 0ms, z-index 0ms 0ms; /* Remove the z-index transition delay on hover. This is counter-intuitive but works. */
}
.expander:nth-child(1) {
margin-left: -105px;
background-color: #a00000;
}
.expander:nth-child(2) {
margin-left: 5px;
background-color: #00af00;
}
<div class="expander"></div>
<div class="expander"></div>
Note that (unless you try to mouse around really quickly in order to break it) neither square bleeds through the other, not even for a frame, when they expand.
I've also finally managed to solve by myself my problem.
It's more intuitive than #Gershom Maes answer in my opinion.
Fiddle
I have used animation system to achieve the result.
#keyframes nohovering {
0% { z-index: 9; }
100% { z-index: 1; }
}
#keyframes hovering {
0% { z-index: 10; }
100% { z-index: 10; }
}
First one will be by default fired on selector without :hover like this
animation: nohovering 0.9s;
It will guarantee that after i complete my hovering it will go smoothly down from z-index 9 to z-index 1. After hovering my image will be on top of other images. When i tested it for z-index 10 for 0% i had a little glitch when i tried to hovered 2 images at same time and then hover only 1 of them.
For my hovering selector I used:
animation: hovering 0.1s infinite;
It will just loop my image on z-index 10. On hover it will always be on top of the other images. Short animation time guarantee that it will go off after hovering stopped in maximum time of 0.1s.
After deleting normal static z-indexes it works.
Related
I am animating a button. A class is assigned depending on my app state. This is actually implemented in Svelte as follows:
<div class="default"
class:run-animation="{$animate === true}">
But the equivalent in vanilla javascript without Svelte is:
let element = document... (find element)
element.classList.add("run-animation")
... later ...
element.classList.remove("run-animation)
For the sake of a minimum reproducible example, the classes I'm trying to animate/transition between look like this:
.default {
top: 20px;
color: white;
}
#keyframes button-animation {
from {
top: 20px;
color: white;
}
20% {
top: 23px;
color: white;
}
25% {
color: red;
}
100% {
top: 23px;
color: red;
}
}
.run-animation {
animation-name: button-animation;
animation-duration: 2s;
/* Preserve the effect of the animation at ending */
animation-fill-mode: forwards;
}
I add the class to the element, and the button animates just like I want it to. My problem arises when I remove the class. I want the button to transition smoothly back to the default CSS. I have tried adding the animation to the run-animate class:
.run-animation {
animation-name: ... ;
top: 23px;
color: red;
}
I have come across many people stating the transition upon class removal will apply if I add a transition property to the default class. I have tried this as follows:
.default {
...
transition: all 3s linear;
}
But it isn't working. The animation runs smoothly when it is added but the styling immediately reverts to the default when the class is removed (no smooth transition).
MY GOAL: I want to smoothly transition away from the end-state of the animation to the default class when the animate class is removed. Is this possible?
Ideally, I'm adding the class with the Svelte logic at the top so the animation should not be triggered in javascript but rather naturally occur as a result of class assignment.
(My code in practice is a little more complicated than shown, the button has another class with styles not being animated at all and the animation includes more styles such as box-shadow and text-shadow. Still, I don't see why this should be more problematic than just color and top included above)
// JS only toggles '.animation'
document.querySelector("button").addEventListener("click", () => {
document.querySelector("div.default").classList.toggle("animation");
});
body {display: flex}
button {position: absolute; left: 120px}
div.default {
position: absolute;
width: 100px;
height: 100px;
background: darkgreen;
}
/* Above code to make a visible working example */
div.default {
top: 20px;
color: white;
transition: top 0.4s, color 0.1s 0.4s;
}
#keyframes define-animation {
from {
top: 20px;
color: white;
}
}
div.default.animation {
animation-name: define-animation;
animation-duration: 2s;
top: 24px;
color: red;
}
<div class="default">I'm colourful</div>
<button>Toggle ".animation"-class</button>
Above is a working snippet with an animation running on class addition and no reverse transition on class removal. I have tried setting animation direction to opposite values in .default and .animation. I have tried defining the .animate end state properties in the class and/or in the keyframes to attributes.
EDIT: It works now! How?
You cannot apply:
animation-fill-mode: forwards;
The end-attributes need to be defined in the animate class not in the keyframe.
The animation plays when the class is added. Transition timings are used when the class is removed (if the animation has completed).
To get a transition effect, you can use the transition-property.
The transition-property can be used here, since every property you want to animate only has a start- and end-value.
Translating animation-percentages to seconds
To translate the percentages of your CSS Animation button-animation to seconds, you just calculate 'percentage' * 'animation-duration'.
This works for both the transition-duration-property as well as for the transition-delay-property.
Example:
color is being animated from 20% to 25%, which is a duration of 5% with a delay of 20%.
All in all, the animation should take 2 seconds.
So we calculate for:
transition-duration: 5% * 2s = 0.1s
transition-delay: 20% * 2s = 0.4s
With that, we can add transition: color 0.1s 0.4s to the .default-class.
Why add it to .default, and not to .animation?
If we were to add the transition-property to .animation, the following would happen:
When adding .animation, there will be a transition-effect, since the element now has a transition-property defined.
But when removing .animation, the element would no longer have a transition-property defined, meaning there would be no transition.
Now, we want to transition on both adding and removing .animation, meaning we want to have a transition-property defined both when .animation is present and when it is not. That means, transition should not be defined in .animation.
// JS only toggles '.animation'
document.querySelector("button").addEventListener("click", () => {
document.querySelector("div.default").classList.toggle("animation");
});
body {display: flex}
button {align-self: center}
div.default {
position: relative;
border: 2px solid black;
width: 100px;
height: 100px;
background: darkgreen;
}
/* Above code to make a visible working example */
div.default {
top: 20px;
color: white;
transition: top 0.4s, color 0.1s 0.4s;
}
div.default.animation {
top: 23px;
color: red;
}
<div class="default">Some text to see the "color"-property</div>
<button>Toggle ".animation"-class</button>
Why does it behave differently...
...when placing the properties inside the to-section of the animation, than when placing them inside .animation itself?
That is, because the properties are not directly applied to the element itself, but rather the element is stopped in its animation (right at the very end), giving only the appearance of the properties being actually applied.
Removing animation-fill-mode: forwards shows the actually applied properties after the animation has played. Those actually applied properties will be the start-values for transition after .animation is removed.
When defining these properties in .animation, they will inherently be the to-values for the animation (if not defined otherwise in animation itself), and be the applied properties of the element.
That means, when removing .animation, the transition will start from there.
I'm using CSS column count property to achieve 2 columns. When I have a button with hover animation - the first column button works fine but the 2nd column button give a weird jump on hover.
For container I'm using
column-count: 2;
for button its
transition: all ease-in .2s;
transform: translateX(0);
and button hover its
transform: translateX(10px);
I've made a little fiddle for demonstration. Its not working only in Chrome - weirdly.
http://jsfiddle.net/jp6vt97g/2/
Any Idea guys?
There seems to be a bug in Chrome when using transform inside columns. As a workaround, you can animate margin-left instead of transform.
.cta-txt {
display: inline-block;
transition: all ease-in .2s;
margin-left: 0;
}
.cta-txt:hover{
margin-left: 10px;
}
http://jsfiddle.net/dfgueg49/1/
I have an image on my website. When I hover over it I want it to do a 360 spin animation.
I'm currently doing so in CSS:-
.img-responsive:hover {
transition-duration: 2s;
transform:rotate(360deg);
}
However, when the user hovers at the edge of the image, the image rotates and is no longer being hovered over at the edge causing the image to "spasm".
How can I achieve a proper looking and stable rotation? JavaScript would work too.
You can fix it by adding small delay to your transition
Working Demo
.img-responsive:hover {
transition-duration: 2s;
transform:rotate(360deg);
transition-delay: 0.5s;
}
Update:
If you can use animation, You can do this
Updated Demo
.img-responsive {
animation: rotateme;
}
.img-responsive:hover {
animation: rotateme 5s;
}
You can make the image bigger when hovered, so that it's difficult that the user accidentally unhovers
if there is no padding or margin, set
.img-responsive:hover {
transition-duration: 2s;
-webkit-transform:rotate(360deg);
-moz-transform:rotate(360deg);
transform:rotate(360deg);
padding: 50px;
margin: -50px;
}
Increasing the padding to 50px makes sure that the mouse is still on it. Changing the margin in the same amount, but in opposite sense makes it stay at the same location.
fiddle
My issue is that during CSS transition border-radius temporarily stops clipping elements inside if transition of overlapping element involves transform. In my case I have two divs absolutely positioned one above the other where the first one has transition triggered by action on clicking a navigation element inside the second one, like:
<div id="below"></div>
<div id="above"><div id="nav"></div></div>
The above div has border-radius: 50% and clips the nav div. In CSS it goes like (minimal example, original onclick action illustrated as :hover):
#below {
position: absolute; width: 250px; height: 250px;
-webkit-transition: all 1s linear;
transition: all 1s linear;
}
#below:hover {
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
}
#above {
position: absolute;
width: 200px; height: 200px;
border-radius: 50%;
overflow: hidden;
}
#nav {
width: 40px;
height: 200px;
background-color: rgba(0,0,0,0.3);
}
Of course it is better visible in http://jsfiddle.net/UhAVG/ with some additional styling for better illustration.
This works as expected in IE10+ and FF25, also in Chrome 31 and 32 with hardware acceleration disabled. In result only accelerated Chrome shows this unwanted behaviour. So I'm wondering if it's possible to workaround it somehow using current CSS3 techniques.
After some more experiments I've finally found the solution. Sometimes simple ones are the hardest to find. In this case #above {z-index: 1;} (like in http://jsfiddle.net/UhAVG/1/) solves the issue. Wild guess is that z-index prevents some optimization that combines operations from single layer and doing so mistakenly optimizes out applying border-radius on element. With layers separated this is no longer the case.
I need to change the background-color from red to transparent.
This change should occur when I hover over a div.
The reason is why I need it transparent is so I can show an absolute positioned div under the main div, in other words, when I hover over the parent div, I need to show the child div.
When I move away the cursor from this div, I don't want a reverse-transition, I want the background to stay transparent, I want the blue div to always be there after I move away the cursor.
Since I need a PURE CSS solution (No JS/JQuery), I came into the CSS3 Transition.
<div id="parent">
<div id="child">
</div>
</div>
This is a fiddle (Firefox).
#parent
{
background:red;
-moz-transition:background 1s;
}
#parent:hover
{
background:transparent;
}
I thought about doing this with animation, since I can fake this by giving it a temporary duration to stay transparent, for example.
0% {background:red;}
1% {background:transparent;}
100% {background:transparent;}
But then animation will stop when I move the cursor away.
Note: This may sound ridiculous or stupid, but my intention is bigger than this, this is just one small example.
Take a look at the transition-delay property.
#parent { transition-delay:999999s; }
#parent:hover { transition-delay:0s; }
Fiddle
This way, the hover animation will happen instantly (0s) while the transition to the initial state will only happen after 277 hours without leaving the page. You can increase the value a bit further if necessary, though I believe this value is enough for a real world page. =]
I don't think it's possible with pure CSS. As a compromise you can use JavaScript to add a class to the element and then handle all visuals with CSS.
http://jsfiddle.net/ZvcgP/1/
HTML
<div class="effect">Hover me</div>
CSS
.effect {
background-color: red;
-webkit-transition:background 1s;
transition:background 1s;
}
.effect.anim-done {
background-color: transparent;
}
JS
$('.effect').mouseenter(function () {
$(this).addClass('anim-done');
});
use below code to transiton from red to transparent. and please change 'object' to the class of your object
.object {
background-color: red;
-webkit-transition:background-color 1s linear; /* for webkit supported browsers */
-moz-transition:background-color 1s linear; /* for old mozilla browsers */
-o-transition:background-color 1s linear; /* for opera browsers */
transition:background-color 1s linear; /* for css3 supported browsers */
}
.object:hover {
background-color: transparent;
}