HTML5+CSS on Canvas 3D WebGL (TM) Library
 

CSS Transition Visibility

The CSS visibility transition does not make elements appear or disappear gradually (see 2 sections below), as one might expect. It is, however, important in combination with a visual effect that is specified separately by other means (see below Why setting Visibility and using Transition is often needed) E.g. often just the opacity transition is used for a fade-in and fade-out effect. This, however, has significant problems in specific situations or with certain browsers, as discussed below.

In this article we give various sample visual effects for combination with the visibility transition, to make an element appear or disappear made with HTML5 features like
X

Sample HTML/CSS Text

Dummy text to replace by a text of your choice.

Use the X above to close.

CSS transitions or WebGL™. Click on the effects listed below or on more to scroll to source code and description below.
Curved more
Circles more
Rotating Fade more
Fly In with Shadow more
Fade more
Flexible more
Fly In more
Appear Inside more
Rotation more
Box more
Circle Blend more
Parts more
Spin
Parts more
Spin
Box more
Rotation more
Fade more
Appear Inside more
Fly In more
 
The following animations require WebGL™
Curved more
Circles more
Fly In with Shadow more
Flexible more
Rotating Fade more
Circle Blend more

Incomplete Workaround: Fade-In and -Out using Transitions on Opacity

Most often the opacity property is used instead of visibility, which results in a fade-in and fade-out effect. The idea is that a completely transparent element is very similar to an element with visibility:hidden.

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

However care has to be taken with that approach, because unlike an invisible element (with visibility:hidden) a fully transparent element (opacity:0) still catches events and e.g. a transparent link still functions. The blog article CSS Transition Opacity for Fade Effects has a detailed description and examples of that problem. Also old browsers like IE8.0 do not understand the opacity property and so this simple approach will never hide the element in IE 8.

The solution is to combine the opcity transition with a transition on visibility. Before we discuss that in detail after the next the section, the next section itself explains the detailed workings of transitions on visibility.

Appearance of a CSS Transition on Visibility

Just as transitions on other properties you can define a transition on visibility, e.g. using " transition:visibility 1s". This example specifies a duration of 1 second. There are still just the two states visible and hidden (for normal non-table elements). While the transition is running, the element is visible regardless if it is a transition from visible to hidden or vice versa from hidden to visible (if using the default ease or the linear timing function). Only after the transition visibility switches to its specified target value.

So in other words, when you hide an element using a transition from visibility:visible to visibility:hidden it takes some time before the element is actually hidden. This is the time when you want to play some visual effect. You can specify the time as duration of the visibility-transition.

On the other hand, when you reveal an element using a transition from visibility:hidden to visibility:visible then the element becomes visible immediately regardless on the specified duration.

This might sound like a strange complicated behaviour, but it nicely solves the problem of playing a visual effect to hide an element:

Why the Transition on Visibility is often Needed

Often simply using "visibility:hidden" in a style sheet renders an additional visual effect invisible and therefore does not work. On the other hand leaving out the "visibility:hidden" can create other unwanted effects as discussed in the next section.

The solution is delaying hiding the element via a transition until playing the effect is finished. The specific semantics of the transition makes sure that when playing an animation to let the element appear, the visibility property is set to visible at once, to make the animation show.

Fade-In and -Out by Combining Transitions on Visibility and Opacity

The opacity transition creates a nice fade-in and -out effect. However fully transparent elements, unlike hidden elements, still catch mouse events and older browsers fail completely on opacity. A solution for these problems is to specify a transition on both visibility and opacity. This works fine and the following example shows how to do it:

<style >
   .cl1 { transition:visibility 1s, opacity 1s; 
            visibility:hidden; opacity:0}
   .outer1:hover > div 
         { visibility:visible; opacity:1}
</style>
 
<div class="outer1">
      <div class="cl1">
            Sample Text
      </div>
      Hover Here <br >
</div>
 
Sample Text
Hover Here

It also exposes and solves another problem: if visibility is set to hidden the cl1 element does no longer act on mouse events and so the cl0:hover as used in the first example never applies. So we put another div of class outer1 around the sample element and use a rule .outer1:hover > div which means that whenever the mouse hovers the outer element then the inner div should get the specified format.

Other solutions for these problems are discussed in [1].

