Posts Tagged ‘Using CSS3 Transforms’


Box-shadow, one of CSS3′s best new features

The box-shadow property allows designers to easily implement multiple drop shadows (outer or inner) on box elements, specifying values for color, size, blur and offset.

Browser support is growing of late with Mozilla (Firefox), Webkit (Safari/Chrome/Konqueror), Opera and the IE9 Platform Preview all offering a decent implementation of the spec, although Mozilla and Webkit still require their respective -moz- and -webkit- prefixes (note Mozilla Firefox 4.0+ no longer requires the -moz- prefix).

Here’s a basic example:

In theory, the code for this is straightforward:

#example1 {
box-shadow: 10px 10px 5px #888;
}

But for the moment, as with many other ‘experimental’ CSS3 properties, you’ll need to use the following prefixes to support Mozilla and Webkit:

#example1 {
-moz-box-shadow: 10px 10px 5px #888;
-webkit-box-shadow: 10px 10px 5px #888;
box-shadow: 10px 10px 5px #888;
}

 

How it Works

The box-shadow property can accept a comma-separated list of shadows, each defined by 2-4 length values (specifying in order the horizontal offset, vertical offset, optional blur distance and optional spread distance of the shadow), an optional color value and an optional ‘inset‘ keyword (to create an inner shadow, rather than the default outer shadow).

 

The Syntax:
box-shadow: none | <shadow> [ , <shadow> ]* 

<shadow> = inset? && [ <length>{2,4} && <color>? ]

 

Examples:
box-shadow: 10px 10px;
box-shadow: 10px 10px 5px #888;
box-shadow: inset 2px 2px 2px 2px black;
box-shadow: 10px 10px #888, -10px -10px #f4f4f4, 0px 0px 5px 5px #cc6600;

 

Let’s first look at how to create a basic outer shadow, before going on to look at the inset keyword, layering multiple shadows and how to spice up your shadows with RGBa colors(?).

 

Creating a basic drop shadow

By default, shadows are drawn on the outside of elements. According to the specification;

An outer box-shadow casts a shadow as if the border-box of the element were opaque. The shadow is drawn outside the border edge only: it is clipped inside theborder-box of the element.

The first step is to define the shape of the shadow by specifying 2-4 length values.

The first value defines the horizontal offset of the shadow, with a positive value offseting the shadow to the right of the element, and a negative value to the left.

The second value defines the vertifical offset of the shadow, with a positive value offsetting the shadow from the bottom of the element, and a negative value from the top.

If supplied, an optional third value defines the blur distance of the shadow. Only positive values are allowed, and the larger the value, the more the shadow’s edge is blurred. The specification does not include an exact algorithm for how the blur distance should be calculated, however it does elaborate as follows:

…for a long, straight shadow edge, this should create a color transition the length of the blur distance that is perpendicular to and centered on the shadow’s edge, and that ranges from the full shadow color at the radius endpoint inside the shadow to fully transparent at the endpoint outside it.

An optional fourth value can be supplied to define the spread distance of the shadow. A positive value will cause the shadow shape to expand in all directions, while a negative value will cause the shadow shape to contract. The specification goes into much greater detail on how the shadow shape is calculated as follows:

If a spread distance is defined, the shadow is expanded outward or contracted inward by an operation equivalent to applying twice the absolute value of the spread value to a blur operation as defined below and thresholding the result such that for a positive spread distance all non-transparent pixels are given the full shadow color and for a negative spread distance all non-opaque pixels are made transparent. The UA may approximate this operation by taking an outward outset of the specified amount normal to the original shadow perimeter. Alternatively the UA may approximate the transformed shadow perimeter shape by outsetting (insetting, for inner shadows) the shadow’s straight edges by the spread distance and increasing (decreasing, for inner shadows) and flooring at zero the corner radii by the same amount. (The UA may even combine these methods, using one method for outer shadows and another for inner ones.) For corners with a zero border-radius, however, the corner must remain sharp—the operation is equivalent to scaling the shadow shape. In any case, the effective width and height of the shadow shape is floored at zero. (A zero-sized shadow shape would cause an outer shadow to disappear, and an inner shadow to cover the entire padding-box.)

The diagram below (taken from the W3C Backgrounds and Borders Candidate Recommendation) offers a good example of the effects of spread and blur on the shadow:

An optional color value can also be supplied, directly after the 2-4 length values, to define the shadow’s color. If not supplied, a UA-chosen default should be applied, however, whilst in Firefox/Opera/IE9 the default color is black, in Safari/Chrome (webkit) no shadow is visible unless a color is specified.

Here are a few examples of shadows with differing offsets, spread and blur.

 

Examples:

Example A shows a shadow offset to the left and top by 5px:

