HTML5 Canvas 2D Library
 

Workarounds for CSS Transitions on the Display and Height Properties

With the CSS property display:none an element can be removed from the displayed page. Unfortunately CSS transitions on the display property, which could be used to gradually remove an element, are not supported by CSS1 and furthermore setting the display property also cancels transitions on all other properties.

This article gives various workarounds for these limitations i.e. transitions that gradually make an element disappear with various visual effects.

Simple (but incomplete) Opacity Workaround

In simple cases it is possible to use the opacity property instead of the display property, resulting in a fade-out effect. Setting opacity to 0 makes an element fully transparent and so makes it disappear.

<style >
   .cl0  { opacity : 0; transition:opacity 1s; }
   .cl0:hover { opacity : 1}
</style>
 
<div class="cl0">
   Sample Text
</div>
<span class="hoverhere">Hover Above this Line</span> <br>
leaves empty space, fails on IE8 and catches events while transparent
 
Sample Text
Hover Above this Line
leaves empty space, fails on IE8 and catches events while transparent

This method has 3 important limitations :

  • The element becomes transparent and empty space remains. In contrast display:none fills that empty space by moving the following elements upwards.
  • The transparent element is not completely gone but still catches mouse events, while an element with display:none does not. This can cause unwanted effects, e.g. covered links not working, see our blog article "Problems of CSS Transition Opacity for Fade Effects".
  • It fails on older browsers, e.g. IE 8, because opacity is not supported by older browsers.

Better Solutions and other Visual Effects

If you are looking for solutions that eliminate the empty space by moving up following content, please continue reading this article. Otherwise, please refer to the CSS Transition Visibility article, which explains how to do various visual effects that gradually make an element appear or disappear.

CSS Transitions on the Height Property

The idea is to simulate a display:none by setting the content elements height to 0 and then to slide-in the element by setting the height to normal.

This works fine, as long as the height of the element is fixed and known. It is required to specify the height as number in the style sheet. Unfortunately the transition does no longer work if height:auto or height:100% is specified (unless the parent element has a fixed height). In the example below we used a height of 100px, which leaves some extra space after Line2.

<style >
   .cl1            { height:0px; transition-property:height
                       transition-duration:1s; overflow:hidden}
   .outer1:hover .cl1 { height  : 100px}
</style>
 
<div > This is a first paragraph before the sample text. </div>
<div class="outer1">
   <div class="cl1">
      Sample Text<br >
      Line1 <br >
      Line2 
   </div>
   <div class="hoverhere">Hover Here</div>
</div>
<p > This is a second paragraph after the sample. </p>
 
This is a first paragraph before the sample text.
Sample Text
Line1
Line2
Hover Here

This is a second paragraph after the sample.

Easily Create WebGL™ based 2D/3D animations using our taccgl™ open source library:
taccGL Home Tutorial

CSS Transitions using the Max-Height Property

As with height, the idea is to simulate a display:none by setting the elements max-height to 0 and then to slide in the element by setting the max-height to normal.

The advantage of max-height compared to height is that in case max-height is too big, no extra space shows up, since max-height just limits the height of the content box but does not make it bigger than required. So it is possible to set max-height to a high value that is bigger than the biggest possible content element.

<style >
   .cl4            { max-height:0px; transition:max-height 1s; 
                       overflow:hidden}
   .outer4:hover .cl4 { max-height  : 100px}
</style>
 
<div > This is a first paragraph before the sample text. </div>
<div class="outer4">
   <div class="cl4">
      Sample Text <br >
      Line1 <br >
      Line2 
   </div>
   <div class="hoverhere">Hover Here</div>
</div>
<p > This is a second paragraph after the sample. </p>
 
This is a first paragraph before the sample text.
Sample Text
Line1
Line2
Hover Here

This is a second paragraph after the sample.

So the advantage of using max-height is that the height of the content element does not need to be known and fixed. It is sufficent to use an upper bound, i.e. a height value that is heigher than the content element ever can get.

The problem is, however, if the upper bound used for max-height is significantly bigger than the real height, then it takes considerable transition run-time to animate the max-height from the upper bound down to the real height. This appears as an undesired delay before the closing transition (although the transition is running and animating the max-height that does not have a visual effect until max-height limits the actual height.) In addition since the transition timing function applies to the complete transition of max-height and not just the visible part it does not appear right, if upper bound and real height a quite different.

