With the CSS3 transition-delay Property I can delay the opacity, color etc.
But how can I delay things like the position with pure css ?
.element{
position: absolute;
visibility: hidden;
}
// Delay with 1s
.demo--active .element{
position: relative;
visibility: visible;
float: left;
width: 33%;
}
If you want to actually animate between the position values eg: from static to absolute- then you can't! - because position is not an animatable property.
From MDN:
Animatable no
However if you just want to delay the change between the values - this can be done with the animation-delay and animation-fill-mode properties:
Here's a demo
.wpr {
position: relative;
}
.wpr div {
width: 100px;
height: 100px;
background: green;
margin: 10px;
}
.wpr div:nth-child(3) {
animation: test 2s;
animation-delay: 3s;
animation-fill-mode: forwards;
}
#keyframes test {
from {
position: static;
top: auto;
background: green;
}
to {
position: absolute;
top: 0;
background: red;
}
}
<div class="wpr">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
Notice (from the above demo) that:
1) there's a 3s delay for the 3rd div to change to position:absolute
2) With animation-fill-mode: forwards; we can ensure that the animated block will retain the computed values set by the last keyframe.
Related
I am aware that !important is not recommended, and the few known use cases where it is appropriate includes when working with third party libraries such as Bootstrap. However, i would like to ask if this use case is appropriate too. Suppose i have a <div/> which i would want to animate from background-color transparent to a certain color. However, i would like to have a color change on hover too after the animation happens, but i can't seem to find a way to do it without using the !important rule. Thanks in advance!
div{
position: absolute;
width: 100px;
height: 100px;
animation: animate 4s forwards;
}
div:hover{
background-color: blue !important;
}
#keyframes animate{
from {
background-color: transparent;
}
to {
background-color: maroon;
}
}
Not judging if it would be an appropriate use of !important here or not, one way around in your case would be to split your animation and transition on two different elements. Note that it's quite common to do so when you want to animate and transition the same properties.
background-color even has the advantage that you can use pseudo-elements instead of a plain one.
Less talk, more code:
div{
position: absolute;
width: 100px;
height: 100px;
animation: animate 4s forwards;
}
div::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: background-color 2s;
}
div:hover::after{
background-color: blue;
}
#keyframes animate{
from {
background-color: transparent;
}
to {
background-color: maroon;
}
}
<div></div>
What I prefer to do is unsetting the property beforehand I want to customise with the bootstrap, say I want to change button's default blue colour to red, I do it using,
background-color: unset;
background-color: #ff000;
Keep in mind, the order of code matters here by a lot
Do the animation differently and don't rely on forwards
div {
position: absolute;
width: 100px;
height: 100px;
animation: animate 4s;
background-color: maroon;
transition: background-color 2s;
}
div:hover {
background-color: blue;
}
#keyframes animate {
from {
background-color: transparent;
}
}
<div></div>
I have spend hours trying to find a solution that just requires css to work. I am trying to animate a div when it is hoverd, that its height and width be reduced uniformly.
<div class="a"></div>
Above is a simple div element with the following css:
.a {
width: 350px;
height: 350px;
background: #000;
margin: 100px 0 0 400px;
transition: all 2s linear;
position:fixed;
}
I want to reduce the height and width of the element on hover from the center using just css.
Use scale transformation:
.a {
width: 350px;
height: 350px;
background: #000;
margin: 10px;
transition: all 2s linear;
position: fixed;
}
.a:hover {
transform:scale(0.5);
}
<div class="a"></div>
The function you are looking for is scale()
As per your requirement, ideally what you would want to do is to fire the scale() function on hover of the target element as:
.a {
width: 350px;
height: 350px;
background: #000;
margin: 10px;
transition: all 2s linear;
position: fixed;
}
.a:hover {
transform:scale(0.7);
}
This css function will zoom the div element with respect to its center. See this for a complete reference.
Use the :hover pseudoclass.
.a:hover {
width: 300px;
height: 300px;
}
The transition on .a will apply as expected.
I have a container of variable height, and would like to put an element at the middle of it. So I've set these styles:
#parent {
position: relative;
}
#child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
Which work in most cases. However, the container's height is not only variable, but it also changes constantly.
Because of this, that code won't work. An example:
#keyframes changeSize {
0% {
height: 100px;
}
50% {
height: 150px;
}
100% {
height: 100px;
}
}
#parent {
position: relative;
width: 400px;
height: 300px;
background: red;
animation-name: changeSize;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
}
#child {
position: absolute;
margin-block-start: 0;
margin-block-end: 0;
right: 0;
top: 50%;
transform: translateY(-50%);
}
<div id="parent">
<p id="child">I should not be moving...</p>
</div>
As you can see, it's moving. So, my question is, is there a way to place it in the middle of the element (vertically) but without having it move if the container changes size - just with CSS?
The issue is that percentage measure units are relative to the containing element. Since the #parent is changing in height through the animation, the value of a percentage unit changes. The unit change affects the percentage height property applied to the #child. The work-around might be some very complicated CSS (might not work in every situation) so the best solution is to use JavaScript to capture the initial 50% height in pixels so the unit no longer changes. It is important to also use a resize event listener to apply a new 50% height should the browser window be resized.
window.addEventListener('load',resizeDiv());
window.addEventListener('resize',resizeDiv());
function resizeDiv(){
var initialHeight = document.getElementById('parent').offsetHeight/2;
document.getElementById('child').style.top = initialHeight+'px';
}
#keyframes changeSize {
0% {
height: 100px;
}
50% {
height: 150px;
}
100% {
height: 100px;
}
}
#parent {
position: relative;
width: 400px;
height: 300px;
background: red;
animation-name: changeSize;
animation-duration: 2s;
animation-iteration-count: infinite;
animation-timing-function: ease-in-out;
}
#child {
position: absolute;
margin-block-start: 0;
margin-block-end: 0;
right: 0;
}
<div id="parent">
<p id="child">Hey!! I'm not moving anymore!</p>
</div>
Please help me to resolve animation issue, here is a link and code:
https://fiddle.jshell.net/gvopk1qe/37/
Description of issue:
This 'train' is infinity but after once the yellow rectange is covered by blue rectangle. You see yellow, black, red, blue rectangle and then should be yellow again, black, red and blue but yellow is covered by blue.
Please help me to resolve this.
Thanks.
Exact problem : animation-delay property is used. It will delay by assigned time before starting animation each time. Therefore, first cycle is good but second cycle onward everything breaks.
Suggested Fix
I would say don't use animation-delay property instead arrange the div's so that they are next to each other and then animate them.
Example Snippet:
/* steps animation */
.steps-animation {
position: relative;
width: 1200px;
height: 250px;
float: left;
background: lightgrey;
border: 1px solid black;
overflow: hidden;
}
.steps-animation span {
display: inline-block;
position: relative;
top: 32%;
left: -100%;
width: 160px;
height: 80px;
margin-left: 100px;
-webkit-animation: stepmoveone 6s linear infinite;
animation: stepmoveone 6s linear infinite;
}
.steps-animation .step1 {
background: yellow;
}
.steps-animation .step2 {
background: black;
}
.steps-animation .step3 {
background: red;
}
.steps-animation .step4 {
background: blue;
}
#keyframes stepmoveone {
to {
left: 100%;
}
}
<div class="steps-animation">
<span class="step1"></span>
<span class="step2"></span>
<span class="step3"></span>
<span class="step4"></span>
</div>
**Need to edit margin-left, height and width as per requirement.
The problem is in timming. I haven't worked too much with animations but I think I know what's the problem. The animation has a loop set on this line
animation: stepmoveone Xs linear infinite;
This will initially wait X seconds but will also show the animation in an X seconds interval. So it will take X seconds for the animation to complete.
In your code you set X to 18 seconds but this is the same time the last div (the blue one) will wait to be animated. So it will be animated exactly when a new cycle of the animation begins. But when this happens the yellow div will show up so the two of them will overlap. You can check this by changing the delay time for the yellow div to 1s.
To fix this you can change the animation time to 24 for example.
Here's the code but with the seconds changed:
/* steps animation */
.steps-animation {
position: relative;
width: 800px;
height: 250px;
float: left;
background: lightgrey;
border: 1px solid black;
overflow: hidden;
}
.steps-animation span {
display: block;
position: absolute;
top: 32%;
left: -100%;
width: 160px;
height: 80px;
-webkit-animation: stepmoveone 8s linear infinite;
animation: stepmoveone 8s linear infinite;
}
.steps-animation .step1 {
animation-delay: 0s;
background: yellow;
}
.steps-animation .step2 {
animation-delay: 2s;
background: black;
}
.steps-animation .step3 {
animation-delay: 4s;
background: red;
}
.steps-animation .step4 {
animation-delay: 6s;
background: blue;
}
#keyframes stepmoveone {
to {
left: 100%;
}
}
<div class="steps-animation">
<span class="step1"></span>
<span class="step2"></span>
<span class="step3"></span>
<span class="step4"></span>
</div>
This code will leave a 2 seconds gap between each element.
Set .steps-animation width to 100% && .steps-animation span to negative of its width to hide from the frame
Check the fiddle
I have 2 divs positioned horizontally next to each other inside a container. I want each div to expand width on hover to the full width of the container.
The problem is that after the transition when the pointer is no longer hovering the left div (which is first in the html flow) is overlapped under the right div.
Here's an example.
To recreate just place the pointer on the left div until the transition is finished, then take the pointer off the div.
The desired effect is that the width will decrease gradually (just like the right div).
* { margin: 0; padding: 0; }
#wrap { position: relative; width: 500px; margin: 0 auto; }
#one, #two { height: 100px; position: absolute; transition: width 1s ease-out; }
#one { width: 300px; background: #49d7b0; }
#two { right: 0; width: 200px; background: #d8c800; }
#one:hover, #two:hover { width: 500px; z-index: 1; }
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="z-index.css">
</head>
<body>
<div id="wrap">
<div id="one"></div>
<div id="two"></div>
</div>
</body>
</html>
animation can do the trick here. Actually z-index cause the issue here. You can solve following way.
* { margin: 0; padding: 0; }
#wrap { position: relative; width: 500px; margin: 0 auto; }
#one, #two { height: 100px; position: absolute; transition: width 1s ease-out; }
#one { width: 300px; background: #49d7b0; animation: movedec 1s; }
#two { right: 0; width: 200px; background: #d8c800; }
#one:hover { animation: moveinc 1s forwards; -webkit-animation: moveinc 1s forwards; }
#two:hover { width: 500px; }
#keyframes moveinc {
from {width: 300px; z-index: 1;}
to {width: 500px; z-index: 1;}
}
#keyframes movedec {
from {width: 500px; z-index: 1;}
to {width: 300px; z-index: 1;}
}
#-webkit-keyframes moveinc {
from {width: 300px; z-index: 1;}
to {width: 500px; z-index: 1;}
}
#-webkit-keyframes movedec {
from {width: 500px; z-index: 1;}
to {width: 300px; z-index: 1;}
}
<div id="wrap">
<div id="one"></div>
<div id="two"></div>
</div>
Set the z-index with more difference between the un-hovered and the hovered state (for instance, go from 1 to 10).
Add transition on the z-index also ... But only when going back to the default state.
This way, when you change the hover from one element to the other, the newly hovered element will have immediately the high z-index, while the un-hovered is slowly dreasing it. And the newly hovered element will be in front.
Demo: (with the key styles in first place)
#one:hover,
#two:hover {
width: 500px;
z-index: 10;
transition: width 1s ease-out, z-index 0s linear;
}
#one,
#two {
z-index: 1;
transition: width 1s ease-out, z-index 1s linear;
}
* {
margin: 0;
padding: 0;
}
#wrap {
position: relative;
width: 500px;
margin: 0 auto;
}
#one,
#two {
height: 100px;
position: absolute;
}
#one {
width: 300px;
background: #49d7b0;
}
#two {
right: 0;
width: 200px;
background: #d8c800;
}
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" type="text/css" href="z-index.css">
</head>
<body>
<div id="wrap">
<div id="one"></div>
<div id="two"></div>
</div>
</body>
</html>
This isn't really a problem, just the way overflows have to work. You have 2 options:
1) Use CSS keyframe animations - that way, you can give the hovered div a higher z-index, and have the reverse animation keep the z-index higher (dropping it back to a lower index at the very end of the animation).
2) use javascript/jquery (if you want this to work well on all devices/browsers, I would recommend Jquery anyway, which gives support to older browsers like IE8 that don't support css3)