#Example_A {
-moz-box-shadow: -5px -5px #888;
-webkit-box-shadow: -5px -5px #888;
box-shadow: -5px -5px #888;
}

 

Example B shows the same shadow with a blur distance of 5px:

#Example_B {
-moz-box-shadow: -5px -5px 5px #888;
-webkit-box-shadow: -5px -5px 5px #888;
box-shadow: -5px -5px 5px #888;
}

 

Example C shows the same shadow with a spread distance of 5px:

#Example_C {
-moz-box-shadow: -5px -5px 0 5px #888;
-webkit-box-shadow: -5px -5px 0 5px#888;
box-shadow: -5px -5px 0 5px #888;
}

 

Example D shows the same shadow with both a blur distance of 5px and a spread distance of 5px:

#Example_D {
-moz-box-shadow: -5px -5px 5px 5px #888;
-webkit-box-shadow: -5px -5px 5px 5px#888;
box-shadow: -5px -5px 5px 5px #888;
}

 

Example E shows a shadow with no offset and a blur distance of 5px:

#Example_E {
-moz-box-shadow: 0 0 5px #888;
-webkit-box-shadow: 0 0 5px#888;
box-shadow: 0 0 5px #888;
}

 

Example F shows a shadow with no offset and both a blur distance of 5px and a spread distance of 5px:

#Example_F {
-moz-box-shadow: 0 0 5px 5px #888;
-webkit-box-shadow: 0 0 5px 5px#888;
box-shadow: 0 0 5px 5px #888;
}

 

 

Creating an inner shadow with the ‘inset’ keyword

An optional ‘inset‘ keyword can be supplied, preceding the length and color values. If present, this keyword causes the shadow to be drawn inside the element. According to the specification:

An inner box-shadow casts a shadow as if everything outside the padding edge were opaque. The inner shadow is drawn inside the padding edge only: it is clipped outside the padding box of the element.

Here are the same examples as above, this time with the ‘inset‘ keyword present.

 

Examples:

Example G shows an inner shadow offset to the left and top by 5px:

#Example_G {
-moz-box-shadow: inset -5px -5px #888;
-webkit-box-shadow: inset -5px -5px #888;
box-shadow: inset -5px -5px #888;
}

 

Example H shows the same inner shadow with a blur distance of 5px:

#Example_H {
-moz-box-shadow: inset -5px -5px 5px #888;
-webkit-box-shadow: inset -5px -5px 5px #888;
box-shadow: inset -5px -5px 5px #888;
}

 

Example I shows the same inner shadow with a spread distance of 5px:

#Example_I {
-moz-box-shadow: inset -5px -5px 0 5px #888;
-webkit-box-shadow: inset -5px -5px 0 5px#888;
box-shadow: inset -5px -5px 0 5px #888;
}

 

Example J shows the same inner shadow with both a blur distance of 5px and a spread distance of 5px:

#Example_J {
-moz-box-shadow: inset -5px -5px 5px 5px #888;
-webkit-box-shadow: inset -5px -5px 5px 5px#888;
box-shadow: inset -5px -5px 5px 5px #888;
}

 

Example K shows an inner shadow with no offset and a blur distance of 5px:

#Example_K {
-moz-box-shadow: inset 0 0 5px #888;
-webkit-box-shadow: inset 0 0 5px#888;
box-shadow: inner 0 0 5px #888;
}

 

Example L shows an inner shadow with no offset and both a blur distance of 5px and a spread distance of 5px:

#Example_L {
-moz-box-shadow: inset 0 0 5px 5px #888;
-webkit-box-shadow: inset 0 0 5px 5px#888;
box-shadow: inset 0 0 5px 5px #888;
}

 

 

Layering multiple shadows

The box-shadow property allows elements to have multiple shadows, specified by a comma seperated list. When more than one shadow is specified, the shadows are layered front to back, as in the following example.

 

Example:

Example M shows five shadows specified in the following order; firstly a black shadow with a spread distance of px and a blur distance of px, secondly a lime shadow offset to the top right, thirdly a red shadow offset to the bottom right with a blur distance applied, fourthly a yellow shadow offset to the bottom left, and lastly a blue shadow offset to the top left with a blur distance applied:

#Example_M {
-moz-box-shadow: 0 0 10px 5px black, 40px -30px lime, 40px 30px 50px red, -40px 30px yellow, -40px -30px 50px blue;
-webkit-box-shadow: 0 0 10px 5px black, 40px -30px lime, 40px 30px 50px red, -40px 30px yellow, -40px -30px 50px blue;
box-shadow: 0 0 10px 5px black, 40px -30px lime, 40px 30px 50px red, -40px 30px yellow, -40px -30px 50px blue;
}

 

 

Spicing up shadows with RGBa color & border-radius

The box-shadow property can be further enhanced using CSS3 RGBa colors to create shadows with differing levels of opacity, as demonstrated by the examples below.

 