In summary the max-height transition works well, if one knows a close upper bound of the height of the content element, but it becomes difficult, if you know nothing about the content, e.g. because it contains unkonwn data.

CSS Transition on the Margin-Top/Margin-Bottom Property

By directly enclosing the content element in another element with overflow:hidden and using a negative value for margin-Top or margin-Bottom it is possible cut away the upper or lower part of the content element. By using a negative value of margin-Top or margin-Bottom that('s absolute value) is bigger than the content elements height the content element completely vanishes.

<style >
   .cl2            { transition:margin-top 1s; margin-top:-200px;}
   .outer2:hover .middle2 .cl2 { margin-top : 0px}
   .middle2          { overflow:hidden }
</style>
 
<div > This is a paragraph before the second example 
text. </div>
<div class="outer2">
   <div class="middle2">
       <div class="cl2">
            Sample Text
            Sample Text
            Sample Text
            Sample Text
       </div>
   </div>
   <div class="hoverhere">Hover Here</div>
</div>

<p > This is a paragraph after the second sample. </p>
 
This is a paragraph before the second example text.
Sample Text Sample Text Sample Text Sample Text
Hover Here

This is a paragraph after the second sample.

This solution at the first glance has a similar disadvantage as the max-height solution, i.e. one has to find a good upper bound for the maxium height of the content box and if the upper bound is too big, then there are some timing problems: With Margin-Top/Margin-Bottom there is a delay before the opening animation, while with max-height there is a delay before the closing animation.

However, it is possible to extend this solution in the following way:

Margin-Top/Margin-Bottom Transition Combined with Height Transition

As explained above, in order to use the transition on max-height or on margin-top/margin-bottom as described in the previous paragraph one needs to supply an upper bound for maximal height of the content element.

If the guess is wrong and the content element becomes bigger than the value used, then the content element will not open completely in the max-height case and it will not vanish completely in the margin-top/margin-bottom case.

Now the idea is to combine these solutions and to use a transition on max-height to make the element vanish after the transition. Then even if margin-top/margin-bottom does not completely remove the element max-height will.

In the following example the margin-top/margin-bottom transition described in the previous paragraph is combined with a "transition" on max-height property from 0px to 100%. As explained above such a transition on max-height from 0px to 100% does not work smoothly, however it at least opens an closes the element instanteanously.

<style >
   .cl7            { transition:margin-bottom 1s ease-in; 
                       margin-bottom:-150px;}
   .outer7:hover .middle7 .cl7 { 
                     transition:margin-bottom 1s ease-out;
                     margin-bottom : 0px}
   .middle7          { overflow:hidden; 
                       transition:max-height .1s ease 1s; max-height:0px}
   .outer7:hover .middle7 {
                       transition:max-height .1s ease 0s; 
                       max-height:10000px}
</style>
 
<div > This is a paragraph before the second example text. </div>
<div class="outer7">
   <div class="middle7">
       <div class="cl7">
            Sample Text
            Sample Text
            <div style="height:150px; background-color:blue">
            </div>
            Sample Text
       </div>
   </div>
   <div class="hoverhere">Hover Here</div>
</div>

<p > This is a paragraph after the second sample. </p>
 
This is a paragraph before the second example text.
Sample Text Sample Text
Sample Text
Hover Here

This is a paragraph after the second sample.

For using this approach you still need to guess something like an upper bound, for the height of the content element, 150px in the example. However, it is not a desaster if the guessed value is too small in some situations, then the opening transition jumps in the beginning and the closing transition jumps at the end, which does not look that bad (please try out the example).

Adding Animations

Now it is possible to add animations that play while the element's height gradually changes. The following example shows some WebGL™ and taccgl™ animations (that require to include the taccGL Library) and the examples below shows some CSS transitions on the transform property.

<style >
   #el10       { border: 1px black solid; background-color:yellow;
                       padding:30px}
   #middle10   { overflow:hidden; transition:height 2s linear 0.1s;
                       height:0px;}
</style>
 
<div > This is a paragraph before the example text. </div>
<div id="middle10">
       <div id="el10">
            Sample Text Sample Text  Sample Text Sample Text
       </div>
</div>
<p > This is a paragraph after the example. </p>
 
This is a paragraph before the example text.
Sample Text Sample Text Sample Text Sample Text

This is a paragraph after the example.

