How to unveil a div with fixed contents

487 Views Asked by At

I'm animating an element by unveiling it from the bottom of the page. The position of the child elements should not be affected by the size change of the unveiling animation.

That's what I'm looking for:

goal

<div>
    <h1>Hello stranger</h1>
</div>

Both elements are positioned absolute with top, right, bottom & left set to 0. The contents are revealed by lowering the top of the div from 100% to 0%. Have a Fiddle.

My goal is

  1. to keep the heading always at a fixed position (middle)
  2. hide the heading when it is not uncovered yet

But these are my problems (Fiddles included)

  • When using position:fixed for the h1 the overflow becomes always visible.
  • When using position:absolute the position isn't fixed correctly.
  • When using clip:rect(500px auto auto auto) I lose the ability to use %. And thus I can't determine the exact height of the viewport without using JavaScript.

What else can be done to archieve the described behavour without JS?

5

There are 5 best solutions below

1
On BEST ANSWER

The solution is to move the h1 in the opposite direction to the div animation at the same time which gives the illusion that the h1 has remained static. However the h1 is actually also moving relative to the div just in the opposite direction.

I've kept the same markup and also the position: absolute; top: 0; right:0; left:0; bottom: 0; requirement you stated on both elements.

http://jsfiddle.net/eLbcdc9c/6/

HTML

<div>
    <h1>Hello stranger</h1>
</div>

CSS

div {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: #000;
    transform: translate3d(0, 0%, 0);
    overflow: hidden;
}

h1 {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    color: #fff;
    text-align: center;
    transform: translate3d(0, 50%, 0);
}

/* Transition effect and timing must be the same for both elements to give the perfect illusion */
div,
h1 {
    transition: transform 500ms ease-in;
}

/* The transform class added to the div to begin the animation on the h1 and div at the same time */
.hide {
    transform: translate3d(0, 100%, 0);
}
.hide h1 {
    transform: translate3d(0, -50%, 0);
}

Apply the hide class to the div (by clicking the toggle in the fiddle) and you should get the desired affect.

Things that are important to note here is the use of 3dtransforms. These are much smoother than animating top or margins and takes advantage of using a devices GPU for Hardware acceleration to achieve this.

3dtransforms are very well supported but you may need to apply the browser prefixes in some instances depending on the support you want to offer.

4
On

This is what you want exemple.

You need to do this. And see the css in the exemple.

<h1>Hello stranger</h1>
<div class="test"></div>
0
On

As an alternative you could translate the div:after on top of your text :

fiddle

$$('button').first().on('click', function(e){ $$('body').first().toggleClassName('animate'); });
body{
    margin:0
}


div {
     position:absolute;
    height: 100%;
    width: 100%;
    z-index: -1;
    overflow:hidden
}

div:after {
    content: "";
    position: absolute;
    height: 100%;
    width: 100%;
    bottom: 100%;
    background-color: black;
    top:0;
    z-index:999;
}
h1 {
    position:absolute;
    color:red;
    top:50%;
    left:0;
    right:0;
    text-align:center;
    transform:translateY(-50%);
}

.animate div:after {
    animation-name:ani;
    animation-duration:2s;
    animation-fill-mode: forwards;
}

@keyframes ani {
    0% {
        transform: translateY(0);
    }
    
    100% {
       transform: translateY(-100%);
    }
}
button{position:absolute;top:5px;left:5px;
z-index:9999}
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.min.js"></script>
<div><h1>Hi, I'm centerized</h1></div>


<button>Start</button>

0
On

Here goes my attempt, using a pseudo element to hide the h1

This pseudo element has an arbitrary high height, and is positioned always at the upper side of the div.

div:after {
    content: "";
    position: absolute;
    height: 9999px;
    width: 100%;
    bottom: 100%;
    background-color: white;
}

fiddle

3
On

I think you could just change the h1 from position:absolute to fixed.

http://jsfiddle.net/o8d79jum/8/

div {
    position:absolute;
    overflow:hidden;
    top:100%;
    right:0;
    bottom:0;
    left:0;
    background:black;
    color:white;
    animation:ani 2s infinite;
}
h1 {
    position:fixed;
    top:50%;
    left:0;
    right:0;
    text-align:center;
    transform:translateY(-50%);
    margin:0;
}
@keyframes ani {
    0% {
        top:100%;
    }
    100% {
        top:0%;
    }
}
<div>
     <h1>Hi, I'm centerized</h1>
</div>