Fly In from Outside the Screen - CSS Transition on Left and Top

The idea of this approach is to move an element somewhere off the screen and to so simulate a hidden visibility. This works nicely and the transition shows the element flying from outside the document to its normal position and vice versa.

We modified the example code given above accordingly, leading to the example below. The first thing we added was "width:80%; padding:10%; background-color:yellow;" which gives the element a yellow background and some padding. This is not really required but makes the example look better. Then we gave the element a position outside of the screen using position:relative; left : -2000px; top:-500px;, i.e. we moved the element 2000px to the left and 500px to the top from its normal position. This effectively hides the element without actually using the visibility property. Finally we define transition-property:all; transition-duration:1s; to enable transitions on all properties (we could also have used just left and top).

On activation of the transition we would like move the element to its normal position on the screen e.g. using left : 0px; top:40%. However a rule as above like .cl2:hover { left : 0px; top:40% } will not work, because initially the element is moved off the screen and you cannot move the mouse there. So what we do it to put another div of class outer2 around the sample element. The outer div is normally invisible (we just gave it a blue border for illustration). Then we can write a rule .outer2:hover > div which means that whenever the mouse hovers the outer element then the inner div should get the specified format, { left : 0px; top:40% } in the example.

<style >
   .cl2           {width:80%; padding:10%; background-color:yellow;
                       position:relative; left : -2100px; top:-500px; 
                       transition-property:all; transition-duration:1s;}
   .outer2     {border : 1px blue solid; width:90%; height:100px;}
   .outer2:hover > div {left:0px; top:40%}
</style>
 
<div class="outer2">
      <div class="cl2">
            Sample Text
      </div>
      Hover Here
</div>
 
Sample Text
Hover Here

You can also implement a similar transition using another new HTML5 technique called HTML5 canvas 3D or WebGL™ and the taccgl™ javascript library. The example script below first finds the HTML element with id=demo. Then from(-600,4000,0) declares the corresponding fly in transition from coordinates (x=-600,y=4000,z=0). The vEnd(0,0,0) gradually slows down the motion, which corresponds to the default timing function of the transition example.

taccgl.actor("demo",null,"visible") .from(-600,4000,0). vEnd(0,0,0) . start()RUN

The taccGL/WebGL™ example can easily be extended to display a curved surface showing a kind of page flip effect.

taccgl.actor("demo",taccgl.flexiBorder,"visible") .from(-600,4000,0). Flip(0,0). Rect1(). vEnd(0,0,0) . start()RUN

Also a shadow can be included. In the example below a first line for the shadows and a z-coordinate for the source position of the element were added:

taccgl.a(document.body).color("white") .shadowOnly().showAfter() .start();
taccgl.actor("demo",null,"visible") .from(-400,2500,-2000).
vEnd(0,0,0).duration(3).start()
RUN

Very similar examples are discussed in the WebGL-HTML5 PopUp Animations article or see our WebGL™ webdesign homepage for more details on taccgl™.

Appear Inside - Clipping using Overflow:hidden and CSS transition on Top and Left

The idea of this workaround is to simulate hidden visibility by using the overflow:hidden specification for the outer div element. This specification hides the inner div while it is positioned outside the outer one. Then the transition moves the inner div outside and inside the outer div. It will not move across the document but vanishes as soon as it leaves the outer div.

Main difference of the example below is the overflow:hidden specification for the outer div element. This means that whenever the inner div is positioned outside the outer one, it is hidden. This is done using left : 150px; top:-150px;. When hovering over the outer div, the .outer3:hover > div { left : 0px; top:40% } rule applies and the inner div moves to its normal position inside the outer div and thereby appears.

<style >
   .cl3           { background-color:yellow; width:80%; padding:10%;
                      position:relative; left : 150px; top:-150px; 
                      transition-property:all; transition-duration:1s;}
   .outer3     { width:90%; height:150px; overflow:hidden}
   .outer3:hover > div { left:0px; top:30% }
</style>
 
<div class="outer3">
      <div class="cl3">
            Sample Text
      </div>
      Hover Here
</div>
 
Sample Text
Hover Here

Clipping using Overflow:hidden and CSS Transition on Width

