Defining keyframe animations inside media queries - css

I'm trying to get objects to "slide in" from the bottom of the screen, but since I can't get the screen height as a unit in CSS, I'm trying to do this with media queries, like so:
#media(max-height:500px) {
#keyframe slideUp {
0% { transform: translate3d(0,500px,0); }
100% { transform: translate3d(0,0,0); }
}
}
#media(max-height:750px) {
#keyframe slideUp {
0% { transform: translate3d(0,750px,0); }
100% { transform: translate3d(0,0,0); }
}
}
/* etc. */
This doesn't work (it uses the first version of slideUp regardless of height), so I assume keyframes, once defined, cannot be overwritten or reassigned based on media queries? Is there any way to achieve this effect (short of having many different keyframe setups and using a media query to assign the appropriate one to the class)?

I don't know why no one else has suggested this, but instead of setting the keyframes in the media query you can set the animation in the media query.
#media(max-height:500px)
{
#selectorGroup {
animation: slideUp500 1s forwards;
}
}
#media(max-height:750px)
{
#selectorGroup {
animation: slideUp750 1s forwards;
}
}
#keyframes slideUp500 {
0% { transform: translate3d(0,500px,0); }
100% { transform: translate3d(0,0,0); }
}
#keyframes slideUp750 {
0% { transform: translate3d(0,750px,0); }
100% { transform: translate3d(0,0,0); }
}

Nowadays you can solve this using native CSS variables.
In your case:
#media(max-height:500px) {
:root {
--slide-up-y: 500px
}
}
#media(max-height:750px) {
:root {
--slide-up-y: 750px
}
}
#keyframes slideUp {
0% { transform: translate3d(0,var(--slide-up-y),0); }
100% { transform: translate3d(0,0,0); }
}
}

A way of doing a slide up animation regardless of screen or element height is to use position: fixed:
.box {
position: fixed;
animation: slideUp 1s forwards;
}
#keyframes slideUp {
from { top: 100%; }
to { top: 0; }
}
Demo: http://jsfiddle.net/myajouri/Kvtd2/
If you want to slide relative to a parent element and not the viewport, use position: absolute instead.

Long time since this question was asked. But I'm seeing that nobody has answered the solution that I'll give you, and this one, in my opinion, is easier than creating different media-queries for different screen sizes.
#myajouri proposed you to use a fixed position and you discarded this solution because you need to use 3d transforms to get hardware acceleration. But you can still use 3d transforms with a fixed position. With CSS transformations, if you use percentages, they will be relative to the size of the element itself. This will allow you to move the element from outside the screen no matter what size it has, so, only one keyframe animation is needed. Check the next snippet:
body {
margin: 0;
padding: 0;
}
.element {
animation: slideUp 1s ease-in-out infinite alternate;
background: #CCC;
border: 5px solid gray;
box-sizing: border-box;
height: 100%;
position: fixed;
width: 100%;
}
#keyframes slideUp {
from {
transform: translate3d(0, 100%, 0);
}
to {
transform: translate3d(0, 0, 0);
}
}
<div class="element" />

If you have to use translate3d to get hardware acceleration on mobile devices (as you mentioned), and given that you can't use at-rules inside #media:
You could define one #keyframes with large translateX (say 5000px) and change the animation-duration based on the screen height to ensure the speed is more or less the same across the different heights.
I would also define height ranges (max-height and min-height) as opposed to upper limits (max-height only) to prevent unwanted style overrides.
#keyframes slideUp {
from { transform: translate3d(0,5000px,0); }
to { transform: translate3d(0,0,0); }
}
.box { animation: slideUp 5s forwards; }
#media (min-height: 0) and (max-height: 500px) {
.box { animation-duration: 0.5s; }
}
#media (min-height: 501px) and (max-height: 750px) {
.box { animation-duration: 0.75s; }
}
#media (min-height: 751px) and (max-height: 1000px) {
.box { animation-duration: 1s; }
}
DEMO: http://jsfiddle.net/myajouri/9xLyf/

Related

CSS #keyframes translate3d Compatibility

