Is a new transition always applied before the new value? - css

Suppose I'm using transition, to smoothly change an element's position on hover. I also change the value of transition itself to achieve a different animation in each direction.
It seems like when I move the mouse over the elements, the new transition value is used for the "forward" transition, and when I un-hover, the old value is used for the "reverse" transition.
I couldn't find much documentation about this. Is the order guaranteed?
div {
background: red;
width: 40px;
height: 40px;
position: absolute;
top: 30px;
left: 0px;
transition: left 1s linear, top 1s ease-in-out;
}
:hover div {
top: 150px;
left: 400px;
transition: left 1s linear, top 1s linear;
}
div:nth-child(2) { transition-delay: 0.1s; }
div:nth-child(3) { transition-delay: 0.2s; }
div:nth-child(4) { transition-delay: 0.3s; }
Hover on me!
<div></div>
<div></div>
<div></div>
<div></div>

[...] all 3 properties change their values when I hover on the element, and it's not intuitively clear in which order the changes are applied, at least coming from background experience with a framework such as Core Animation where "model" and "presentation" layers are separate things and the parameters of an animation are set up before the animation starts running. I think your answer makes sense though...
I think the key difference here is that thinking about transition in terms of "animations starting while the element is/isn't :hovered" is the wrong way to think about it.
You are right, the paradigm you're used to (an MVC paradigm) doesn't really apply to CSS. At least not at the level where you as a CSS "writer" are affected. The relevant spec for this, by the way, is CSS Transitions
In CSS, changes to CSS properties apply immediately. Transitions allow you to apply a change to a value over some duration. In your case, you have four divs who are all set to be 30px from the top and 0px from the left edges of the screen.
On hover, thanks to your :hover div selector, new styles apply. Normally they'd apply instantaneously, but because you gave them a transition, it happens over a duration. You can see each one move individually thanks to the transition-delay you gave some of them, as well. To make it even easier to see, I changed the color of each div to be unique. It should be pretty clear which ones move first.
As soon as you remove your mouse, the :hover pseudo-class no longer applies, and so the styles under div are re-applied. Again, they would be instantaneously applied, but the transition you set (along with the transition-delay on 3 of the 4 divs) changes that to occur over a longer duration. So, just as when the :hover` styles apply, the red div moves first, then the others after an increasing 0.1s delay each.
div {
background: red;
width: 40px;
height: 40px;
position: absolute;
top: 30px;
left: 0px;
transition: left 1s linear, top 1s ease-in-out;
}
:hover div {
top: 150px;
left: 400px;
transition: left 1s linear, top 1s linear;
}
div:nth-child(2) { transition-delay: 0.1s; background: blue; }
div:nth-child(3) { transition-delay: 0.2s; background: green; }
div:nth-child(4) { transition-delay: 0.3s; background: yellow; }
Hover on me!
<div></div>
<div></div>
<div></div>
<div></div>

Related

CSS animation 0px to initial not working

Can I animate width from 0px to initial? Or it has to be absolute value?
span {
background: red;
animation: scroolDown 1s linear;
display: inline-block;
}
#keyframes scroolDown {
from {
width: 0px;
}
to {
width: initial;
//width: 130px;//works
}
}
<span>asdfdsafsafdsafdsaf</span>
Why does this happen?
When you set width to initial, you're really setting the width to auto (which is the initial value of the width property).
This issue dates as far back as 2007, when this bug was reported on WebKit. You can follow the conversation on that report and see:
The CSS WG has resolved that transitions don't run to/from auto values.
This is the behavior for all of the major browsers, so when trying to animate width to auto, we're out of luck and we have to go with an existing workaround.
The Workarounds
There's a few workarounds for animating to auto, but animating max-width is by far the most popular as it was already referenced by the two answers before this.
Rather than listing and explaining the workarounds in this post, I suggest you see this awesome article on the workarounds for this problem.
Summarizing the article, the workarounds are:
Animating max-height with explicit values
Animate transform with scaleX
Use JavaScript to achieve the desired effect
Use Flexbox
If you really need the functionality of animating to auto, your best bet is animating with JavaScript.
You can animate the max-width rather that the width; if you set the end width to something you know is at least as great as the desired end width, it will stop growing automatically at its natural width!
In this example, I set the end width at 20em, about twice the natural size, and I also increased the animation time, so that the time is about the same as the originally intended one.
span {
background: red;
animation: scroolDown 2s linear; /* about twice the expected time */
display: inline-block;
}
#keyframes scroolDown {
from {
max-width: 0px;
}
to {
max-width: 20em; /* about twice the expected size */
}
}
<span>asdfdsafsafdsafdsaf</span>
The concept for this kind of solution comes from How can I transition height: 0; to height: auto; using CSS?, so maybe I should have closed as a duplicate instead. Sorry.
Is this what you're trying to achieve?
The text gets unrevealed as the animation occurs with the background instead of text appearing and the background animating with a delay.
.inner {
display: inline-block;
height:20px;
background: #c3c;
overflow: hidden;
-webkit-transition: width 1s ease-in-out;
-moz-transition: width 1s ease-in-out;
-o-transition: width 1s ease-in-out;
transition: width 1s ease-in-out;
animation: mymove 3s linear;
}
#keyframes mymove {
0% {
max-width: 0px;
}
100% {
max-width: 100%;
}
}
<span class="inner">
This is a test text for testing the text appearance for this test.
</span>

Hover off transition css

this question might be obvious but i'm new in css.
I'm animating a shape so when you hover it, it stretches. I've completed the hover on with a nice ease transition but when you move off the mouse the transition doesn't work. Is there a way to make it happen also in the hover off moment?
.shape1{
position: absolute;
background:red
top:512px;
width:180px;
height:140px;
}
.shape1:hover {
height: 160px;
top:492px;
transition: 0.2s ease;
}
Your answer
You have added the transition property on the hover state of the element. Therefore the transition is not applied when you leave the cursor from the element.
.shape1{
position: absolute;
background: red;
top: 512px;
width: 180px;
height: 140px;
transition: .2s ease; /* move this here from :hover */
}
Further information
Besides this you can also add specific properties to the transition. For example, if you only want the height to be animated you could it like this:
.shape1 {
transition: height .2s ease;
/* this inly affects height, nothing else */
}
You can even define different transition-times for each property:
.shape1 {
transition: height .2s ease, background-color .5s linear;
/* stacking transitions is easy */
}
Add the transition before the :hover, so the transition always applies
.shape1 {
transition: 0.2s ease;
}
The :hover selector is used to select elements when you mouse over them.
W3Schools
When you add also transition to your shape1 class it should works

Chrome Transitions doesnt work. all other browsers do

I've created a menu that adjusts itself as it gets past a certain point of the screen. Everything works great, except for transitions and only on Chrome.
I tried adding a -webkit- version of the transition, but it doesn't work either.
This is my CSS
.past-main {
height: 97px !important;
margin-left: -40px;
width: 100%;
top: 0px !important;
position: absolute;
-webkit-transition: height 300ms opacity 300ms top 300ms ease 0s;
transition: height 300ms, opacity 300ms,top 300ms ease 0s;
opacity: 1!important;
height: 90px !important;
margin-top:0px !important;
}
.past-maina {
-webkit-transition: top 800ms ease 0s;
transition: top 800ms ease 0s!important;
top:0px!important;
}
.past-mainb {
-webkit-transition: all 800ms ease 0s;
transition: all 800ms ease 0s;
margin-top:0px!important;
}
To add more context, the various levels of your header menu gets those classes applied when the user scrolls past a certain point:
some wrapper elements get past-maina and past-main
each menu item (they are li elements) gets past-mainb
Before scrolling down, each menu item has varying margin-top values; afterwards they all get 0. These are set with style rules like
.desktop-nav ul li:nth-child(1) {
margin-top: -10px;
}
Now, this selector has a higher specificity (22) than your .past-mainb selector (10), which, I'm guessing, is why you added the !important annotation to the latter's rule: otherwise, it wouldn't take effect.
But this had an undesired side effect: important declarations always win over transitions! Thus, if you want your transitions to take effect you can't use !important.
The simple cheat is to up the specificity of the "past main" style rules. For example, add an ID selector. Or perhaps better: instead of adding a class when the user scrolls, remove a "before main" class instead, and rewrite all the rules giving specific menu-item margins to use it:
.desktop-nav.before-main ul li:nth-child(1) {
margin-top: -10px;
}

CSS: Preventing a property to affect on element until the end of transition

We've some boxes to show some data on hover. So, when we move mouse over one element, it should expand, get in front of other elements, and show the hidden data.
I did something like this:
box:hover {
z-index: 50;
}
But there's one problem; When we move mouse on another outer white space, the z-index back to the value, same as others. So it's visible that hovered element is in lower layer than next one.
How to prevent a property to apply, until the end of transition?
Here's my jsFiddle. Try to hover on one element, move your mouse out of element and the background-image of other elements will be in front of our hovered element before the transition ends.
Update: this is the screen shot of problem. This is when we unhover on element. background-image of another elements come in front of our hovered element.
Add a transition also for z-index, but insert a delay only when .box is in normal state.
Doing so the z-index will change istantly on hover, while on the opposite action (“unhover”) the z-index will take its initial value but only after 0.5 seconds (the duration of your expanding effect is 0.4 seconds)
.box {
...
z-index: 1;
-webkit-transition: z-index 0s .5s;
-moz-transition: z-index 0s .5s;
transition: z-index 0s .5s;
}
.box:hover {
-webkit-transition: z-index 0s 0s;
-moz-transition: z-index 0s 0s;
transition: z-index 0s 0s;
z-index: 50;
}
example: http://jsfiddle.net/yjg2oach/
Add a transition attribute to your .box group.
.box {
float: left;
position: relative;
width: 100px;
height: 100px;
margin: 10px;
margin-bottom: 35px;
transition: .4s;
}
Fixed fiddle

Disable hover effect in pure css

First stackoverflow post, so please forgive if I'm missing something obvious. I did search for an answer first but didn't find one I recognized as relevant.
In this jsfiddle, I have a div that I'm using as a hover target to get some transitions to happen to an <a> element.
http://jsfiddle.net/ramatsu/Q9rfg/
Here's the markup:
<div class="target">Target
<p>.LightMe</p>
</div>
And the css:
body {
background-color: #099;
height: 100%;
width: 100%;
margin-top:200px;
}
.target{
position: absolute;
left: 40%;
height: 100px;
width: 200px;
padding: 20px;
background-color: #ccc;
cursor: pointer;
}
a {
display: block;
position: relative;
padding: 1px;
border-radius: 15%;
}
a.LightMe {
/*Starting state */
background-color: white;
border-style:solid;
border-color:#fff;
top: -120px;
left: -200px;
height: 80px;
width: 80px;
z-index: 10;
opacity: 0;
transition:left 0.55s ease, opacity .5s .7s ease;
-webkit-transition:left 0.55s ease, opacity .5s .7s ease;
-o-transition:left 0.55s ease, opacity .5s .7s ease;
}
.target:hover a.LightMe {
/*Ending state*/
left: 80px;
opacity: 1;
transition:left 0.55s .7s ease, opacity .5s ease;
-webkit-transition:left 0.55s .7s ease, opacity .5s ease;
-o-transition:left 0.55s .7s ease, opacity .5s ease;
}
.target:hover {
transition: background-color 500ms ease;
-webkit-background-color 500ms ease;
-o-background-color 500ms ease;
background-color:#999;
}
Hover over the grey box labeled Target and back off again to see the transitions on the <a> element. It's doing what I want: opacity fades in during position delay, then it slides to the desired position. when moving out of the hover target, the <a> slides to it's original position, then opacity fades back out. All good so far.
The catch is, if the user hovers over the hidden <a> element, it triggers the same set of transitions, which causes all kinds of unintended havoc.
I'd like to prevent any response to a hover directly over the <a> element, and really like to continue to keep it in css if possible.
I tried adding an explicit hover to <a> and .LightMe to override this, to no avail. (Though that could be that I just didn't get the selector syntax right.)
I added the background-color transition to .target intentionally for testing, and it provided an interesting clue: hovering over the <a> triggers the upstream transitions of the .target div. That's about where my brain broke and I decided I'd better seek help.
I'm working with a few things here that are above my head, I just started from the closest thing I could find and worked toward what I needed. This was the starting point jsfiddle (with thanks to the author):
You can start your 'top' position outside of the viewer port and delay the 'top' transition until after your 'left' transition is over. That way the <a> element will not be clickable until the left transition start.
See: http://jsfiddle.net/Q9rfg/4/
Or you can also use this method, combined with the sibling selector as suggested by aorcsik.
Update: another hacky solution is to place a div which is outside, the hover sensitive element, that covers the moving link. Check it out: http://jsfiddle.net/aorcsik/Q9rfg/2/
The problem with my original idea (below) was, that you could not click on the moving link, since it returned to its original position, once you hovered out of the gray box, also the cursor changed over the hidden link.
I would try to get the <a> out of the gray box, put it after, and reference it in css with the sibling selector +.
.mainclass.subclass:hover + a.LightMe {
/* ... */
}
This way it won't trigger the hover effect of the gray box when itself is hovered, and you stay in pure css land.
This would make positioning a bit trickier, here is a fiddle, check it out: http://jsfiddle.net/aorcsik/Q9rfg/1/

Resources