var t=taccgl.actor("el10",taccgl.flexiBorder,"visible");
t.from(t.x+(t.w/2),t.y,0).to (t.x+(t.w-t.h)/2,t.y,0).
resize(1,1,t.h,t.h/2).Circle().start()
.cont().Rect1().flyHome().resize(t.h,t.h/2,t.w,t.h).start();
t.el.parentElement.style.height=t.h+"px";
RUN
var t=taccgl.actor("el10",taccgl.flexiBorder,"hidden");
t.resize(t.w,t.h,t.w*2,t.h/2).
to(t.x-t.w/2,t.y,0).Circle1().dur(1).start();
t.cont().resize(t.w*2,t.h/2,t.w*4,1).
to(t.x-t.w*3/2,t.y,0).dur(1).start();
t.el.parentElement.style.height="0px";
RUN
t=taccgl.actor("el10",null,"visible");t.resize(t.w,1,t.w,t.h).dur(2).start();
t.el.parentElement.style.height=t.h+"px";
RUN
t=taccgl.actor("el10",null,"hidden");t.resize(t.w,t.h,1,1).dur(2).start();
t.el.parentElement.style.height="0px";
RUN
taccgl.a(document.body).color("white").shadowOnly().dur(2).start();
var t=taccgl.actor("el10",null,"visible").from(-300,1000,-4000).
vEnd(0,0,0).duration(2).start()
t.el.parentElement.style.height=t.h+"px";
RUN
taccgl.a(document.body).color("white").shadowOnly().dur(2).start();
var t=taccgl.actor("el10",null,"hidden").to(-400,1000,-4000).
vBegin(0,0,0).rotateMiddle(0,1,0).duration(2).start()
t.el.parentElement.style.height="0px";
RUN

For the WebGL™ animations we just used the workaround on the height property as discussed first in this article, since with javaScript and taccgl™ the actual height value value is readily available as t.h: t.el.parentElement.style.height=t.h+"px";. This works fine, as long as the content element does not dynamically change its height. If it does, use onEnd to reset the height to auto after the animation.

For the following CSS animation(s) we used the Margin-Top/Margin-Bottom Transition Combined with Height Transition Workaround and added a transition on the transform property.

<style >
   .cl11            { transition:margin-bottom 1s ease-in, transform 1s; 
                     transform:rotate(150deg);
                       margin-bottom:-150px;}
   .outer11:hover .middle11 .cl11 { 
                     transition:margin-bottom 1s ease-out, transform 1s;
                     transform:rotate(0deg);
                     margin-bottom : 0px}
   .middle11          { overflow:hidden; 
                       transition:max-height .1s ease 1s; max-height:0px}
   .outer11:hover .middle11 {
                       transition:max-height .1s ease 0s; 
                       max-height:10000px}
</style>
 
<div > This is a paragraph before the second example text. </div>
<div class="outer11">
   <div class="middle11">
       <div class="cl11">
            Sample Text
            Sample Text
            <div style="height:150px; background-color:blue">
            </div>
            Sample Text
       </div>
   </div>
   <div class="hoverhere">Hover Here</div>
</div>

<p > This is a paragraph after the second sample. </p>
 
This is a paragraph before the second example text.
Sample Text Sample Text
Sample Text
Hover Here

This is a paragraph after the second sample.

Conclusion

We showed various workarounds for transitions on the CSS display:none property, i.e. transitions that make an element appear or disappear in a way that other elements take up the space of a disappearing element, e.g. by scrolling up and down the elements below.

These combine well with WebGL™ animations made with taccgl™ whereby the taccGL transition plays on the element itself and the CSS transition moves the remaining HTML elements in and out the space of the disappering or appearing element.

Blog Articles

Parallax scrolling with 3D Acceleration
CSS Transition Opacity for Fade Effects
CSS Transition Display
CSS Transition Visibility
WebGL-HTML5 PopUp Animations
3D Objects on HTML pages
Deforming and Morphing of HTML

Tutorial Sections

First Example
Basic Shapes
Basic 3D Models
Basic Animations
Colors and Textures
Integration of HTML and WebGL
Timing Transitions
Boxes
JavaScript Embedding
External 3D Models
HTML Elements on Canvas
Selectors for Multiple Transitions
Flexibles
Fragment Shaders

 

WebGL™ is a trademark of the Khronos Group Inc.

[1] The CSS Transition Working Draft does not list the display property as one of the animatable properties and so no CSS transtions on that property are possible.
Please Add a Comment or Question, click here!
 
Easily Create
WebGL 2D/3D
Animations
using HTML+CSS
taccGL
Open Source javaScript
Library