36

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)?

futuraprime
  • 5,468
  • 7
  • 38
  • 58
  • 1
    @adrift [As of CSS 3, nested `At`-rules are permitted](https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule). CSS2.1 is from 1998 btw, so it's very obsolete now. – Dai Oct 04 '20 at 09:18
  • @Dai: Deleted, thanks for updating me. – Adrift Oct 13 '20 at 16:16

5 Answers5

66

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); }
}
Muhammad Dyas Yaskur
  • 6,914
  • 10
  • 48
  • 73
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
14

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); }
  }
}
tomijovanoski
  • 481
  • 4
  • 5
2

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.

myajouri
  • 3,076
  • 18
  • 13
  • Unfortunately, it needs to be fast on mobile devices, which means I need to use a 3d transform to get hardware acceleration. Otherwise I'd be doing this. – futuraprime Dec 05 '13 at 22:09
  • I see. I have just posted another answer for that purpose. It requires some experimentation to get the results you want, but I hope you'll find it helpful. – myajouri Dec 06 '13 at 08:43
  • do you have example of sliding relative to parent element? seems that more than `position: absolute` is needed http://jsfiddle.net/ypuun2xL/ – Simon_Weaver Mar 24 '15 at 03:51
  • @Simon_Weaver you mainly need a `position: relative` on the parent as well. Here are two different ways of achieving this (it can get more complicated/simple depending on your needs): http://jsfiddle.net/ypuun2xL/3/ and http://jsfiddle.net/ypuun2xL/4/ – myajouri Mar 24 '15 at 12:51
2

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" />
ElChiniNet
  • 2,778
  • 2
  • 19
  • 27
0

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/

myajouri
  • 3,076
  • 18
  • 13