Basic idea of this work around for visibility:hidden is to set an elements width (or height) to 0 and so to make the element disappear. Then the transition turns the width to normal which should result in an animation that gradually makes the element visible from left to right.

For this approach it is essential to use Overflow:hidden on the element itself, because otherwise the elements content stays visible even if the width is set to 0. See below an example. Note that it is necessary to do a transition for padding as well since otherwise the element does not disappear completely. You might notice that there is a line break appearing during the transition, which makes this approach not very attractive.

<style >
   .cl4           {background-color:yellow; width:0px; padding:0px; 
                      overflow:hidden;
                      transition-property:all; transition-duration:1s;}
   .outer4     {width:90%; height:150px; overflow:hidden}
   .outer4:hover > div {width:80%; padding:10%}
</style>
 
<div class="outer4">
      <div class="cl4">
            Sample Text
      </div>
      Hover Here
</div>
 
Sample Text
Hover Here

It is possible to improve this example using 3 nested div-elements. Thereby the inner element is static containing the actual content. The middle element is resizing using the transition. It is also using the overflow:hidden to clip the inner element. The outer element is needed for the hovering to work.

<style >
   .cl6           {background-color:yellow; width:100px; padding:10px; }
   .middle6    {width:0px; overflow:hidden; 
                     transition-property:all; transition-duration:1s;}
   .outer6      {width:90%; height:150px; overflow:hidden}
   .outer6:hover > div {width:80%}
</style>
 
<div class="outer6">
      <div class="middle6">
            <div class="cl6">
                  Sample Text
            </div>
      </div>
      Hover Here
</div>
 
Sample Text
Hover Here

You can implement similar transitions using HTML5 canvas 3D or WebGL™ and taccgl™. Here clipping is done using the ClipA method. In addition there is the resize method to shrink and grow the element.

(a=taccgl.actor("demo",null,"visible")) . clipA(0.1,a.h,a.w,a.h) .start()RUN
(a=taccgl.actor("demo",null,"visible")) . from(a.x+a.w,a.y,0). clipA(0.1,a.h,a.w,a.h) .start()RUN
(a=taccgl.actor("demo",null,"visible")) . resize(0.1,a.h,a.w,a.h) .start()RUN
(a=taccgl.actor("demo",null,"visible")) . from(a.x+a.w/2,a.y+a.h/2,0). resize(1,1,a.w,a.h) .start()RUN

Using a feature called flexiBorder it is further possible to deform the HTML element during the transition:

(a=taccgl.actor("demo", taccgl.flexiBorder, "visible")) . resize(0.1,a.h,a.w,a.h)
.Wave(40,40,-Math.PI,Math.PI) .Rect1() .start()
RUN
(a=taccgl.actor("demo", taccgl.flexiBorder, "visible")) . from(a.x+a.w/2,a.y,0). resize(1,a.h,a.w,a.h)
.Wave(40,40,-Math.PI,Math.PI) .Rect1() .start()
RUN
(a=taccgl.actor("demo", taccgl.flexiBorder, "visible")) . resize(0.1,a.h,a.w,a.h)
.ZWave(0.2,0.2,-Math.PI,Math.PI) .Rect1() .start()
RUN
(a=taccgl.actor("demo", taccgl.flexiBorder, "visible")) . from(a.x+a.w/2,a.y,0). resize(1,a.h,a.w,a.h)
.ZWave(0.2,0.2,-Math.PI,0) .Rect1() .blend(0,0,1,0) .start()
RUN

Similar examples are discussed in the WebGL-HTML5 PopUp Animations article.

Using transitions on the CSS Clip Property

Using clipping seems to work as well. The idea is simply to set the clip parameters in a way that clip the complete element in order to simulate hidden visibility. The transition then gradually removes the clipping. Some browsers might have problems with percent values and so you need to specify the actual pixel sizes which is a disadvantage for dynamic or responsive layouts.

<style >
   .cl7           { background-color:yellow; padding:10px; 
                      clip:rect(0px 0px 40px 0px);
                      position:absolute; width:100px;
                      transition-property:all; transition-duration:1s;}
   .outer7     { width:90%; height:150px; overflow:hidden}
   .outer7:hover > div { clip:rect(0px 140px 40px 0px)}  
</style>
 