How do I specifically check for compatibility of #keyframes translate3d animations with the browser ?
Please Don't close this question since I've tried many stackoverflow solutions before asking this question.
I want to check whether the browser my webpage runs is compatible for running animations, since many android browsers(Old Ones) are not capable of running them, they just stop displaying output text when animation fails (In MY Case). So, I would like to either stop animations or redirect them to another copy of my same website without any animations :)
P.S I've also tried using #supports, but of no use :(
h1,h2{
height: 40px;
animation: an 1s ease-out 1 both;
}
#keyframes an {
from {
opacity: 0;
transform: perspective(500px) translate3d(-35px, -40px, -150px) rotate3d(1, -1, 0, 35deg);
}
to {
opacity: 1;
transform: perspective(500px) translate3d(0, 0, 0);
}
}
<h1 id="h1" class="th">Test Texts</h1>
<h2 id="h2" class="th">Also Test Texts..</div>
#supports query works just fine. It has to be at top level of the code. You also need to provide some dummy values for the translate3d.
#supports(transform: translate3d(100px,100px,10px)){
div{
background: blue;
}
}
#supports not (transform: translate3d(100px,100px,10px)){
div{
background: red;
}
}
div{
width: 250px;
height: 250px;
)
<div></div>
For browsers with no support for #supports query, you can add default value/property to the element. You also need to add !important to values of properties inside of #supports to override the default value.
This should work on all browsers.
#supports(transform: translate3d(100px,100px,10px)){
div{
background: blue !important;
}
}
#supports not (transform: translate3d(100px,100px,10px)){
div{
background: red !important;
}
}
div{
width: 250px;
height: 250px;
background: red; /* default value */
)
<div></div>
Applying this to your snippet, you get this:
#supports(transform: translate3d(100px, 100px, 10px)) {
h1,
h2 {
animation: an 1s ease-out 1 both !important;
}
#keyframes an {
from {
opacity: 0;
transform: perspective(500px) translate3d(-35px, -40px, -150px) rotate3d(1, -1, 0, 35deg);
}
to {
opacity: 1;
transform: perspective(500px) translate3d(0, 0, 0);
}
}
}
#supports not (transform: translate3d(100px, 100px, 10px)) {
h1,
h2 {
animation: an 1s ease-out 1 both !important;
/*you can also set it to efault animation */
}
#keyframes an {
/* some different animation */
}
}
h1,
h2 {
height: 40px;
animation: defaultA 1s ease-out 1 both;
}
#keyframes defaultA {
/* some default animation */
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<h1 id="h1" class="th">Test Texts</h1>
<h2 id="h2" class="th">Also Test Texts..</h2>
Check with media query:
#media all and (-webkit-transform-3d) {
css animation when supported
};
Check with #supports:
#supports (transform: translate3d) {
}
or
#supports not (transform: translate3d) {
}
or you can check out this javascript solution
https://gist.github.com/lorenzopolidori/3794226

CSS animations - initialise animation at last frame

I'm doing some CSS animations inside a modal dialog. Here's the pertinent SCSS:
#keyframes grow {
from {
transform: scale(1);
}
to {
transform: scale(1.1);
}
}
#keyframes shrink {
from {
transform: scale(1.1);
}
to {
transform: scale(1);
}
}
$duration: 0.5s;
$animationFillMode: both;
&:not(.active):hover, &.active {
img {
animation: grow $duration $animationFillMode;
}
}
&:not(.active) {
img {
animation: shrink $duration $animationFillMode;
}
}
This works well but the problem is, when I open the modal, the animations kick in immediately. For example, because when the modal is first open I'm not hovering on one of the elements, the element instantly shrinks from big to small. I want the element to start in the small state when the modal is open.
Is is possible? TIA
Yes it is, use reverse tag.
Example: animation-direction: reverse;

Disable css animation on orientation change

So I made two animations for tablet using css animation and media query.
The main thing animation does is animate the div from top to center in tablet portrait and from left to center in tablet landscape.
When the page loads in portrait it animates correctly from top to center. But when the orientation is changed to landscape it starts the second animation from left to center. The same if it is in landscape first.
What I want is to animation to run only once on page load, and not trigger every time orientation changes.
Preferably without javascript, only css.
Here is a bit of code of how it works:
#keyframes leftToCenter {
from {
margin-left: -100vw;
}
to {
margin-left: 0;
}
}
#keyframes topToCenter {
from {
margin-top: -100vh;
}
to {
margin-top: 0;
}
}
#media only screen and (orientation: portrait) {
.div {
animation-name: topToCenter;
animation-duration: 1s;
}
}
#media only screen and (orientation: landscape) {
.div {
animation-name: leftToCenter;
animation-duration: 1s;
}
}
Edit:
The animation must not be done with jQuery, it should be done only with css animation. This is the requirement.
Also, the animation is a bit more complicated, I just put the simplest version of it here.
The main thing is that it runs only on page load, and not on orientation change.
The only way that I can think of to do that in pure CSS involves the use of a single animation.
This way the browser asumes the animation has finished, and won't trigger it again.
In one orientation, we will use half of the animation, beginning at the middle, and ending at the end.
In the other orientation, we will begin also at the middle, but we will execute it in reverse and end at he beginning
#keyframes dual {
from {
margin-left: 0;
}
49.9% {
margin-left: -100vw;
margin-top: 0;
}
50% {
margin-left: 0;
margin-top: -100vh;
}
to {
margin-top: 0;
}
}
#media only screen and (orientation: portrait) {
.element {
animation-name: dual;
animation-duration: 2s;
animation-delay: -1s;
}
}
#media only screen and (orientation: landscape) {
.element {
animation-name: dual;
animation-duration: 2s;
animation-delay: -1s;
animation-direction: reverse;
}
}
.element {
width: 100px;
height: 100px;
background-color: lightblue;
}
<div class="element"></div>
In case anyone's interested, I found another solution to this problem.
You have to move the keyframes declaration inside the media query and give them the same name. That way the right animation still gets triggered when needed, and as they have the same name animation count will increese to 1 after first animation and won't trigger again after orientation change.
#media only screen and (orientation: portrait) {
#keyframes animation{
from {
margin-top: -100vh;
}
to {
margin-top: 0;
}
}
.div {
animation-name: animation;
animation-duration: 1s;
}
}
#media only screen and (orientation: landscape) {
#keyframes animation{
from {
margin-left: -100vw;
}
to {
margin-left: 0;
}
}
.div {
animation-name: animation;
animation-duration: 1s;
}
}
There is probably a CSS way to do it but it is very easy to create your effect using jQuery:
$(document).ready( function(){
$('#yourdiv').show().animate({top:'50%'},1000);
});
Just set #yourdiv's style this way in order to center it when position is absolute:
display: none;
position: absolute;
z-index: 100000; /* on top of all others element */
top: -50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
The effect will occur only when thee page is refreshed.
You can even add an other div called shadow to make it even better looking :)

