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

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 (<body>, 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:
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:
it doesn't slide in, it's more like drops the curtain
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:
And fiddle for that:
http://jsfiddle.net/bsd7vnwu/1/

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

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/

I added transition to your fiddle to get what i think you are looking for
.inner {
background: #afa;
width: 300px;
overflow: hidden;
max-height: 0;
transition:0.5s ease-out;
}
.body:hover .inner {
max-height: 100%;
transition:0.5s ease-in;
}
JSFIDDLE
and by lowering the time for transition:ease-out you will get a more responsive slide up when you mouse out of the div
like this JSFIDDLE

Another CSS solution after 2.5 years, using flex layout:
.body {
background: #aaf;
height: 300px;
width: 300px;
overflow: hidden;
}
.inner {
display: flex;
align-items: flex-end;
-webkit-transition: all cubic-bezier(0, 1, 0, 1) 0.5s;
transition: all cubic-bezier(0, 1, 0, 1) 0.5s;
background: #afa;
max-height: 0;
overflow: hidden;
}
.body:hover .inner {
-webkit-transition: all ease-in-out 0.5s;
transition: all ease-in-out 0.5s;
max-height: 100%;
}
<div class="body">
<div class="inner">Green is variable-height text which slides in on viewport hover</div>
Blue is a viewport (<body>, visible part of a page), which content should be compressed
Also on JSFiddle.

Related

CSS transition on height auto only working when adding class, not when removing class

The goal is to use CSS transition on the height of a div changing from 0 to auto height so it slides open and closed as a visual.
Because CSS height: auto can't have transition, I used max-height as the transition. When I add the class "expanded" the height is then auto...
But when toggling the height on and off, it transitions only when adding the class. Removing the class (changing the height back to 0 and max-height back to 0) the transition doesn't exist and it is instant
.information{
height: 0;
max-height: 0;
width: 100%;
overflow: hidden;
z-index: -1;
background: #434C69;
transition: max-height 700ms ease-in-out;
&.expanded{
height: auto;
max-height: 500px;
border-bottom: 1px solid $secondary-blue;
}
}
It's the height, you are adding transition on max-height but your height changes to 0 instantly when you remove expanded class.
You can set height: auto; on the .information class with transition only on max-height.
.information{
height: auto;
max-height: 0;
width: 100%;
overflow: hidden;
z-index: -1;
background: #434C69;
transition: max-height 700ms ease-in-out;
&.expanded{
max-height: 500px;
border-bottom: 1px solid $secondary-blue;
}
}
you should create a class which it reverses the affect of information class and assign it instead of removing information class.
I hope it will be useful.

initiate css transitions on page load

Im trying to understand CSS Transition - but I cant make it happen. I want to make a line go from 0 to 100% width with a small delay on pageload. I understand that CSs transition needs a trigger, and tried to read up to a jQuery or Vanilla Js solution, but get stuck.
Why is this ot working? Jsfiddle: https://jsfiddle.net/1fzzgnwy/
<div class="container">
<span class="h-line"></span>
</div>
.h-line {
position: absolute;
z-index: -1;
width: 0%;
height: 10px;
right: 0;
background-color: #000;
top: 400px;
transition: right 1.5s linear;
transition-delay: 2s;
}
.h-line.ready {
width: 100%;
background-color: #000;
}
.container {
height:100%;
width:100%;
}
$(function(){
$('.h-line').addClass('ready');
});
In your transition line, you are telling it to transition right, but that doesn't change in the added class. Your width does. So you need to transition the width like transition: width 1.5s linear;: JS Fiddle
And if you want it to expand left to right, remove right: 0: JS Fiddle
In your jsfiddle link (https://jsfiddle.net/1fzzgnwy/) there are some errors.
Here a simplified example of your code that work https://jsfiddle.net/50t3qwmL/ .
.h-line {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
background-color: #000;
transition: .3s;
transition-delay: 2s;
}
.h-line.ready {
width: 100%;
}

Image rendering with decimal pixels and css transition

If an image in an element with a decimal width is animated using css (opacity), the image loads at a fixed pixel width then after completing the transition changes size to the correct decimal pixels.
I have tested this on Chrome only. See the fiddle, which shows the problem only when using css animations. http://jsfiddle.net/minlare/kext0af4/
.opacity{
width: 400px;
}
.opacity div {
width: calc(100% / 3);
float: left;
}
.opacity img{
max-width: 100%;
display: block;
opacity: 1;
transition: .25s;
}
.opacity img.visible{
opacity: 0;
}
Any way around this?
I solved adding outline: 1px transparent solid;
.opacity img{
max-width: 100%;
display: block;
opacity: 1;
transition: .25s;
outline: 1px transparent solid;
}
Fork: http://jsfiddle.net/0dvvd1n1/
Also backface-visibility: hidden; solves the issue but the outline approach doesn't create sharpened edges.
Another method to sort of solve it is to add translate:transformZ(0) This forces GPU rendering, which corrects the jumping in the version I tested it in (Chrome 43.0.2357.132 on Mac). However, it can cause issues if there are a large number of GPU rendered elements that have transitions.
http://jsfiddle.net/kudj7zxn/
.opacity img{
max-width: 100%;
display: block;
opacity: 1;
transition: .25s;
transform: translateZ(0);
}

CSS Transition and Auto position

I have a div .box with which has absolute position set at the bottom of the parent div. It does not have the top position set because the height differs for different .box divs. On hover over the parent div, I want to change its top position to 0 with the transition effect.
In the following code transition does not work if I do not define the top position by default. I have tried using top: auto and it still does not work. How can I use transition without defining the top position.
Here's my code:
HTML:
<div class="wrap">
<div class="box">
Box
</div>
</div>
CSS:
.wrap{
position: relative;
height: 200px;
width: 200px;
background: green;
}
.box{
background: yellow;
position: absolute;
bottom: 0;
left: 0;
transition: all 0.9s ease 0s;
top: 50%; /*== does not work without it ==*/
}
.wrap:hover .box{
top: 0;
bottom: 0;
}
Fiddle: http://jsfiddle.net/5hs09apn/
A slight different approach than using top: http://jsfiddle.net/5hs09apn/2/
set the height for the box, and on hover set it to 100%; let the bottom be zero, so you don't even need to use top
.box{
background: yellow;
position: absolute;
bottom: 0;
left: 0;
height:20px;
transition: all 1s ease 0s;
}
.wrap:hover .box{
height:100%;
bottom: 0;
}
.wrap {
position: relative;
height: 200px;
width: 200px;
background: green;
}
.box {
background: yellow;
position: absolute;
bottom: 0;
left: 0;
height: 20px;
transition: all 1s ease 0s;
}
.wrap:hover .box {
height: 100%;
bottom: 0;
}
<div class="wrap">
<div class="box">
Box
</div>
</div>
Add Top property in JQuery getting the current value of the Top of the .box using position().
This will be dynamic allocation of Top and will not effect your condition of varying .box height.
While doing this, you will have to add the hover effect in the JQuery part too, since the Top will be defined here and CSS wont know what to do with the hover.
Check the Fiddle here
This is the JQuery function added:
$(document).ready(function(){
var x = $('.box').position();
var myTop = x.top;
$('.box').css("top",myTop+"px");
$('.box').css("transition","all 0.9s ease 0s");
$('.wrap').bind('mouseover',function(){
$('.box').css("top","0px");
$('.box').css("bottom","0px");
});
$('.wrap').bind('mouseout',function(){
$('.box').css("top",myTop+"px");
$('.box').css("bottom","0px");
});
});
Hope this gives you what you need.
You can use:
.wrap:hover .box{
margin-bottom: 100%;
}
And try with different percentages until you get one you like. It's crude but I think it can work.

Change child style on parent hover, with :after

I have a button with a link inside it, and an animated underline for said link. Code used from here, (example).
To make sure the underline was not huge and far below the text, I applied the animation to the text itself. The problem with this is the hover radius is to small, and I would like the entire button to be able to trigger the animation.
Here is my css and html:
.menuButtonText {
display: inline-block;
position: relative;
padding-bottom: 3px;
}
.menuButtonText:after {
content: '';
display: block;
margin: auto;
height: 2px;
width: 0;
background: transparent;
transition: width .5s ease, background-color .5s ease;
}
.menuButtonText:hover:after {
width: 100%;
background: #E0E0E0;
}
.menuButton {
width: 200px;
height: 100px;
margin: 20px;
background-color: red;
}
<div class="menuButton"><a class="menuButtonText">MenuButton</a>
</div>
<div class="menuButton"><a class="menuButtonText">MenuButton</a>
</div>
<div class="menuButton menuButtonSelected"><a class="menuButtonText">MenuButton</a>
</div>
The "menuButton" class is the parent and much larger than the space the text takes up, which is the trigger I wanted, I can't seem to get other solutions to work, and I'm assuming thats because of the ":after".
This what you're after?
http://jsfiddle.net/19mdzLdk/
I added this css:
.menuButton:hover .menuButtonText:after {
width: 100%;
background: #E0E0E0;
}
Now on div hover, the text underlines.