<div class="outer7"> 
      <div class="cl7">
            Sample Text
      </div>
      Hover Here 
</div>   
 
Sample Text
Hover Here

Circle Blends using transition of the border-radius Property

The next idea is to use a very high value of the border-radius property instead of visibility:hidden. The transition then turns the border-radius to 0 which shows a kind of circle blend.

The first try below is not working. If the border-radius is set too high, the rounded corners do not clip the element but instead the border-radius is just taken into account to the extend that the content of the element stays visible.

This approach, however, works in the special case that the only content of the inner div is a background-image.

<style >
   .cl8           { background-color:yellow; padding:10px; 
                      border-radius:100px;
                      position:absolute; width:100px;
                      transition-property:all; transition-duration:1s;}
   .outer8     { width:90%; height:150px; overflow:hidden}
   .outer8:hover > div { border-radius:0px }
</style>
 
<div class="outer8"> 
      Hover Here for a demo how not to do it.
      <div class="cl8">
            Sample Text
      </div>
</div>   
 
Hover Here for a demo how not to do it.
Sample Text

The problem can be overcome with d a middle element again. In the following circle blend code the "Sample Text" is contained in an inner div element, which in turn is contained in a middle div element. The middle div initially has width:0px; height:0px; and so is invisible. It also has overflow:hidden and so the inner div element is invisible as well. Using the rule .outer10:hover > div { width:140px; height:140px; ... } the middle element grows on hovering.

The middle element also has an initial border-radius:140px which becomes a border-radius:0px on hover and so the middle element turns from a circle to a square on hover.

Normally this would make the middle element grow starting from the top left corner. We however would like to grow it inside out, i.e. the center of the circle and the square should be fixed. Therefore the middle element gets an position:absolute; margin-top:70px; margin-left:70px; which moves the center point of the circle to the center point of the square.

Now we have a new problem, i.e. although the center point is fixed, the "Sample Text" starts to move. To keep that fixed we need to add an initial margin-top:-70px; margin-left:-70px; for the inner element and a final { margin-top:0px; margin-left:0px} using the rule .outer10:hover > div > div { margin-top:0px; margin-left:0px}.

<style >
   .cl10           { background-color:yellow; padding:10px; 
                         padding-top:60px; padding-bottom:60px;
                         height:20px; width:100px; 
                         margin-top:-70px; margin-left:-70px;
                         transition-property:all; transition-duration:1s;
                       }
   .outer10     { width:90%; height:150px;}
   .middle10    { width :0px; height:0px; overflow:hidden; 
                        border-radius:140px;  position:absolute;
                        margin-top:70px; margin-left:70px; 
                        transition-property:all; transition-duration:1s;}
   .outer10:hover > div  { width:140px; height:140px; border-radius:0px; 
                              margin-top:0px; margin-left:0px}
   .outer10:hover > div > div { margin-top:0px; margin-left:0px}

</style>
 
<div class="outer10"> 
      <div class="middle10">
          <div class="cl10">
            Sample Text
          </div>
      </div>
      Hover Here
</div>   
 
Sample Text
Hover Here

With WebGL™ and taccgl™ further circle blends are possible that deform the complete element :

(a=taccgl.actor("demo", taccgl.flexiBorder, "visible")) .from(a.x+(a.w-a.h),a.y+a.h/2,0)
.to (a.x+(a.w-a.h)/2,a.y,0) .resize(1,1,a.h,a.h) .Circle() .start()
.cont() .Rect1() .flyHome() .resize(a.h,a.h,a.w,a.h) .start()
RUN

Negative Blends

Idea is to simulate hidden visibility by moving another element in front covering the "Sample Text". The covering element gets the background-color of the neighbor elements and so is not realized by the viewer. There are many transition possibilities to make the covering element appear and disappear, below we give an example for a negative circle blend.

Note that in this example the "Sample Text" element is not contained in the middle element, but instead both elements are contained on the same level inside the outer element. Using absolute and/or relative positioning both elements are positioned on top of each other and using z-index the middle element is put on top covering the "Sample Text" element. Using border-radius the middle element is turned into a circle. This circle is, however, invisible since it has a white background color. And because it covers the "Sample Text" element nothing is visible initially.

