i'm trying to apply a minimize/maximize effect to a div through keyframes and animations in css. While the plain, non-animated, effect is by itself pretty simple (i've already added it), the need for a starting point (from{...}) for keyframes is driving me mad! I've already tried with an empty from property, whitout it and with a dummy, non-related attribute (like opacity: 1, where opacity is not needed) or with auto values for needed properties, but so far i had no luck. So my question is, is there a way to set a keyframes so it starts from div's current properties values? To be more specific, can i have a div's width and height expanded to a given size starting from it's CURRENT, generic, width and height?
My code so far (effect related code):
#-webkit-keyframes maxWin{
from
{
/* width: auto; or width: ; or nothing at all */
/* height: auto; or height: ; or nothing at all */
/* left: auto; or left: ; or nothing at all */
/* top: auto; or top: ; ...you know. */
}
to
{
width: 100% !important;
height: 100% !important;
left: 0px !important;
top: 0px !important;
}
}
#-webkit-keyframes minWin
{
from
{
/*width: auto; or width: ;*/
/*height: auto; or height: ;*/
}
to
{
width: 200px !important;
height: 30px !important;
}
}
....
.maximized
{
/*width: 100% !important;
height: 100% !important;
left: 0px !important;
top: 0px !important;*/ Plain maximize effect. Works.
-webkit-animation: maxWin 1s normal forwards !important;
animation: maxWin 1s normal forwards !important;
}
.minimized
{
/*width: 200px !important;
height: 30px !important;*/ Plain minimize effect. Also works.
-webkit-animation: minWin 1s normal forwards !important;
animation: minWin 1s normal forwards !important;
}
If you are simply concerned about setting the end state relative to the present state of an element, You want a transition not an animation.
Transitions allow you to set the desired outcome and keyframes are then extrapolated automatically from the current state of the element.
e.g. in the below- applying the .minimized class to .window would reduce its size with only the endpoints specified.
.window{
transition: all 250ms ease-in;
width: 100%;
height: 100%;
}
.minimized{
width: 200px !important;
height: 30px !important;
}
If anyone has do that for some reason, simply leave the from {} part and only specify the to {}
#keyframes addright{
/* from{width:0;} */
to {width: var(--small-width);}
}
Take a look at the Web Animations API. You can use it to directly manipulate the browser's CSS animation engine and directly call CSS animations on elements with JavaScript. Just like CSS animations, you specify a set of keyframes for the animation engine to interpolate.
The benefit is, as it is JavaScript, you can get the current CSS (property: value) pair/s from the element you want to animate and pass them into the first keyframe. That way your animation would always take the elements current CSS styling as the starting point for your animation.
Easiest thing to do is, if you have added margins or top remove it and use
'transform'. It will animate it according to the starting positions of it.
ex:
#keyframes move_right
0% {
transform: translatex(16px);
}
100% {
transform: translatex(160px);
}
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've made a slideshow that works by putting three inline blocks next to each other (all with the same background-image) within a slideshow container, and using translateX to move that container 33% of the way to the left/right, before looping. The three inline blocks pretty much ensures it will always look continuous and you never see a seam at the each of your screen.
The slideshow is placed into another container of its own, typical width, and overflow: hidden is used to crop the long photo strip and prevent it from stretching your browser window.
#container {
width: 100%;
height: 200px;
overflow: hidden;
position: relative;
}
.slideshow {
position: absolute;
z-index: 5;
top: 0;
width: auto;
height: 100%;
overflow: hidden;
white-space: nowrap;
}
.slide {
display: inline-block;
height: 100%;
}
#about-slideshow {
right: 0;
-webkit-animation: slideshow-right 10s linear infinite;
animation: slideshow-right 10s linear infinite;
}
#about-slideshow .slide {
width: 964px;
background: url('http://simplegrid.cochranesupply.com/images/slideshow-a.jpg') 0 0 repeat-x;
background-size: 101%;
}
/* the animation */
#-webkit-keyframes slideshow-right {
from {
-webkit-transform: translateX(0);
}
to {
-webkit-transform: translateX(33.33333333333%);
}
}
#keyframes slideshow-right {
from {
transform: translateX(0);
}
to {
transform: translateX(33.33333333333%);
}
}
My problem: After looking at it thoroughly on an iPhone 5S and iPhone 6 Plus, it seems to not start sometimes. It'll just sit there. Maybe glitch out after a while. If I continue to refresh, it will sometimes run, and sometimes not. Seems completely inconsistent.
Any ideas on what could be causing this? Seems pretty simple.
Here's a CodePen that I've confirmed displays the issue on iOS Safari: http://codepen.io/arickle/pen/pvGJBM
Here's a full screen view to pull up on an iOS device for testing (remember, keep refreshing until it stops--you don't have to refresh particularly fast or anything): http://codepen.io/arickle/full/pvGJBM/
Well, I appear to have stumbled upon a workaround at least. Apparently, if mobile Safari hiccups on anything during load, or can't keep up, or something, it won't start the animation. My solution was simply to delay the animation by 0.1s. This gives the browser enough time to get everything loaded and then start the animation, every time.
-webkit-animation: slideshow-right 10s 0.1s linear infinite;
Silly.
I'm trying to make an infinite horizontal slider with 3 rows of images.
It looks like this:
But as you see when the end of the rows of images arrive, there's a huge blank space while the image finally appears again.
You can test it live here: http://jsfiddle.net/tbergeron/q596y/6/
Here's the CSS behind it:
ul.lists {
position: absolute;
left: 0;
top: 0;
white-space: nowrap;
-webkit-animation: moveSlideshow 180s linear infinite;
-moz-animation: moveSlideshow 180s linear infinite;
}
ul.lists li {
list-style: none;
display: inline-block;
}
ul.lists li img {
display: inline-block;
width: 100px;
height: 100px;
}
ul.slider2 {
top: 140px;
}
ul.slider3 {
top: 280px;
}
#-webkit-keyframes moveSlideshow {
0% {
-webkit-transform: translateX(0);
}
100% {
-webkit-transform: translateX(-300%);
}
}
#-moz-keyframes moveSlideshow {
0% {
-moz-transform: translateX(0);
}
100% {
-moz-transform: translateX(-300%);
}
}
What I'd like to happen is to never see that blank space, I would like it to roll on forever. Anyone has an idea on how to achieve this behavior?
Thanks and have a nice day.
basicly , You need to clone your elements.
At least many enough of the first ones to fill the entire width of the screen, or split into two differents tags, your elements.
So once a part of them, is gone left, you move them back to the right end to fill that empty space to keep scrolling without any gaps.
Your case requires javascript.
So many images wrapping line by line needs to clone the whole ul.
A good compromise could be to split content within two ul, so one can to next once of screen.
To duplicate the whole ul in the HTML document might not be a good idea and i would not advise to do so for text.
jQuery DEMO of your fiddle.
$(".lists.slider1").clone().appendTo("body");
$(".lists.slider2").clone().appendTo("body");
$(".lists.slider3").clone().appendTo("body");
But for small "marquee like" , you can use pseudo elements to clone the first few images.
For text of a known length(em) or known container's width , you may use text-shadow.
Pseudo and text-shadow avoid duplication of content.
Some horrible CSS example that demonstrate the cloning idea: http://dabblet.com/gist/5656795
I am using marquee scroll from right side to the left. The below code works fine. But its not scrolling smoothly. The content "Hover on me to stop" is blinking or flashing. I need a 100% smooth scroll for the below marquee. Please help me. Whether it is possible without javascript??
<marquee behavior='scroll' direction='left' scrollamount='3' onmouseover='this.stop()' onmouseout='this.start()'>Hover on me to stop</marquee>
If you wish to try it using pure CSS then this is the easiest approach. Though you need to check the support for older browsers and do add vendor prefixes.
.marquee-parent {
position: relative;
width: 100%;
overflow: hidden;
height: 30px;
}
.marquee-child {
display: block;
width: 147px;
/* width of your text div */
height: 30px;
/* height of your text div */
position: absolute;
animation: marquee 5s linear infinite; /* change 5s value to your desired speed */
}
.marquee-child:hover {
animation-play-state: paused;
cursor: pointer;
}
#keyframes marquee {
0% {
left: 100%;
}
100% {
left: -147px /* same as your text width */
}
}
<div class="marquee-parent">
<div class="marquee-child">
Hover on me to stop
</div>
</div>
A little late to the party..
There's an angular directive for this: https://github.com/davidtran/angular-marquee. You don't touch any js - just add the directive tag and you're done
<div angular-marquee></div>
And it doesn't fall back on the "deprecated tag" argument, relying on modern solution
Is it possible to animate the transition between the open/close state of the <details> element with just CSS?
No, not currently. Yes, but only if you know the height or can animate the font-size.
Originally, this wasn't the case. From http://html5doctor.com/the-details-and-summary-elements/, "...if you could use CSS transitions to animate the opening and closing, but we can’t just yet." (There is a comment at HTML5 doctor near the end, but it appears to require JS to force the CSS animation.)
It was possible to use different styles based on whether it's opened or closed, but transitions didn't "take" normally. Today, however, the transitions do work if you know the height or can animate the font-size. See http://codepen.io/morewry/pen/gbJvy for examples and more details.
This was the 2013 solution that kind of fakes it:
CSS (May need to add prefixes)
/* http://daneden.me/animate/ */
#keyframes fadeInDown {
0% {
opacity: 0;
transform: translateY(-1.25em);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.details-animated[open] {
animation-name: fadeInDown;
animation-duration: 0.5s;
}
HTML
<details class="details-animated">
<summary>CSS Animation - Summary</summary>
Try using [Dan Eden's fadeInDown][1] to maybe fake it a little. Yay, some animation.
</details>
This works today:
CSS (May need to add prefixes)
.details-animated {
transition: height 1s ease;
}
.details-animated:not([open]) { height: 1.25em; }
.details-animated[open] { height: 3.75em; }
PS: Only tested in Chrome. Hear FF still doesn't support details in general. IE and Edge prior to version 79 still don't support details.
(You can use keyframe animations or transitions to do all sorts of other animations for open. I've chosen fadeInDown for illustration purposes only. It is a reasonable choice which will give a similar feel if you are unable to add extra markup or will not know the height of the contents. Your options are, however, not limited to this: see the comments on this answer that include two alternatives, including the font-size approach.)
My short answer is : you can not transition between summary and the rest of the details content.
BUT!
You can do some nice transition inside the summary between the selector details and details[open]
details{
position: relative;
width: 100px;height: 100px;
perspective: 1000px;
}
div{
position: absolute;
top: 20px;
width: 100px;height: 100px;
background: black;
}
details .transition{
transition: 1s linear;
transform-origin: right top;
;
}
details[open] .transition{
transform: rotateY(180deg);
background: orangered;
}
<details>
<summary>
<div></div>
<div class="transition"></div>
</summary>
</details>
NB : I answer this because it was the first result from googling on this!
Given the height has to snap at some point I prefer to start to animate the height and then snap. If your lucky enough to have all the elements a similar height this solution can be quite effective. (you do need a div inside your details elements though)
#keyframes slideDown {
0% {
opacity: 0;
height: 0;
}
100% {
opacity: 1;
height: 20px; /* height of your smallest content, e.g. one line */
}
}
details {
max-width:400px;
}
details[open]>div {
animation-name: slideDown;
animation-duration: 200ms;
animation-timing-function:ease-in;
overflow:hidden;
}
see http://dabblet.com/gist/5866920 for example
Of course it's possible:
DETAILS[open] SUMMARY ~ * {
animation: sweep 3s ease-in-out;
}
#keyframes sweep {
0% {
opacity: 0;
margin-left: -10px
}
100% {
opacity: 1;
margin-left: 0px
}
}
<details>
<summary>Summary content</summary>
Test test test test.
</details>