Examples:

Example N shows a black shadow, specified using standard RGB color, offset to the right and bottom by 5px:

#Example_N {
-moz-box-shadow: 5px 5px rgb(0,0,0);
-webkit-box-shadow: 5px 5px rgb(0,0,0);
box-shadow: 5px 5px rgb(0,0,0);
}

 

Example O shows the same shadow, this time with the color black specified using RGBa color with an opacity of 70%:

#Example_O {
-moz-box-shadow: 5px 5px rgba(0,0,0,0.7);
-webkit-box-shadow: 5px 5px rgba(0,0,0,0.7);
box-shadow: 5px 5px rgba(0,0,0,0.7);
}

 

Example P shows the same shadow, this time with the color black specified using RGBa color with an opacity of 50%:

#Example_P {
-moz-box-shadow: 5px 5px rgba(0,0,0,0.5);
-webkit-box-shadow: 5px 5px rgba(0,0,0,0.5);
box-shadow: 5px 5px rgba(0,0,0,0.5);
}

 

The box-shadow property can also be applied to elements with rounded corners, created using theborder-radius property, in which case the shadow will follow the curve specified by the border-radius property (note: although IE9 seems to struggle with this).

 

Examples:

Example Q shows a shadow offset to the bottom and right by 5px, with a border-radius of 5px applied to each corner:

#Example_Q {
-moz-border-radius: 5px;
border-radius: 5px;
-moz-box-shadow: 5px 5px black;
-webkit-box-shadow: 5px 5px black;
box-shadow: 5px 5px black;
}

 

Example R shows the same shadow with a blur distance of 5px:

#Example_R {
-moz-border-radius: 5px;
border-radius: 5px;
-moz-box-shadow: 5px 5px 5px black;
-webkit-box-shadow: 5px 5px 5px black;
box-shadow: 5px 5px 5px black;
}

 

 

Browser Support

The box-shadow property has not caught on as quickly as some of its peers (such as the border-radius property) and the property was removed from the CSS3 Backgrounds and Borders specification when it reached Candidate Recommendation earlier this year, pending further development, however the property has been reintroduced in the latest version of the specification and browser support has been growing steadily of late.

The table below provides an overview of current browser support.

Browser Basic support Multiple shadows inset keyword Spread radius
Internet Explorer 9.0 box-shadow 9.0 9.0 9.0
Firefox
(Gecko)
4.0
(2.0)
box-shadow 4.0
(2.0)
4.0
(2.0)
4.0
(2.0)
3.5
(1.9.1)
-moz-box-shadow 3.5
(1.9.1)
3.5
(1.9.1)
3.5
(1.9.1)
Opera 10.5 box-shadow 10.5 10.5 10.5
Safari/Chrome
(WebKit)
3.0/1.0
(522)
-webkit-box-shadow 4.0/1.0
(528)
5.0/4.0
(533)
5.0/4.0
(533)
Browser support data courtesy of Mozilla Developer Center.

 

Additional Notes and Further Reading

The CSS3 Backgrounds and Borders specification makes the following additional notes with regard to the effect of box-shadow on layout and how it interacts with other elements:

  • Shadows do not influence layout and may overlap other boxes or their shadows. In terms of stacking contexts and the painting order, the outer shadows of an element are drawn immediately below the background of that element, and the inner shadows of an element are drawn immediately above the background of that element (below the borders and border image, if any).
  • If an element has multiple boxes, all of them get drop shadows, but shadows are only drawn where borders would also be drawn; see ‘box-decoration-break’.
  • Shadows do not trigger scrolling or increase the size of the scrollable area.
  • The ‘border-image’ does not affect the shape of the box-shadow.
  • The ‘box-shadow’ property applies to the ‘::first-letter’ pseudo-element, but not the ‘::first-line’ pseudo-element. Outer shadows have no effect on internal table elements in the collapsing border model. If a shadow is defined for single border edge in the collapsing border model that has multiple border thicknesses (e.g. an outer shadow on a table where one row has thicker borders than the others, or an inner shadow on a rowspanning table cell that adjoins cells with different border thicknesses), the exact position and rendering of its shadows are undefined.

Full details can be found in section 6.2 of the specification here.

Advertisements

3D card flipping : 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.

When hovering on the outside container, add a rotate around the Y axis to the inside container

Code

First, the markup.

<div id="f1_container">
	<div id="f1_card">
		<div>
			<img src="/images/Stones.jpg"/>
		</div>
		<div>
			<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;
}
.face.back {
	display: none;
}

#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;
}

.


Sliding with transfoms : Sliding by translating the images (transitions and transforms)

Note: Animating by transitioning transforms is hardware accelerated on iPhone OS, making this a good option there.

