Flipping Effect



Flipping a simple image to a div (transitions and 3d transforms)

Plan

  1. Put an image on top of a div inside a container.
  2. Put that in another container with perspective defined.
  3. When hovering on the outside container, add a rotate around the Y axis to the inside container.

Move Cursor On Image

Code

First, the markup.

<div
 
id
=
"f1_container"
>

<div
 
id
=
"f1_card"
 
class
=
"shadow"
>

<div
 
class
=
"front face"
>

<img
 
src
=
"/images/natureimage.jpg"
/>

</div>

<div
 
class
=
"back face center"
>

<p>
This is nice for exposing more information about an image.
</p>

<p>
Any content can go here.
</p>

</div>

</div>

</div>

Then the CSS, stripped of the vendor prefixes to keep it clean.

#f1_container {
position
:
 relative
;
margin
:
 
10px
 
auto
;
width
:
 
450px
;
height
:
 
281px
;
z
-
index
:
 
1
;

}

#f1_container {
perspective
:
 
1000
;

}

#f1_card {
width
:
 
100
%;
height
:
 
100
%;
transform
-
style
:
 preserve
-
3d
;
transition
:
 all 
1.0s
 linear
;

}

#f1_container:hover #f1_card {
transform
:
 rotateY
(
180deg
);
box
-
shadow
:
 
-
5px
 
5px
 
5px
 
#aaa;

}

.
face 
{
position
:
 absolute
;
width
:
 
100
%;
height
:
 
100
%;
backface
-
visibility
:
 hidden
;

}

.
face
.
back 
{
display
:
 block
;
transform
:
 rotateY
(
180deg
);
box
-
sizing
:
 border
-
box
;
padding
:
 
10px
;
color
:
 white
;
text
-
align
:
 center
;
background
-
color
:
 
#aaa;

}


Flipping around other axes

You can also flip around the X and Z axes by changing rotateY to rotateX or rotateZ.

This is nice for exposing more information about an image.

Any content can go here.



Commonly used as part of image galleries, or to show detail on products. This has traditionally been done in javascript by iterating over the opacity - using CSS transitions makes this very easy to add to your site.

Demo 1 - One image to another, on hover

Plan

  1. Put one image on top of the other
  2. Change the opacity of the top image on hover

Demo

Code

First up, the HTML markup. Without CSS enabled, you just get two images. Remember to add alt text for production use.

<div
 
id
=
"cf"
>

<img
 
class
=
"bottom"
 
src
=
"/css/001.jpg"
 
/>

<img
 
class
=
"top"
 
src
=
"/css/002.jpg"
 
/>

</div>

Then the CSS:

#cf {
position
:
relative
;
height
:
281px
;
width
:
450px
;
margin
:
0
 
auto
;

}

#cf img {
position
:
absolute
;
left
:
0
;

-
webkit
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;

-
moz
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;

-
o
-transition: opacity 1s ease-in-out;
  transition: opacity 1s ease-in-out;
}

#cf img.top:hover {
  opacity:0;
}

Demo 2 - One image to another, when a button is pressed (transitions)

Plan

Same as before, but instead of using the :hover pseudo class, we are going to use javascript to add a toggle a class. I'm using jQuery here because it's easy to understand, though you could just use plain old JS.

Demo

Click me to toggle

Code

First up, the HTML markup. Again, with no CSS enabled, you just get two images.

<div
 
id
=
"cf2"
 
class
=
"shadow"
>

<img
 
class
=
"bottom"
 
src
=
"/css/001.jpg"
 
/>

<img
 
class
=
"top"
 
src
=
"/css/002.jpg"
 
/>

</div>

<p
 
id
=
"cf_onclick"
>
Click me to toggle
</p>

Then the CSS. I've added a class with the opacity value.

#cf2 {
position
:
relative
;
height
:
281px
;
width
:
450px
;
margin
:
0
 
auto
;

}

#cf2 img {
position
:
absolute
;
left
:
0
;

-
webkit
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;

-
moz
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;

-
o
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;
transition
:
 opacity 
1s
 ease
-
in
-
out
;

}

#cf2 img.transparent {
opacity
:
0
;

}

#cf_onclick {
cursor
:
pointer
;

}

Then the extremely short JS. Note that the browser is smart enough to realise that it can animate to the new properties, I didn't have to set them in javascript (thought that works too).

$
(
document
).
ready
(
function
()
 
{
$
(
"#cf_onclick"
).
click
(
function
()
 
{
$
(
"#cf2 img.top"
).
toggleClass
(
"transparent"
);

});

});

Demo 3 - One image to another with a timer (CSS animations)

Plan

You could implement this by using Javascript to toggle classes with a delay - that would allow older browsers to still have the images change. As we are looking forward though, we'll use CSS keyframes.

  1. Start with two images absolutely positioned on top of each other.
  2. Use CSS keyframes to define two states, one with top image transparent, one with it opaque.
  3. Set the animations number of iterations to infinite.

Demo

Each image is visible for 9 seconds before fading to the other one.

Code

  
@keyframes
 cf3FadeInOut 
{

0
%
 
{
opacity
:
1
;

}

45
%
 
{
opacity
:
1
;

}

55
%
 
{
opacity
:
0
;

}

100
%
 
{
opacity
:
0
;

}

}

#cf3 img.top {
animation
-
name
:
 cf3FadeInOut
;
animation
-
timing
-
function
:
 ease