How do I reverse this CSS rotate animation?

I have this CSS animation which I'm trying to reverse the animation of based on a class being added to a DOM node. I've tried multiple things but with no avail. Here is the code I'm using, see below:
EXAMPLE
// Closed state
#-moz-keyframes spin-close { 100% { -moz-transform: rotate(-0deg); } }
#-webkit-keyframes spin-close { 100% { -webkit-transform: rotate(-0deg); } }
#keyframes spin-close { 100% { transform:rotate(-0deg); } }
// Open state
#-moz-keyframes spin-open { 100% { -moz-transform: rotate(-90deg); } }
#-webkit-keyframes spin-open { 100% { -webkit-transform: rotate(-90deg); } }
#keyframes spin-open { 100% { transform:rotate(-90deg); } }
I don't know whether I'm looking at it all wrong? Please advise(a demo would be awesome).
Don't bother with javascript or animations. Use a CSS transition for this:
.image {
position: absolute;
top: 50%;
left: 50%;
width: 120px;
height: 120px;
margin:-60px 0 0 -60px;
transition:all 1s ease-out;
transform:rotate(0deg);
-webkit-transform:rotate(0deg); /* Safari and Chrome */
}
.image:hover {
transform:rotate(90deg);
-webkit-transform:rotate(90deg); /* Safari and Chrome */
}
http://jsfiddle.net/Ugc5g/892/
To reverse the rotation, you can simply change the degree value to the opposite value. For example, if the element is currently rotated 45 degrees clockwise, you can reverse the rotation by rotating it -45 degrees.
transform: rotate(-45deg);

Combining semi transparency of background image with keyframe animation

I would like to add a continuous fading effect in the background image of my wrapper. I know you can use keyframe animation to make a background image move arround, however, i was wondering if there is a fade effect possible using this technique.
http://css-tricks.com/snippets/css/webkit-keyframe-animation-syntax/
For example:
#-webkit-keyframes fontbulger {
0% {
font-size: 10px;
}
30% {
font-size: 15px;
}
100% {
font-size: 12px;
}
Would be in my perfect situation something like...
#-webkit-keyframes fontbulger {
0% {
background: url(image.png, 1);
}
30% {
background: url(image.png, 0.5);
}
100% {
background: url(image.png, 1);
}
...for which 0.5 would be a visibility of 50%. Ofcourse, this suggestion does not work. Any way to accomplish this? I know you can apply transparency to RGB value's, but I would like to apply it to an image.
I am not aware of any way currently to directly affect the opacity of the background image as you seek. Two possible workarounds are:
1. Pure CSS3 way (not well supported yet)
Using a pseudo-element to supply the background-image allowed opacity to be used and keep the whole thing as pure css, but it did not work on webkit (which apparently does not support animation on pseudo-elements), only on the moz extension (I could not test IE10... feedback on that would be helpful). Compare Firefox with Chrome for this fiddle, which used this code:
HTML
<div class="bkgAnimate">Foreground text</div>
CSS
.bkgAnimate {
width: 300px; /*only for demo*/
height: 200px; /*only for demo*/
position: relative;
z-index: 1; /* make a local stacking context */
}
.bkgAnimate:after {
content: '';
position: absolute;
top:0;
right: 0;
bottom: 0;
left: 0;
background: url(src="your/image/path/file.png") no-repeat;
z-index: -1;
-webkit-animation: fontbulger 3s infinite;
-moz-animation: fontbulger 3s infinite;
-ms-animation: fontbulger 3s infinite;
}
#-webkit-keyframes fontbulger {
0% { opacity: 1; }
30% { opacity: 0.5; }
100% { opacity: 1; }
}
#-moz-keyframes fontbulger {
0% { opacity: 1; }
30% { opacity: 0.5; }
100% { opacity: 1; }
}
#-ms-keyframes fontbulger {
0% { opacity: 1; }
30% { opacity: 0.5; }
100% { opacity: 1; }
}
2. Cluttered HMTL solution (more cross browser friendly)
Changing to put an actual img tag in as the background seemed to be the only way to get webkit to behave, as this fiddle shows. But that may not be desirable for you. Code similar to above except:
HTML
<div class="bkgAnimate">Foreground text
<img class="bkg" src="your/image/path/file.png"/>
</div>
CSS change from above
Change the :after selector to .bkgAnimate .bkg and remove the content and background property from that code.

Resources