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.
|
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.
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.
|