-
in
-
out
;
animation
-
iteration
-
count
:
 infinite
;
animation
-
duration
:
 
10s
;
animation
-
direction
:
 alternate
;

}

To make sense of that, I've defined 4 keyframes, specified that whatever has this animation attached will be opaque for the first 45%, then transparent for the last 45%. The animation will repeat forever, will last 10 seconds, and will run forward then backwards. In other words, image 1 will be visible for 4.5 seconds, followed by a 1 second fade, followed by 4.5 seconds of image 2 being visible. Then it will reverse, meaning that image 1 and 2 will both be visible for 9 (4.5 x 2) seconds each time.

Demo with multiple images

Staggering the animations can result in a multiple image fader.

This time I've created an animation that goes from 0 to 1 opacity, then staggered the animations so only one is visible at once.

Thanks to Pafson's comment, this is finally working as expected! He proposes the following algorithm to determine the percentages and timings:

For "n" images You must define:
a=presentation time for one image
b=duration for cross fading
Total animation-duration is of course t=(a+b)*n

animation-delay = t/n or = a+b

Percentage for keyframes:

  1. 0%
  2. a/t*100%
  3. (a+b)/t*100% = 1/n*100%
  4. 100%-(b/t*100%)
  5. 100%
@keyframes
 cf4FadeInOut 
{

0
%
 
{
opacity
:
1
;

}
  
17
%
 
{
opacity
:
1
;

}
  
25
%
 
{
opacity
:
0
;

}
  
92
%
 
{
opacity
:
0
;

}
  
100
%
 
{
opacity
:
1
;

}

}

#cf4a img:nth-of-type(1) {
animation
-
delay
:
 
6s
;

}

#cf4a img:nth-of-type(2) {
animation
-
delay
:
 
4s
;

}

#cf4a img:nth-of-type(3) {
animation
-
delay
:
 
2s
;

}

#cf4a img:nth-of-type(4) {
animation
-
delay
:
 
0
;

}

Demo 4 - More than just fades

This technique isn't limited to just fades, you can animate almost every property. Here are a couple of examples.

Zooming in and out

Hover on the image

Rotation

Hover on the image

Demo 5 - Animating the background-image property

Right now this only works on webkits built from 2012 onwards. It's not part of the spec (yet?).

Plan

  1. Make a div with a width and height
  2. Change the background-image property

Demo

Code

This only works on Chrome 18+ and on Webkit built in 2012 onwards, including iOS6. It seems to be a side effect of the CSS4 crossfading work, though this is a lot more useful.

<div id="cf6_image" class="shadow"></div>

Then the CSS:

#cf6_image {
margin
:
0
 
auto
;
width
:
450px
;
height
:
281px
;
transition
:
 background
-
image 
1s
 ease
-
in
-
out
;
background
-
image
:
url
(
"/css/001.jpg"
);

}

#cf6_image:hover {
background
-
image
:
url
(
"/css/002.jpg"
);

}

Pretty cool - this can easily be extended by simply changing the background-image property with JS, and makes things much much simpler. I'm not sure if this behaviour is part of the spec or not, and I haven't seen support anywhere other than in the afore mentioned browsers.

Demo 6 -Fading between multiple images on click

Image 1 Image 2 Image 3 Image 4

This is very similar to the others – just layout the images on top of each other, set them all to be transparent, then when the controls are clicked change that one to opaque.

For this example:

HTML

<div
 
id
=
"cf7"
 
class
=
"shadow"
>

<img
 
class
=
'opaque'
 
src
=
"/css/004.jpg"
 
/>

<img
 
src
=
"/css/001.jpg;"
 
/>

<img
 
src
=
"/css/002.jpg;"
 
/>

<img
 
src
=
"/css/003.jpg;"
 
/>

</div>

<p
 
id
=
"cf7_controls"
>

<span
 
class
=
"selected"
>
Image 1
</span>

<span>
Image 2
</span>

<span>
Image 3
</span>

<span>
Image 4
</span>

</p>

CSS

p
#cf7_controls {
text
-
align
:
center
;

}

#cf7_controls span {
padding
-
right
:
2em
;
cursor
:
pointer
;

}

#cf7 {
position
:
relative
;
height
:
281px
;
width
:
450px
;
margin
:
0
 
auto
 
10px
;

}

#cf7 img {
position
:
absolute
;
left
:
0
;

-
webkit
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;

-
moz
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;

-
o
-
transition
:
 opacity 
1s
 ease
-
in
-
out
;
transition
:
 opacity 
1s
 ease
-
in
-
out
;
opacity
:
0
;

-
ms
-
filter
:
"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"
;
filter
:
 alpha
(
opacity
=
0
);

}

#cf7 img.opaque {
opacity
:
1
;

-
ms
-
filter
:
"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"
;
filter
:
 alpha
(
opacity
=
1
);

}

JS

$
(
document
).
ready
(
function
()
 
{
$
(
"#cf7_controls"
).
on
(
'click'
,
 
'span'
,
 
function
()
 
{
$
(
"#cf7 img"
).
removeClass
(
"opaque"
);

var
 newImage 
=
 $
(
this
).
index
();
$
(
"#cf7 img"
).
eq
(
newImage
).
addClass
(
"opaque"
);
$
(
"#cf7_controls span"
).
removeClass
(
"selected"
);
$
(
this
).
addClass
(
"selected"
);
 
});

});