Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to shift element upwards to it's variable height using css

Main question

I have two divs, one nested inside the other and i wish to shift inner div outside (upwards) of outer div and slide-in it on a hover.

Markup is looking like so:

<div class="body">
    <div class="inner">Green is variable-height text which slides in on viewport hover</div>
    Blue is a viewport (&lt;body&gt;, visible part of a page), which content should be compressed upon green slide-in
</div>

And (a little pseudo) css:

.body {
    background: #aaf;
    height: 300px;
    width: 300px;
    overflow: hidden;
}

.inner, .body:hover .inner {
    -webkit-transition:all linear 0.2s;
    transition:all linear 0.2s;
}

.inner {
    background: #afa;
    width: 300px;
    margin-top:-some-magic-to-get-this-div-height;
}

.body:hover .inner {
    margin-top: 0;
}

And a final result animation i'd like to get, without using fixed height of green div:

example.gif

Also, this example (with a guessed and hard-coded height value of 2.5em) on jsfiddle to experiment with:

http://jsfiddle.net/n7vyLoh4/20/

Possible partial work-around (not satisfactory)

It is possible to partially implement what i want, using transitioning max-height instead of transitioning margin-top, the transition of max-height: 0; -> max-height: 100%; with overflow: hidden; set at all times works, but has two draw-backs:

  1. it doesn't slide in, it's more like drops the curtain
  2. it doesn't stop transition at the end of green div, it transits till the end of outer blue div, which especially noticeable at reverse transition, when it first travels all the way from bottom of blue div to bottom of green div before any effect is visible. Also, this means that despite transition time set to 0.2s, it will spend only fraction of this time on transiting trough green div, because this 100% are 100% of parent div, not inner one (and my question could be answered if there is a way to calculate the 100% of inner div height).

Here is an illustration:

example2.gif

And fiddle for that:

http://jsfiddle.net/bsd7vnwu/1/

like image 415
Alexander Tumin Avatar asked Nov 07 '14 22:11

Alexander Tumin


2 Answers

This is the pure css solution, which means it does not require any scripts, just a browser that support transitions:

.body {
    background: #aaf;
    height: 300px;
    width: 300px;
    overflow: hidden;
}

.inner {
    -webkit-transition:all cubic-bezier(0,.81,.4,1) 0.5s;
    transition:all cubic-bezier(0,.81,.4,1) 0.5s;
}

.inner {
    background: #afa;
    width: 300px;
    position: absolute;
    margin-top: -100%;
    float: left;
}

.body:hover .inner {
    position: relative;
    margin-top: 0;
}

And Fiddle is here

like image 78
skobaljic Avatar answered Sep 28 '22 02:09

skobaljic


I think this is the effect you want. CSS doesn't allow you to get the height of an element to use in calc() for positioning and margins, so a little JS is needed.

CSS:

.body {
    background: #aaf;
    height: 300px;
    width: 300px;
    overflow: hidden;
}

.inner, .body:hover .inner {
    -webkit-transition:all linear 0.2s;
    transition:all linear 0.2s;
}

.inner {
    background: #afa;
    width: 300px;
    overflow: hidden;
}

.body:hover .inner {
    margin-top : 0 !important;
}

JS:

Array.prototype.forEach.call(document.getElementsByClassName('inner'), function (item) {
    item.style.marginTop = (item.clientHeight * -1) + 'px';
});

Demo:

http://jsfiddle.net/09tyLr9b/

like image 27
AlienWebguy Avatar answered Sep 28 '22 01:09

AlienWebguy