Plan
  1. Create a container with overflow set to hidden.
  2. Inside that container, create another container with width equal to the width of all the images added together.
  3. Inside that, float the images left with no padding or margin.

When clicking a control, translate the second container to show the required image

Code

Exactly the same as Demo 1, but the JS looks like this: (times 4 for the vendor specific markup)

$(document).ready(function() {
	$("#slide2-1").click(function() {
		$("#slide2_images").css("-webkit-transform","translate(0px, 0px)");
	});
	$("#slide2-2").click(function() {
		$("#slide2_images").css("-webkit-transform","translate(-450px, 0)");
	});
	$("#slide2-3").click(function() {
		$("#slide2_images").css("-webkit-transform","translate(-900px, 0)");
	});
	$("#slide2-4").click(function() {
		$("#slide2_images").css("-webkit-transform","translate(-1350px, 0)");
	});
});

.


Sliding by changing position : Sliding by adding padding (transitions)
Plan
  1. Create a container with overflow set to hidden.
  2. Inside that container, create another container with width equal to the width of all the images added together.
  3. Inside that, float the images left with no padding or margin.
  4. When clicking a control, change the left position of the second container to show the required image.
Code

Firstly, the mark up:

<div id="slide1_container">
	<div id="slide1_images">
		<img src="img1.jpg" />
		<img src="img2.jpg" />
		<img src="img3.jpg" />
		<img src="img4.jpg" />		
	</div>
</div>
<p id="slide1_controls">
	<span id="slide1-1">Image 1</span>
	<span id="slide1-2">Image 2</span>
	<span id="slide1-3">Image 3</span>
	<span id="slide1-4">Image 4</span>
</p>

The CSS:

#slide1_controls span {
	padding-right:2em;
	cursor:pointer;
}
#slide1_container {
	width:450px;
	height:281px;
	overflow:hidden;
	position:relative;
}
#slide1_images {
	position:absolute;
	left:0px;
	width:1800px;
	-webkit-transition:all 1.0s ease-in-out;
	-moz-transition:all 1.0s ease-in-out;
	-o-transition:all 1.0s ease-in-out;
	-ms-transition:all 1.0s ease-in-out;	
	transition:all 1.0s ease-in-out;
}
#slide1_images img {
	padding:0;
	margin:0;
	float:left;
}

Again, I’m using javascript to bind events to the clickable controls. This time I’m adding the number of pixels to slide into the js, though I could have defined classes for this.

$(document).ready(function() {
	$("#slide1-1").click(function() {
		$("#slide1_images").css("left","0");
	});
	$("#slide1-2").click(function() {
		$("#slide1_images").css("left","-450px");
	});
	$("#slide1-3").click(function() {
		$("#slide1_images").css("left","-900px");
	});
	$("#slide1-4").click(function() {
		$("#slide1_images").css("left","-1350px");
	});
});

This code could be abstracted and improved, but we are looking to keep it simple here.


Cross fading images : One image to another with a timer (Webkit/Firefox 5/IE10 only, transitions and 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 demo 1
  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
Code

Everything’s the same as Demo 1, but I’ve added this to the CSS and removed the hover selector

@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

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. It’s not great, but it is maybe a start. Any suggestions on how to make this better would be gladly received!

	#cf4a img:nth-of-type(1) {
 		animation-delay: 0;		
	}
	#cf4a img:nth-of-type(2) {
 		animation-delay: 2s;		
	}
	#cf4a img:nth-of-type(3) {
 		animation-delay: 4s;		
	}
	#cf4a img:nth-of-type(4) {
 		animation-delay: 6s;		
	}

How to use CSS3  transforms

There are two categories of transform – 2D transforms and 3D transforms. As of May 2010, 3D transforms only work in Safari (both desktop and mobile). 2D transforms are more widely supported.

2D examples

#skew {
	transform:skew(35deg);
}
#scale {
	transform:scale(1,0.5);
}
#rotate {
	transform:rotate(45deg);
}
#translate {
	transform:translate(10px, 20px);
}
#rotate-skew-scale-translate {
	transform:skew(30deg) scale(1.1,1.1) rotate(40deg) translate(10px, 20px);
}

3D Examples

3D transforms are similar to 2D transforms. The basic properties are translate3d, scale3d, rotateX, rotateY and rotateZ. Translate3d and scale3d take three arguments for x,y and z, whereas the rotates just take an angle. Here are some examples:

#transDemo4 div {
	transition:all 2s ease-in-out;
	perspective: 800;
	perspective-origin: 50% 100px;
}
#transDemo4:hover #rotateX {
	transform:rotateX(180deg);
}
#transDemo4:hover #rotateY {
	transform:rotateY(180deg);
}
#transDemo4:hover #rotateZ {
	transform:rotateZ(180deg);
}

For more information read both the Webkit blog entry from when this was first implemented, and David Desandro’s awesome examples.