When you hover over the element, the middle element is resized to zero using the transition to width:0px; height:0px; and so the covering circle disappears and the "Sample Text" element below appears.

<style >
   .cl9        { background-color:yellow; width:100px; padding:10px;
                      padding-top:30px; padding-bottom:30px;
                      position:relative; top:32px; left:10px}
   .middle9    { border-radius:100px; background-color:white; 
                      z-index:1; position:absolute; 
                      width:145px; height:145px;
                      margin-left:0px; margin-top:0px;
                      transition-property:all; transition-duration:1s;}
   .outer9     { width:90%; height:150px; overflow:hidden}
   .outer9:hover > div { width:0px; height:0px; 
                      margin-left:67px; margin-top:69px }
</style>
 
<div class="outer9">
      Hover Here
      <div class="middle9">
      </div>
      <p class="cl9">
           Sample Text
      </p>
</div>
 
Hover Here

Sample Text

The additional transition on margin-left:67px; margin-top:69px is needed to make the circle appear closing and opening from its center point. In other words, while the circle is shrinking it is moved down and left, so that its center point stays fixed.

Using CSS Transitions on the Transform Property to Fly In

Basic idea of this work around for visibility:hidden is to use the CSS transition property to move the element outside the document. This works nicely in newer browsers and allows for interesting animations.

For older browsers you probably need workarounds as in [1]. It is clear that for browsers like IE 8 transitions do not work. However most of the examples in the article still show and hide the elements in IE8, just without animation. This is however not the case for the two following examples (and also not for the first opacity example).

2D Example

The following examples show a fly in animation in 2D and then in 3D:

<style >
   .cl12           { width:80%; padding:10%; background-color:yellow;
      transform:translate(-1300px, 0px) rotate(180deg);
      transition-property:all;  transition-duration:5s;}
   .outer12     {  width:90%; height:100px;}
   .outer12:hover > div { transform:translate( 0px,0px); }
</style>
 
<div class="outer12">
      <div class="cl12">
            Sample Text
      </div>
      Hover Here
</div>
 
Sample Text
Hover Here

3D Example

<style >
   .cl13           { width:80%; padding:10%; background-color:yellow;
                       transform:translate3d(-300px, 20px, 2000px) rotateY(-180deg);
                       transition-property:all; transition-duration:5s;}
   .outer13     {  width:90%; height:100px; perspective:2300px;}
   .outer13:hover > div { transform:translate3d( 0px, 0px, 100px) }
</style>
 
<div class="outer13">
      <div class="cl13">
            Sample Text
      </div>
      Hover Here
</div>
 
Sample Text
Hover Here

Alternatively such an animation can be done with WebGL™ and taccgl™. This has the additional advantage of automatic lighting and shadows. Lighting simulates a virtual light source and calculates the color for every pixel of the animated element. So for instance an element that directly faces the light source appears brighter than an element that rotates away. This leads to a much more realistic rotation effect.

taccgl.a(document.body) .color("white") .shadowOnly() .dur(4) .start();
a=taccgl.actor("demo", null, "visible");<hide>taccgl.adjustEye (0, a.y, -5000); taccgl .stdLight .setPos (-200,a.y-200,-5000);</hide>
a.posZ(-100) .resizeZ() .from(-200,a.y-20,-1400).
rotateMiddle(0,1,0) .rotatePart(Math.PI,2*Math.PI) .vEnd(0,0,0) .dur(4) .start()
RUN

More Animations

Similar animation examples making elements gradually appear and disappear are found in the WebGL-HTML5 PopUp Animations blog article (e.g. the box and parts example from above) and more complex ones like the circle blend and rotating fadein are explained in the Fragment Shaders tutorial page. In addition the Parallax scrolling with 3D Acceleration article has examples useful in the context of parallax scrolling.

Conclusion

The article gave various examples on how to gradually make an HTML element visible or invisible. Some examples used CSS transitions on various other properties besides visibility and other more advanced examples were based on WebGL™. If you are interested in the WebGL™ and taccgl™ technology, we refer to our Home Page for more examples. In order to understand the examples in this article see the taccgl™ Tutorial and the taccgl™ Manual.

July 2014, revised September 2015

[1] Transitions Using Visibility and Delay

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.

Please Add a Comment or Question, click here!