A couple of weeks ago we started a series on how you might implement some of the more notable design effects in iOS 7 using purely web technologies. In the meantime, it’s been noted elsewhere that this may be difficult and perhaps impossible to do. I’m here today to tell you otherwise! Well, at the […]
CSS Filters are a powerful tool available in all modern browsers to bring amazing photographic effects to web content. If you’re not using them, you should be – here’s how! Like what you see? Want a piece of the action next time around? Then get along to Web Directions South in Sydney October 24 and […]
In this session, we’ll take a look at all of the possibilities and explore what works and where — from the simplest effects, to creative usability enhancements including the combination of CSS with mobile Javascript frameworks.
One of the most powerful features of CSS3 are transforms, which allow us to take any element in an HTML document, and while not changing its effect on the page layout, rotate it, translate it (move it left, right, up and down), skew it and scale it. CSS3 provides both 2D and 3D transforms, but while 2D transforms are supported in all modern browsers, including IE9 and up, 3D transforms are currently only supported in Safari, Chrome and IE10.
In this article, we'll take a look at how to use 2D transforms and the various transform functions (such as scale and rotate). We'll also, as always, look at some gotchas when first working with transforms, and once again, there's a tool to help you play with transforms (I developed it some time ago, but I've updated it significantly for this article).
What transforms do
As in many cases, an example is worth a thousand words, so let's take a look at a couple, to illustrate how transforms work, as well as some of their most important aspects.
When you click or tap the button below, this paragraph is rotated by 45 degrees. It's also scaled to 75% of the size it would otherwise be. However note how the rest of the page layout is not affected. That's because transformations don't change the box model of an element, and so leave the page layout unchanged.
This element has been skewed horizontally and vertically. You can still select the text, and otherwise interact with the element, as you would if it weren't transformed.
Transforming elements
The syntax for CSS transforms is in many ways straightforward. There are just two new properties to contend with - transform, and transform-origin. The first specifies the transforms we want applied (scaling, rotating and so on), while the second, which is optional, specifies the origin for this transformation (for example, do we rotate around the middle of the element, its top left hand corner, and so on).
The transform property
The transform property takes as its value one or more transform functions, which each specify a transformation. Let's take a look at each of these different functions in detail. Functions all take the form of a function name, with a value inside round brackets (as indeed do all CSS functions). So for example, we translate horizontally with the function translateX(200px).
OK, enough preliminaries, let's start in with some actual transforming. We'll start with the translate function.
translate
The translate function moves the contents of an element to the left (negative values) or right (positive values), and/or upwards (negative values) and downwards (positive values).
translate takes one or two comma separated values. The first is the horizontal translation value. If there is a second, this is the vertical translation value, while if there is only one value, then the vertical translation is zero (that is, the element will only be translated horizontally).
In addition to the translate function, there are the related translateX and translateY functions, which only translate an element horizontally, or vertically, respectively. Translate functions take length or percentage values, and like CSS properties, require units for values other than zero.
But enough theory, why not have a play with them?
transform: translate(0, 0)
We mentioned a moment ago that transforms don't impact the layout of a page. There's one area where this is not exactly true. If you translate the above element completely to the right, you'll notice a horizontal scrollbar appears (or the page can now be scrolled to the right). While the page layout has not been changed, the overflow property of the transformed elements containing element is affected by transforms (Safari on Mac OS X Lion is an exception to this, and perhaps indicates where this sort of UX is headed, but for now, in desktop/laptop browsers other than this, the addition of a scrollbar will impact page layout).
This element is scaled by 200% when you click the button below. Its containing div has an overflow: auto. So, scrollbars appear when the element is transformed. In many browsers this will cause the page to reflow.
scale
The scale function lets us zoom an element up or down in size (all the while maintaining the dimensions of its box for the purposes of the layout of the page). The function name is scale, and it takes a number value-with a value of .5 meaning "scale to half the current size", and of 2 meaning "scale to twice the current size", and so on. So, if we want to make an element 75% of its current size, we use the property transform: scale(.75). And that's really all there is to it. Why not have a play with it?
transform: scale(1)
It's also possible to scale horizontally and vertically independently from one another, by using two comma separated numerical values for the scale property. The first value scales an element horizontally, and the second, vertically. Let's take a look.
transform: scale(1, 1)
As with translate there are two related scale functions, scaleX, and scaleY. scaleX scales only horizontally (scaleX(2) is the equivalent of scale(2, 1)), and scaleY, which scales only vertically (scaleY(2) is the equivalent of scale(1, 2)).
rotate
Rotating text and images is a common page design technique, until now difficult to achieve on the web without considerable hackery, if at all. Transforms make rotating an element easy.
The rotate function takes an angle value. If you've worked with CSS linear gradients, in particular the newer syntax, then you'll have seen angle units before. There are several ways you can specify an angle in CSS.
degrees
As you most likely remember from school math, there are 360 degrees in a circle. So, when specifying a rotation of an element, 90 degrees is a quarter turn clockwise, 180 degrees is a half turn, 270 degrees is three quarters turn clockwise, and 360 degrees is a full revolution. Here these are below.
Of course, it is possible to rotate an element by an arbitrary angle, for example 34.6 degrees, like so
rotate(34.6deg)
But, there are other ways we can specify rotations.
turns
perhaps the simplest way to specify a rotation is with the turn value. We can rotate an element a quarter turn clockwise with the function rotate(.25turn), half a turn with .5turn, three quarters of a turn with .75 turn, and a whole turn with the function rotate(1turn). WebKit and Opera support the turn value, while Firefox (version 6) does not.
For completeness, it's worth noting that there are two other possible angle units-radians (rad), and gradians (grad). Briefly, there are 400 gradians in a full rotation (so one grad is slightly larger than one degree), while there are 2π radians in a full rotation (radians are widely used in mathematics).
Now, if you think about rotating an element, then you might wonder what point of the element the rotation takes place around. For example - is it the center? Or one of the corners?
This element rotates around the top left hand corner when you click or tap and hold it. (transform: rotate(360deg))
We can in fact specify where the rotation (and as we'll soon see, any transformation) takes place, using the transform-origin property. transform-origin takes two length or percentage values, which specify the horizontal and vertical "origin" of the transformation. In the above example, we have transform-origin: 0 0. If we want to rotate around the center of the element, we use transform-origin: 50% 50%, while to rotate around the bottom right of the element, we use transform-origin: 100% 100%.
This element rotates around the center of the element (transform-origin: 50% 50%; transform: rotate(360deg)).
This element rotates around the bottom right hand corner of the element (transform-origin: 100% 100%; transform: rotate(360deg)).
(You might be able to guess that we can animate transformation changes, like we can most other CSS property changes using CSS Transitions. For more on this, see my article on CSS transitions and animations.)
So, let's now put rotations and transform origin together so we can play around with them.
transform: rotate(0);
transform-origin: 0 0
transform-origin can also be specified with keywords, in place of percentage (or length) values. As with background-position we can use left, center or right for the horizontal origin position and top, center or bottom for vertical. Where only one value is used, this applies to the horizontal origin, and the vertical is 50% (or center). Where no transform-origin is specified, its default value is 50% 50%.
skew
the last of the 2 dimensional transform functions is skew. Skewing is typically explained in mathematical terms, but if you recall a little school geometry, it isn't really that complicated. Horizontal skew (the skewX function) takes the box of an element, and while the top and bottom edges remain horizontal, tilts the left and right edges by the specified number of degrees to create a parallelogram. Similarly, a vertical skew (skewY), leaves the left and right edges vertical, and creates a parallelogram with the top and bottom edges rotated by the specified number of degrees. And when you skew both horizontally and vertically, you combine both of these (where it can get really quite tricky to work out what's going on). Does that help? You can play with the values below to get a sense of how skewing works in practice, including how it can create apparent 3D effects.
The skew function, like most other functions, takes one or two values. As with rotate, they are angle values, and where there are two values, they are comma separated.
transform: skew(0, 0)
Once again, as with a number of the other transform functions we've seen, there are two related functions - skewX and skewY, which each skew only in one dimension, and which take only a single, angle value.
Complex transformations
While you'll likely never need to use it, underneath all these functions is the core of CSS transformations, based on the mathematical concept of a transformation matrix. Each of the functions we've seen can be represented by a matrix value. While it's firmly in the domain of mathematics, we can for example represent the function scale(1.5,1.2) by the matrix
1.5 | 0 | 0
0 | 1.2 | 0
0 | 0 | 1
and directly apply this matrix value using the matrix function, like so
transform: matrix(1.5, 0, 0, 1.2, 0, 0)
this element has been scaled using a matrix function on the transform property.
It's possible to apply multiple transform functions at once to an element. For example we can rotate, translate and skew an element with the single transform property:
Click the button below to apply several transformation functions simultaneously, with the property transform: scale(0.75) rotate(45deg) translate(132px, -149px) skew(32deg, -32deg);
Hand coding transforms, as with much to do with CSS3, is an increasingly complex process. Not only is there a good deal of syntax to remember often for quite straightforward effects, but the outcome of at least some transforms isn't necessarily obvious to most of us simply by looking at the CSS. So, to help you learn, and explore, CSS transforms, I've developed a 2D transform tool (there's a 3D one as well, but we'll cover 3D in a later article).
If you're keen to explore transformations in more detail, and how they can be made to work together, head over and take a look, and as always, let me know what you think via twitter.
Gotchas, tips and tricks
Its fair to say that while now widely supported in modern browsers, 2D CSS transforms are still experimental, and quite quirky. Here are some of the difficulties you might encounter, and some tips and ideas for working with 2D transforms.
vendor specific prefixes
Reflecting the experimental nature of transforms, all browsers require vendor specific prefixes for the transform and transform-origin properties (note that function names are not prefixed). As all modern browsers including IE9 and up support 2D CSS transforms, using these transformation properties can get more than a little unwieldy. For example, the CSS for a simple rotation around the center of an element, if we include all vendor specific properties, would be something like:
img{
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg); //always include a standard for last
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
You might find the use of a CSS preprocessor like LESS or SASS worth exploring, as they can make stylesheets far more manageable when you use a lot of vendor prefixing.
Transforming inline elements in webkit
According to the current version of the specification, CSS Transforms should be applied to inline, as well as block elements, but while Opera and Firefox both correctly apply transforms to inline elements, WebKit browsers (Safari 5.1, Chrome 15) currently don't.
A workaround for this is to give inline elements which are to be transformed display: inline-block, which won't affect how they are laid out in the page, but will enable these browsers to transform them.
Translating rotated content
One subtle aspect of multiple transformations is that functions are performed in sequence - from first to last in the list. The order that you specify functions can make a difference. Take a look at the following paragraphs. Both have the same scale, rotate and translate functions applied. But, in the first, the element is translated to the right, while in the second, it is translated to the left. What's going on?
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) rotate(180deg) translate(-100px,0)
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) translate(-100px, 0) rotate(180deg)
Transformations don't take place in an absolute coordinate space. Rather, "up", "down", "left" and "right" are relative to the current rotation (but not skew) of the element. So, if an element is rotated half a turn, and so is "upside down" then translate(0, -100px) moves it down the page 100px. If it's rotated a quarter turn to the right, it's moved to the left. Similarly, translating "horizontally" is always relative to the element. So, if it's rotated by 180 degrees, then translate(100px, 0) moves the element to the left. In short, the X and Y axes of a transformation are relative not to the page, but the element's current rotation.
Interacting with transformed content
While the box of an element isn't changed by a transformation, elements that are transformed display various quirks when it comes to mouse events in various browsers, most likely due to the still experimental nature of transformations. Take the element below. It rotates a quarter turn clockwise when the mouse is over it, and then back to its original rotation when the mouse is out of it.
Now, if the box of the element isn't changed, then when rotated, hovering over any of the image which is outside that original box should not trigger a mouseover event, and so the element should rotate back to its original position. However, as makes intuitive sense, hovering over those parts of the rotated element that are outside the original box does cause mouseover events to be fired. But in addition, mouseover events are also fired when you hover over that part of the element's original box which no longer has content because it has been rotated away. And if you move your mouse around the element, you'll find in all browsers various locations where the rotation abruptly, though unintuitively, changes. Similar behavior can be observed for translation and other transformations.
In light of this, I'd suggest being extremely wary of transforming elements which users will interact with given the current state of browser support for transformations.
Overflowing and transformations
We mentioned earlier that while transformations don't effect the box model of an element, and so leave the layout of a page untouched, they do effect the overflow, and if we have overflow: auto, they can in fact impact the page flow.
In the element below, we have an image inside a div. The div has an overflow:auto. When we hover over the element (apologies to touch device users), the contained image scales up in size.
Now, in most browsers on most platforms (Safari on Mac OS X 10.7 is an exception) the browser adds a horizontal scrollbar to the div when you hover over the image, which adds to the height of the element, reflowing the page below it. Just something to be aware of.
It has to do with the positioning of elements. When we absolutely or fixed position an element, and give it say a top and left, these positions are offset from their containing box - which is not necessarily their parent element. Rather, the containing box is the first ancestor which itself has either relative, absolute or fixed position. However, adding a transform to an element also makes it a containing block for its descendent elements! As Eric observes, this can particularly cause difficulties with fixed positioning. Rather than rehash Eric's detailed thoughts, I'll let you head over and read them first hand.
General Rendering Problems
On different browsers you'll find various rendering problems with transformed content. For example, with Opera, rotated text appears to be rendered in a lighter font than the same text when it isn't rotated. I've also seen redrawing problems when rotating text in WebKit browsers. In Safari on iOS 4, rotated text doesn't necessarily align smoothly along its baseline. None of these are necessarily deal breakers, but it's worth keeping in mind. Transforms are still experimental, so don't necessarily expect them to be perfectly supported in all circumstances just yet.
Hardware Acceleration
There's a widely held belief that at least some browsers hardware accelerate the rendering of CSS transformations (hardware acceleration involves the CPU handing off execution of certain types of calculation to the GPU, which can increase rendering performance significantly, particularly on mobile devices).
At present the current state of hardware acceleration for CSS transforms across all browsers and devices is difficult to pin down. A webkit engineer I tracked down confirmed that current versions of Safari (5.1 on the desktop, iOS 4), but not necessarily other WebKit browsers:
animated 2D transforms in Safari are always hardware accelerated
using 3D for static 2D transforms may improve performance, but may also increase memory use - a real issue for memory limited mobile devices in particular
Now, haven't we just spent however much effort covering 2D transforms? How could this possibly help? Well, as we'll see in an upcoming article on 3D transforms, we can use 3D transforms to do 2D transforms (for example, there's rotate3D). If squeezing maximum performance for iOS devices is a need, then it may be that using a 3D version of a transform will help.
It's also worth noting that issues around what aspects of CSS transforms are hardware accelerated and how that acceleration works are implementation details in specific browsers, and not specified as part of CSS Transforms. As such, across browsers there's likely to be little uniformity of approach to hardware acceleration, and even from one version of a browser to the next, approaches may change.
Backwards Compatibility
One of the strongest aspects of CSS3 features like gradients, border-radius, shadows and the like is that they have been typically designed so as to be easily used in a way that is backwards compatible almost automatically, or provided we keep a small number of potential challenges in mind. For example, with gradients we need to ensure we have a fallback background color or image for when gradients aren't supported. For text-shadow, we need to ensure that the contrast between the text and the element background is sufficient when the shadow is not drawn.
Of all new CSS3 properties, transform is the one where backwards compatibility is the most difficult to ensure. Ironically, it's precisely because transforms don't affect the page layout that they cause such difficulty. For example, in order to accommodate say a heading rotated 90 degree to run horizontally along the left hand side of the text which follows it, we need to create whitespace to ensure the heading does not overlap the text. We might do that with margin, or padding. We're also likely to want to remove the whitespace where the heading has been rotated away from, by, for example, using negative margin on the paragraph following the heading. But, what happens if transforms aren't supported? The heading text will be overlapped by the paragraph below it.
In order to use transforms for more sophisticated page layout along these lines, a solution like Modernizr, which enables different CSS to be applied based on the support, or absence of support for various CSS3 features like transforms is indispensable.
Transformations are typically most easily used in a way that is backwards compatible where animated transforms create a transition between states in an application. We're all most likely used to sliding or flipping transitions between states in iOS and other mobile apps. CSS transforms can be used for these transitions, in conjunction with CSS Transitions, and where transforms aren't supported (in which case it's unlikely transitions will be as well), your users simply see an abrupt change in state.
However you plan to use transforms, as with every other aspect of web development, keep in mind those browsers which don't support them, and ensure your user's experience isn't diminished to the point where information or functionality is denied them because their browser doesn't support it.
Browser Support
As we mentioned, despite the still rather experimental nature of support for CSS 2D Transforms, they are now widely supported in modern browsers including:
Internet Explorer 9 and up
Firefox 3.5 up
Safari 3.2 up
Chrome 10 and up
Opera 10.6 and up
iOS 3.2 and up
Opera Mobile 11 and higher
Android 2.1 and up
So, support is widespread, and constantly improving. While there are definitely challenges associated with using 2D Transforms, they're a powerful, and worthwhile addition to the repertoire of developers, and will only gain in value. What are you going to do with them?
A couple of weeks ago we started a series on how you might implement some of the more notable design effects in iOS 7 using purely web technologies. In the meantime, it's been noted elsewhere that this may be difficult and perhaps impossible to do. I'm here today to tell you otherwise! Well, at the least the impossible part.
Today we are going to look at one of the features that got some attention, the use of parallax on the homescreen to create a sense of depth This is one of the words that Apple used to describe their new, supposedly "flat" design.
If you've not seen this in action, Gizmodo took Apple's video and made an animated GIF version, which you can see below.
It got me thinking, how did they do that? How easy would it be to replicate using web technologies?
We've all seen parallax effects before. They're a staple of 2D, and "2.5D" games, to add the perception of distance between objects. For the last couple of years we've also seen the use, and abuse, of parallax and scrolling in web page design.
So, what is going on to create what appears at a glance to be a 3rd dimension? Well I'll let you in on a little secret that anyone who has installed the iOS 7 beta will have already noticed. The effect is particularly impressive when viewing a 2D rendering (such as a video) of the effect. When you see the same effect on a device, and then watch a video of the effect on the device, I think you'll find the video more compelling.
What is parallax?
Look out the window. Objects at different distances move at different relative speeds. The closer an object, the more quickly it appears to be moving, and the further away it is, the more slowly it appears to be moving.
Documentary film makers, who often have only photographs or paintings to use as their primary visual material, commonly make use of this to trick our eyes into seeing a 3rd dimension. It's called "the Kid Stays in the Picture" effect. It tricks our brain that we are looking at a 3D scene, by using different relative motions.
In the iOS 7 homescreen situation, we have two levels of depth. The surface of the screen, and the background image. If you pay attention to the animated version, you'll see that the icons don't move relative to the surface of the screen. The effect is created purely by moving the background image relative to the icons. Notice how as we tilt the phone from right to left (on the screen) the background image moves toward the right, and as the phone tilts from left to right, the image moves back to the left. Why does this create a sense of depth? For the moment, to keep things simple let's just worry about rotation around a line running from the top to the bottom of the screen through its middle as the device is facing toward us. That is, when we tilte the phone left and right.
Imagine we were looking down on the scene from above
The vertical arrow is the line of sight. Now, let's rotate the phone to the left
I cheated a bit here, to make the maths a little bit simpler, but the idea is more or less the same. Instead of the device rotating, I've moved the observer, but their line of site is still the same - directly between the two icons in the middle of the screen. So, the icons don't appear to move relative to the screen, but the background figures do. But just how far are the figures apparently shifted?
I'm making the observation that the original, and adjusted lines of sight of the viewer make a right-angled triangle. Which is excellent, because the trigonometry (don't be put off!) of right-angled triangle is simpler than arbitrary triangles.
OK, so if your high school maths is a little rusty (don't worry, I have a degree in mathematics and I had to look this up!) here's what we have.
We have the original line of sight (we've labelled that a, which you might remember as being the adjacent side.
We have our new line of sight, labelled h for hypotenuse
we have the angle between the old and new lines of sight, θ (pronounced theta, for some reason, angles are usually labelled using Greek letters).
We have the distance at right angles from the hypotenuse to the adjacent side, labelled o for opposite (because it is the side opposite the angle we know, θ)
And we have enough information to calculate o, should we know the length of a, using our high school trig
o = a*tan(θ)
We know θ, it's the angle we've rotated the screen (and we'll see in a moment how we'll use the deviceOrientation event to get this angle as it changes). But how do we know a? Well, here's the cool part, we just make it up. The larger the value of a, the further 'away' the background figures will appear to be (so the larger o will be.) In particular what this means is the relative movement of the background figures behind the icons is not linear, but goes something like this, where the background is 50px away
degrees
apparent movement (px)
0
0
5
4
10
9
15
13
20
18
25
23
30
29
35
35
40
42
45
50
50
60
55
71
60
87
65
107
70
137
75
187
80
284
85
572
90
∞
Note how the movement left or right increases dramatically as we get closer to θ = 90 degrees. Of course it can never be 90 degrees.
In short, the more we rotate the device, the more the background image appears to move.
Creating the effect
So, now we have a basic model for how parallax works, how can we use this to emulate the parallax effect? Here's my idea
we'll have an element that emulates the homescreen of the device
the homescreen element contains the application icons
we'll have a background image for that element, like the one in Apple's animated example.
Now we have our basic content
when the device rotates to the right, we calculate how far to the left our background image should move, which will change depending on how far "away" we want the background to be
when the device rotates to the left, we calculate how far to the right the background should move
we then use background-position to move the background image relative to the element.
There are other ways we could do this, with their own advantages. We could have the background as a separate img element, then use CSS3 translate3D to move this element to the left and right. This would have the advantage of enabling the device's GPU to take care of moving the background. But we'll stick to background-position, as it's the simplest approach.
So, here's our basic HTML
<section id="homescreen">
<figure id="app1">
<img src="images/app1.png">
<figcaption>App 1</figcaption>
</figure>
<figure id="app2">
<img src="images/app2.png">
<figcaption>App 2</figcaption>
</figure>
<figure id="app3">
<img src="images/app3.png">
<figcaption>App 3</figcaption>
</figure>
<!-- and so on -->
</section>
Yes, not particularly interesting, yet. Now let's think about moving the background image.
By default, a background image is positioned with its top left hand corner in the element's top left hand corner. But this isn't what we'll want, because as soon as we rotate to the left, the image moves to the right, and so we'll see "through" the element on the left of the background image like so.
So we'll need to make sure that our image is wider than our element, and positioned not in the top left hand corner. We could use the CSS3 property background-size to achieve the first, but we need to be careful. Suppose we decided to make the width of any background image 150% the width of the element. We'd use background-size: 150% to do this, but this then scales the height of the element to maintain the image's proportions. For an image that is inherently narrower than the element's current size, then the height will increase. But if the image is inherently wider than 150% of the width of the element in pixels, then the height of the image will decrease, and we may end up with this situation.
Better to have an image that will in all likelihood be taller and wider than the element's width and height (yes, in a responsive world, this will present its own challenges).
The second part is a bit more straightforward. Surely, we'll just use background-position: center? Sadly, not quite so simple. Because we'll be changing the background-position to achieve the effect. So, what we do is position the background image using JavaScript and the DOM, so that its top is half the difference between its intrinsic height and the current height of the homescreen element above the top of the element, and similarly, its left is half the difference between its width height and the current width of the homescreen element to the left of the element. Essentially, the center of the image will be in the center of the element.
We'll do this by adjusting the background-position of the element once the page has loaded (as is often the case, this is the most complicated part of the process, even though it's only peripheral.)
function setupBackgroundImage(element) {
//set up the background image for the element
//call this when the page loads
var imgURL = window.getComputedStyle(element).backgroundImage
//get the current background-image URL
//bg image format is url(' + url + ') so we strip the url() part
imgURL = imgURL.replace(/"/g,"").replace(/url\(|\)$/ig, "");
//now we make a new image element and set this as its source
var theImage = new Image();
theImage.src = imgURL;
//we'll set an onload listener, so that when the image loads, we position the background image of the element
theImage.onload = function() {
positionBackgroundImage(element, this.width, this.height)
}
}
function positionBackgroundImage(element, imageWidth, imageHeight) {
//this is called when a backgroundImage loads
var elRect = element.getBoundingClientRect();
xOffset = -1 * (imageWidth - elRect.width)/2
yOffset = -1 * (imageHeight - elRect.height)/2
//these are global variables as we want to remember the offsets for later
//ideally we'd not use global vars, but done like this for simplicity
element.style.backgroundPosition = xOffset + "px " + yOffset + "px"
}
Now we've set up our elements, our homescreen background image, and we've worked out our algorithm, we're ready to go.
Adjusting the background image
OK, at this point, we'll pretend we already know the current rotation of the device (we'll cover how we get that next). Let's assume that each time the device changes its orientation we get an event. Which in fact is exactly what happens. We'll create an event handler for this event. As we're responding to a change in the orientation, we'll call this 'orientationChanged'. Here's what this will need to do (again we'll concentrate on just the rotation around the Y axis of the device to keep things simple)
calculate the tan of the rotation around the Y axis (in radians, not degrees) (this was θ in our earlier discussion). More on radians in the notes
calculate the relative movement of the background image (a*tan(θ))
adjust for the xOffset we calculated earlier based on the width of the background image and the element
set the background-position of the element to this value
And here's that in JavaScript
function orientationChanged (xOrientation, yOrientation) {
var rotYTan = Math.tan(yOrientation*(Math.PI/180))
//calculate the tan of the rotation around the Y axis
//Math.tan takes radians, not degrees as the argument
var backgroundDistance = 50
//set the distance of the background from the foreground
//the smaller, the 'closer' an object appears
var xImagePosition = (-1 * rotYTan * backgroundDistance) + xOffset + "px"
//calculate the distance to shift the background image horizontally
//the X and Y seem swapped, but X in device rotation terms is around a line through the middle of of the screen from left to right, so its correct
homescreen.style.backgroundPosition = xImagePosition + " " + 0;
//set the backgroundimage position to xImagePosition
}
So, now we are moving the background image left or right depending on the rotation of the device. But how well does this work? Well, you can test it out yourself. Here's an emulation, which uses CSS 3D transforms, as well as a version you can run directly in a device. What do you think? In the emulated version, you might think the 3D effect is simply coming from the use of CSS 3D, but if you set the distance to zero, and then rotate the device, you'll see that there is no parallax effect. The greater the distance you set, the more pronounced the effect.
The main event
But so far, we've not discussed how we actually get this mystical orientation information. As we mentioned briefly we'll be using the deviceOrientation event widely supported in mobile devices in particular.
I covered DeviceMotion and DeviceOrientation in some detail recently when I built a motion activated security camera in the browser, so we'll not go into the details of DeviceOrientation here. In short though
alpha is the rotation around the z-axis (an imaginary line coming directly out of the screen). Positive alpha is rotated to the left, negative alpha is rotate to the right. This seems counter intuitive, but our frame of reference is looking upwards, so to the left is clockwise in this frame of reference, and clockwise is positive, anti-clockwise negative.
beta is rotation around the x-axis, a line left to right across the device when it is laid flat on its back. Positive beta is when the device is tilted away from you, from 0 degrees to 180 degrees (screen facing downwards). Negative alpha is when the device is tilted toward you (again, from 0 degress to -180 degrees, which is facing downward)
gamma is rotation around the y-axis, a line through the middle of the device away from the user. Positive (from 0 to 180 degrees) is tilted to the left. Negative, 0 to -180 degrees, is tilted to right
Which is all a lot easier to understand with a picture.
Here's how we'll use this information
we'll add an event listener for devicemotion events to the Window
this function will receive an event, which includes information about the current rotation of the device around its x, y and z axes
We'll use this to determine the distance our background image should moved to achieve the parallax effect
We'll then move our image based on this calculation
Here's our event handler, which is almost identical to the code above, just adapted to take the orientation event as its argument.
function orientationChanged (orientationEvent) {
var gamma = orientationEven.gamma;
//get the rotation around the y-axis from the orientation event
var tanOfGamma = Math.tan(gamma*(Math.PI/180))
//calculate the tan of the rotation around the Y axis (gamma)
//Math.tan takes radians, not degrees as the argument
var backgroundDistance = 50
//set the distance of the background from the foreground
//the smaller, the 'closer' an object appears
var xImagePosition = (-1 * tanOfGamma * backgroundDistance) + xOffset + "px"
//calculate the distance to shift the background image horizontally
homescreen.style.backgroundPosition = xImagePosition + " " + 0;
//set the backgroundimage position to xImagePosition 0
}
What the X?
Ok, so there's a reason we've still only worried about movement left to right. When you look at a screen, the neutral position in terms of rotation around the y axis (that is, tilted to left or right) is clearly with the screen perpendicular to the user's line of sight. But, what's the neutral position for the tilt forward and backwards? Lying on its back? Probably not. Perpendicular to the surface of the earth? Also probably not. When you hold a phone or tablet, it's likely to be somewhere between these two. In fact, right now, you're holding your device at an angle of
To simplify matters, let's say that the user will typically hold a device at around 45 degrees. So, we'll make this our "neutral" position for the parallax effect. Which means, we'll subtract 45 degrees from the current rotation when calculating the position of the background image up and down.
function orientationChanged (orientationEvent) {
var beta = orientationEvent.beta;
var gamma = orientationEvent.gamma;
//get the rotation around the x and y axes from the orientation event
var tanOfGamma = Math.tan(gamma*(Math.PI/180))
var tanOfBeta = Math.tan((beta -45)*(Math.PI/180))
//calculate the tan of the rotation around the X and Y axes
//we treat beta = 45 degrees as neutral
//Math.tan takes radians, not degrees, as the argument
var backgroundDistance = 50
//set the distance of the background from the foreground
//the smaller, the 'closer' an object appears
var xImagePosition = (-1 * tanOfGamma * backgroundDistance) + xOffset + "px"
var yImagePosition = (tanOfBeta * backgroundDistance) + yOffset + "px"
//calculate the distance to shift the background image horizontally
homescreen.style.backgroundPosition = xImagePosition + " " + yImagePosition;
//set the backgroundimage position to xImagePosition yImagePosition
}
Dis-orientation
What's also interesting is that if we change the orientation of the screen, from landscape to portrait, the beta and gamma values from the orientation event are still relative to the device. So, we need to now take into account whether the screen has been flipped (maybe even upside down) before doing our calculations.
First, we need to know what the current screen orientation is. We do this with the screenOrientation property of the window. This is the current rotation of the screen, where 90 degrees is rotated to the right, 180 degrees is turned upside down, and -90 degrees is rotated to the left.
Let's think about each of these three 'new' possible states in turn.
When turned upside down (screenOrientation === 180), we'll reverse the beta and gamma values, by multiplying them by -1. Effectively, we're treating up as down, and down as up, left as right, and right as left.
When rotated left, screenOrientation === -90, we'll swap gamma for beta, and the reverse of beta (-1 * beta) for gamma. Essentially, swapping left and right for forward and back, back for right, and forward for left.
Lastly, when the screen is rotated to the right (screenOrientation === 90), we'll do the opposite. So we swap left for forward, right for backward, forward for left, and backwards for right.
Then we continue as before, and now regardless of the screen's orientation, we still have our parallax effect. We've actually gone one step further than the real iOS homescreen, at least on the iPhone, as on the iPhone device rotations don't affect the orientation of the homescreen.
In school, you most likely did trigonometry and geometry with angles in degrees. Grown up math is typically done in radians, where 2π radians is 360 degrees. Since device orientation gives us rotation in degrees, we covert to radians by multiplying the number of degrees we have by π and then dividing by 180.
CSS Filters are a powerful tool available in all modern browsers to bring amazing photographic effects to web content. If you're not using them, you should be - here's how!
Learn how to build great looking and high performance mobile web applications leveraging CSS3 animations and Backbone.js, along with some cool use cases for geolocation and localStorage.
This session will describe in length a boilerplate you can use for developing your own apps aimed at A grade mobile devices and tablets.
About Julio Cesar Ody
Julio has been a full-stack software developer for the 12 years of his career, and during this time he went from being a GNU/Linux and Unix sysadmin, to a VoIP PBX architect, and finally a software developer.
Since moving to Australia from Brazil, he has worked on startups and companies building software and at the same time, stuck his nose as much as he can into the human side of the software equation, understanding developer productivity, how software companies work, and product development.
More recently he grew too interested in design for his own good, and began freelancing under the codename of Awesome By Design, writing a bunch of software which he open sourced on GitHub, giving presentations using his own presentation framework, and building software that not only does the job, but does so in style.
Follow Julio on Twitter: @julio_ody"
["post_title"]=>
string(61) "Julio Cesar Ody - CSS3 and Backbone.js for killer mobile apps"
["post_excerpt"]=>
string(294) "
This session will describe in length a boilerplate you can use for developing your own apps aimed at A grade mobile devices and tablets.
Since the early days of the web, the only reliable way to get movement on your site was through Flash, or more recently, Javascript. But now, with WebKit and Mozilla leading the way, transformations and transitions can be done with pure CSS, even on mobile devices. And for those in need of even more movement, CSS3 provides for keyframe-based animations. In this session, we’ll take a look at all of the possibilities and explore what works and where — from the simplest effects, to creative usability enhancements including the combination of CSS with mobile Javascript frameworks.
About Greg Rewis
Greg Rewis is the Principal Evangelist for Adobe Systems, focusing on Adobe’s open web products and technologies such as HTML5, CSS3 and Javascript. With over 20 years of computer industry experience, Greg spends in excess of 200 days of the year on the road, talking with customers, giving product demonstrations at seminars, and speaking at industry conferences.
Greg has been passionate about the web since putting his first “home page” online in 1994. His career has taken him around the world, from the early days of desktop publishing, to a start-up in Hamburg, Germany, the glory days of the web at Macromedia and finally his current role at Adobe.
The original GoLive Cyberstudio Product Manager and former Dreamweaver Technical Product Manager, Greg is the co-author of “Mastering CSS with Dreamweaver CS3″ and “Mastering CSS with Dreamweaver CS4″ published by New Riders, as well as a regular contributor to industry publications.
Follow Greg on Twitter: @garazi"
["post_title"]=>
string(53) "Greg Rewis - Move it! CSS3 Transitions and Animations"
["post_excerpt"]=>
string(386) "
In this session, we’ll take a look at all of the possibilities and explore what works and where — from the simplest effects, to creative usability enhancements including the combination of CSS with mobile Javascript frameworks.
One of the most powerful features of CSS3 are transforms, which allow us to take any element in an HTML document, and while not changing its effect on the page layout, rotate it, translate it (move it left, right, up and down), skew it and scale it. CSS3 provides both 2D and 3D transforms, but while 2D transforms are supported in all modern browsers, including IE9 and up, 3D transforms are currently only supported in Safari, Chrome and IE10.
In this article, we'll take a look at how to use 2D transforms and the various transform functions (such as scale and rotate). We'll also, as always, look at some gotchas when first working with transforms, and once again, there's a tool to help you play with transforms (I developed it some time ago, but I've updated it significantly for this article).
What transforms do
As in many cases, an example is worth a thousand words, so let's take a look at a couple, to illustrate how transforms work, as well as some of their most important aspects.
When you click or tap the button below, this paragraph is rotated by 45 degrees. It's also scaled to 75% of the size it would otherwise be. However note how the rest of the page layout is not affected. That's because transformations don't change the box model of an element, and so leave the page layout unchanged.
This element has been skewed horizontally and vertically. You can still select the text, and otherwise interact with the element, as you would if it weren't transformed.
Transforming elements
The syntax for CSS transforms is in many ways straightforward. There are just two new properties to contend with - transform, and transform-origin. The first specifies the transforms we want applied (scaling, rotating and so on), while the second, which is optional, specifies the origin for this transformation (for example, do we rotate around the middle of the element, its top left hand corner, and so on).
The transform property
The transform property takes as its value one or more transform functions, which each specify a transformation. Let's take a look at each of these different functions in detail. Functions all take the form of a function name, with a value inside round brackets (as indeed do all CSS functions). So for example, we translate horizontally with the function translateX(200px).
OK, enough preliminaries, let's start in with some actual transforming. We'll start with the translate function.
translate
The translate function moves the contents of an element to the left (negative values) or right (positive values), and/or upwards (negative values) and downwards (positive values).
translate takes one or two comma separated values. The first is the horizontal translation value. If there is a second, this is the vertical translation value, while if there is only one value, then the vertical translation is zero (that is, the element will only be translated horizontally).
In addition to the translate function, there are the related translateX and translateY functions, which only translate an element horizontally, or vertically, respectively. Translate functions take length or percentage values, and like CSS properties, require units for values other than zero.
But enough theory, why not have a play with them?
transform: translate(0, 0)
We mentioned a moment ago that transforms don't impact the layout of a page. There's one area where this is not exactly true. If you translate the above element completely to the right, you'll notice a horizontal scrollbar appears (or the page can now be scrolled to the right). While the page layout has not been changed, the overflow property of the transformed elements containing element is affected by transforms (Safari on Mac OS X Lion is an exception to this, and perhaps indicates where this sort of UX is headed, but for now, in desktop/laptop browsers other than this, the addition of a scrollbar will impact page layout).
This element is scaled by 200% when you click the button below. Its containing div has an overflow: auto. So, scrollbars appear when the element is transformed. In many browsers this will cause the page to reflow.
scale
The scale function lets us zoom an element up or down in size (all the while maintaining the dimensions of its box for the purposes of the layout of the page). The function name is scale, and it takes a number value-with a value of .5 meaning "scale to half the current size", and of 2 meaning "scale to twice the current size", and so on. So, if we want to make an element 75% of its current size, we use the property transform: scale(.75). And that's really all there is to it. Why not have a play with it?
transform: scale(1)
It's also possible to scale horizontally and vertically independently from one another, by using two comma separated numerical values for the scale property. The first value scales an element horizontally, and the second, vertically. Let's take a look.
transform: scale(1, 1)
As with translate there are two related scale functions, scaleX, and scaleY. scaleX scales only horizontally (scaleX(2) is the equivalent of scale(2, 1)), and scaleY, which scales only vertically (scaleY(2) is the equivalent of scale(1, 2)).
rotate
Rotating text and images is a common page design technique, until now difficult to achieve on the web without considerable hackery, if at all. Transforms make rotating an element easy.
The rotate function takes an angle value. If you've worked with CSS linear gradients, in particular the newer syntax, then you'll have seen angle units before. There are several ways you can specify an angle in CSS.
degrees
As you most likely remember from school math, there are 360 degrees in a circle. So, when specifying a rotation of an element, 90 degrees is a quarter turn clockwise, 180 degrees is a half turn, 270 degrees is three quarters turn clockwise, and 360 degrees is a full revolution. Here these are below.
Of course, it is possible to rotate an element by an arbitrary angle, for example 34.6 degrees, like so
rotate(34.6deg)
But, there are other ways we can specify rotations.
turns
perhaps the simplest way to specify a rotation is with the turn value. We can rotate an element a quarter turn clockwise with the function rotate(.25turn), half a turn with .5turn, three quarters of a turn with .75 turn, and a whole turn with the function rotate(1turn). WebKit and Opera support the turn value, while Firefox (version 6) does not.
For completeness, it's worth noting that there are two other possible angle units-radians (rad), and gradians (grad). Briefly, there are 400 gradians in a full rotation (so one grad is slightly larger than one degree), while there are 2π radians in a full rotation (radians are widely used in mathematics).
Now, if you think about rotating an element, then you might wonder what point of the element the rotation takes place around. For example - is it the center? Or one of the corners?
This element rotates around the top left hand corner when you click or tap and hold it. (transform: rotate(360deg))
We can in fact specify where the rotation (and as we'll soon see, any transformation) takes place, using the transform-origin property. transform-origin takes two length or percentage values, which specify the horizontal and vertical "origin" of the transformation. In the above example, we have transform-origin: 0 0. If we want to rotate around the center of the element, we use transform-origin: 50% 50%, while to rotate around the bottom right of the element, we use transform-origin: 100% 100%.
This element rotates around the center of the element (transform-origin: 50% 50%; transform: rotate(360deg)).
This element rotates around the bottom right hand corner of the element (transform-origin: 100% 100%; transform: rotate(360deg)).
(You might be able to guess that we can animate transformation changes, like we can most other CSS property changes using CSS Transitions. For more on this, see my article on CSS transitions and animations.)
So, let's now put rotations and transform origin together so we can play around with them.
transform: rotate(0);
transform-origin: 0 0
transform-origin can also be specified with keywords, in place of percentage (or length) values. As with background-position we can use left, center or right for the horizontal origin position and top, center or bottom for vertical. Where only one value is used, this applies to the horizontal origin, and the vertical is 50% (or center). Where no transform-origin is specified, its default value is 50% 50%.
skew
the last of the 2 dimensional transform functions is skew. Skewing is typically explained in mathematical terms, but if you recall a little school geometry, it isn't really that complicated. Horizontal skew (the skewX function) takes the box of an element, and while the top and bottom edges remain horizontal, tilts the left and right edges by the specified number of degrees to create a parallelogram. Similarly, a vertical skew (skewY), leaves the left and right edges vertical, and creates a parallelogram with the top and bottom edges rotated by the specified number of degrees. And when you skew both horizontally and vertically, you combine both of these (where it can get really quite tricky to work out what's going on). Does that help? You can play with the values below to get a sense of how skewing works in practice, including how it can create apparent 3D effects.
The skew function, like most other functions, takes one or two values. As with rotate, they are angle values, and where there are two values, they are comma separated.
transform: skew(0, 0)
Once again, as with a number of the other transform functions we've seen, there are two related functions - skewX and skewY, which each skew only in one dimension, and which take only a single, angle value.
Complex transformations
While you'll likely never need to use it, underneath all these functions is the core of CSS transformations, based on the mathematical concept of a transformation matrix. Each of the functions we've seen can be represented by a matrix value. While it's firmly in the domain of mathematics, we can for example represent the function scale(1.5,1.2) by the matrix
1.5 | 0 | 0
0 | 1.2 | 0
0 | 0 | 1
and directly apply this matrix value using the matrix function, like so
transform: matrix(1.5, 0, 0, 1.2, 0, 0)
this element has been scaled using a matrix function on the transform property.
It's possible to apply multiple transform functions at once to an element. For example we can rotate, translate and skew an element with the single transform property:
Click the button below to apply several transformation functions simultaneously, with the property transform: scale(0.75) rotate(45deg) translate(132px, -149px) skew(32deg, -32deg);
Hand coding transforms, as with much to do with CSS3, is an increasingly complex process. Not only is there a good deal of syntax to remember often for quite straightforward effects, but the outcome of at least some transforms isn't necessarily obvious to most of us simply by looking at the CSS. So, to help you learn, and explore, CSS transforms, I've developed a 2D transform tool (there's a 3D one as well, but we'll cover 3D in a later article).
If you're keen to explore transformations in more detail, and how they can be made to work together, head over and take a look, and as always, let me know what you think via twitter.
Gotchas, tips and tricks
Its fair to say that while now widely supported in modern browsers, 2D CSS transforms are still experimental, and quite quirky. Here are some of the difficulties you might encounter, and some tips and ideas for working with 2D transforms.
vendor specific prefixes
Reflecting the experimental nature of transforms, all browsers require vendor specific prefixes for the transform and transform-origin properties (note that function names are not prefixed). As all modern browsers including IE9 and up support 2D CSS transforms, using these transformation properties can get more than a little unwieldy. For example, the CSS for a simple rotation around the center of an element, if we include all vendor specific properties, would be something like:
img{
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg); //always include a standard for last
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
You might find the use of a CSS preprocessor like LESS or SASS worth exploring, as they can make stylesheets far more manageable when you use a lot of vendor prefixing.
Transforming inline elements in webkit
According to the current version of the specification, CSS Transforms should be applied to inline, as well as block elements, but while Opera and Firefox both correctly apply transforms to inline elements, WebKit browsers (Safari 5.1, Chrome 15) currently don't.
A workaround for this is to give inline elements which are to be transformed display: inline-block, which won't affect how they are laid out in the page, but will enable these browsers to transform them.
Translating rotated content
One subtle aspect of multiple transformations is that functions are performed in sequence - from first to last in the list. The order that you specify functions can make a difference. Take a look at the following paragraphs. Both have the same scale, rotate and translate functions applied. But, in the first, the element is translated to the right, while in the second, it is translated to the left. What's going on?
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) rotate(180deg) translate(-100px,0)
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) translate(-100px, 0) rotate(180deg)
Transformations don't take place in an absolute coordinate space. Rather, "up", "down", "left" and "right" are relative to the current rotation (but not skew) of the element. So, if an element is rotated half a turn, and so is "upside down" then translate(0, -100px) moves it down the page 100px. If it's rotated a quarter turn to the right, it's moved to the left. Similarly, translating "horizontally" is always relative to the element. So, if it's rotated by 180 degrees, then translate(100px, 0) moves the element to the left. In short, the X and Y axes of a transformation are relative not to the page, but the element's current rotation.
Interacting with transformed content
While the box of an element isn't changed by a transformation, elements that are transformed display various quirks when it comes to mouse events in various browsers, most likely due to the still experimental nature of transformations. Take the element below. It rotates a quarter turn clockwise when the mouse is over it, and then back to its original rotation when the mouse is out of it.
Now, if the box of the element isn't changed, then when rotated, hovering over any of the image which is outside that original box should not trigger a mouseover event, and so the element should rotate back to its original position. However, as makes intuitive sense, hovering over those parts of the rotated element that are outside the original box does cause mouseover events to be fired. But in addition, mouseover events are also fired when you hover over that part of the element's original box which no longer has content because it has been rotated away. And if you move your mouse around the element, you'll find in all browsers various locations where the rotation abruptly, though unintuitively, changes. Similar behavior can be observed for translation and other transformations.
In light of this, I'd suggest being extremely wary of transforming elements which users will interact with given the current state of browser support for transformations.
Overflowing and transformations
We mentioned earlier that while transformations don't effect the box model of an element, and so leave the layout of a page untouched, they do effect the overflow, and if we have overflow: auto, they can in fact impact the page flow.
In the element below, we have an image inside a div. The div has an overflow:auto. When we hover over the element (apologies to touch device users), the contained image scales up in size.
Now, in most browsers on most platforms (Safari on Mac OS X 10.7 is an exception) the browser adds a horizontal scrollbar to the div when you hover over the image, which adds to the height of the element, reflowing the page below it. Just something to be aware of.
It has to do with the positioning of elements. When we absolutely or fixed position an element, and give it say a top and left, these positions are offset from their containing box - which is not necessarily their parent element. Rather, the containing box is the first ancestor which itself has either relative, absolute or fixed position. However, adding a transform to an element also makes it a containing block for its descendent elements! As Eric observes, this can particularly cause difficulties with fixed positioning. Rather than rehash Eric's detailed thoughts, I'll let you head over and read them first hand.
General Rendering Problems
On different browsers you'll find various rendering problems with transformed content. For example, with Opera, rotated text appears to be rendered in a lighter font than the same text when it isn't rotated. I've also seen redrawing problems when rotating text in WebKit browsers. In Safari on iOS 4, rotated text doesn't necessarily align smoothly along its baseline. None of these are necessarily deal breakers, but it's worth keeping in mind. Transforms are still experimental, so don't necessarily expect them to be perfectly supported in all circumstances just yet.
Hardware Acceleration
There's a widely held belief that at least some browsers hardware accelerate the rendering of CSS transformations (hardware acceleration involves the CPU handing off execution of certain types of calculation to the GPU, which can increase rendering performance significantly, particularly on mobile devices).
At present the current state of hardware acceleration for CSS transforms across all browsers and devices is difficult to pin down. A webkit engineer I tracked down confirmed that current versions of Safari (5.1 on the desktop, iOS 4), but not necessarily other WebKit browsers:
animated 2D transforms in Safari are always hardware accelerated
using 3D for static 2D transforms may improve performance, but may also increase memory use - a real issue for memory limited mobile devices in particular
Now, haven't we just spent however much effort covering 2D transforms? How could this possibly help? Well, as we'll see in an upcoming article on 3D transforms, we can use 3D transforms to do 2D transforms (for example, there's rotate3D). If squeezing maximum performance for iOS devices is a need, then it may be that using a 3D version of a transform will help.
It's also worth noting that issues around what aspects of CSS transforms are hardware accelerated and how that acceleration works are implementation details in specific browsers, and not specified as part of CSS Transforms. As such, across browsers there's likely to be little uniformity of approach to hardware acceleration, and even from one version of a browser to the next, approaches may change.
Backwards Compatibility
One of the strongest aspects of CSS3 features like gradients, border-radius, shadows and the like is that they have been typically designed so as to be easily used in a way that is backwards compatible almost automatically, or provided we keep a small number of potential challenges in mind. For example, with gradients we need to ensure we have a fallback background color or image for when gradients aren't supported. For text-shadow, we need to ensure that the contrast between the text and the element background is sufficient when the shadow is not drawn.
Of all new CSS3 properties, transform is the one where backwards compatibility is the most difficult to ensure. Ironically, it's precisely because transforms don't affect the page layout that they cause such difficulty. For example, in order to accommodate say a heading rotated 90 degree to run horizontally along the left hand side of the text which follows it, we need to create whitespace to ensure the heading does not overlap the text. We might do that with margin, or padding. We're also likely to want to remove the whitespace where the heading has been rotated away from, by, for example, using negative margin on the paragraph following the heading. But, what happens if transforms aren't supported? The heading text will be overlapped by the paragraph below it.
In order to use transforms for more sophisticated page layout along these lines, a solution like Modernizr, which enables different CSS to be applied based on the support, or absence of support for various CSS3 features like transforms is indispensable.
Transformations are typically most easily used in a way that is backwards compatible where animated transforms create a transition between states in an application. We're all most likely used to sliding or flipping transitions between states in iOS and other mobile apps. CSS transforms can be used for these transitions, in conjunction with CSS Transitions, and where transforms aren't supported (in which case it's unlikely transitions will be as well), your users simply see an abrupt change in state.
However you plan to use transforms, as with every other aspect of web development, keep in mind those browsers which don't support them, and ensure your user's experience isn't diminished to the point where information or functionality is denied them because their browser doesn't support it.
Browser Support
As we mentioned, despite the still rather experimental nature of support for CSS 2D Transforms, they are now widely supported in modern browsers including:
Internet Explorer 9 and up
Firefox 3.5 up
Safari 3.2 up
Chrome 10 and up
Opera 10.6 and up
iOS 3.2 and up
Opera Mobile 11 and higher
Android 2.1 and up
So, support is widespread, and constantly improving. While there are definitely challenges associated with using 2D Transforms, they're a powerful, and worthwhile addition to the repertoire of developers, and will only gain in value. What are you going to do with them?
We recently took a detailed look at linear gradients in CSS3. If you've not read that, you might like to spend a few minutes doing so, as the concepts are very similar, and I don't spend quite as much time in this article on the fundamentals of gradients which I've already covered there.
This time we'll look in detail at radial gradients. If you've got a good sense of how linear gradients work, radial gradients should present no great difficulty. And, I'll again introduce an updated tool for creating radial gradients, which supports the current syntax, and works across all modern browsers which support radial gradients (more on which they are shortly).
A brief history
Like linear gradients, radial gradients were first introduced in Webkit in 2008. Like linear gradients, they are still in a draft CSS3 specification, and indeed are still in something of a state of flux, so it is more than possible the final specified version will be different from that described here. As with linear gradients, radial gradients as originally proposed by Apple's Webkit team had a different syntax, and quite significantly different conceptual basis from how they are currently specified, and from how they are supported in current browsers. With Safari 5.1, all modern browsers have harmonized on the same syntax, and conceptual basis for radial gradients, which is what we cover here. Safari 4, and Chrome 10 and up support a very different syntax, and model for radial gradients, which is effectively obsolete, and which we won't cover here.
What exactly is a radial gradient?
I've thought long and hard about whether to try and explain what is really going on with a radial gradient (and for most folks, simply playing around with them is likely the best way to really come to grips with them). But, as I've yet to see a very good description of exactly how radial gradients work, here's my attempt.
You'll hopefully remember that linear gradients have a straight gradient line, from one edge of the element's background box. It could be vertically from top to bottom, or bottom to top. It could be horizontally from left to right, or right to left. Or it could be at an angle, from left to right, right to left, upwards or downwards.
Some common linear gradient lines
We then specify two (or more) colors to create the gradient along this line. The gradient "smoothly fades" from one color to the next along the gradient line. So, what exactly does "smoothly fades" mean? To get all technical on you, the Image Values and Replaced Content module of CSS3 says "between two color-stops, the line's color is linearly interpolated between the colors of the two color-stops, with the interpolation taking place in premultiplied RGBA space". Glad you asked? And if you really want to get down and dirty with linear interpolation, the spec has a whole section on it.
Radial gradients also specify a gradient line, but this time, the line goes from the center of an ellipse, outwards in each direction to the edge of the ellipse. Along this line color also "fades smoothly" from one color stop to the next.
We also know from linear gradients, that the gradient can have intermediate stops between the starting and final color. Not surprisingly, radial gradients can have color stops, specified as being a certain percentage, or length value, along the gradient, between the start and final colors.
But where radial gradients differ significantly from linear ones, is the shape and size of the gradient, as well as a gradient's location.
In essence, to specify a radial gradient, we give the gradient
a location
a shape
a size
one or more color stops
Let's look at each of these, though slightly out of order, because to understand how they all work, we need to understand a little bit about what an ellipse is (this won't hurt a bit I promise).
Ellipses
An Ellipse, showing the major and minor radii.
An ellipse is what we more colloquially call an oval. It differs from a circle in that its width and height are different from one another (strictly speaking, a circle is a kind of ellipse where the width and height are equal).
As you can see here, a circle is a special kind of ellipse where these two lines are the same length.
If you drop a vertical line through an ellipse at its tallest point, and a horizontal line through it at its widest, where these two intersect is the center of the ellipse. The longer of these two lines is called the major semi-axis or major radius, and the shorter the minor semi-axis or minor radius.
From all this, the key concepts to take away are
What the center of an ellipse is
What the radii of an ellipse are
Radial gradient location
We give a radial gradient a location by specifying where its center will be in relation to the element it is a background image for (we'll leave aside the case where the gradient is used elsewhere for now).
We can specify the location of the ellipse's center essentially the same way we specify the location of a background image with the background-position CSS property. We specify the horizontal position of the background, and optionally the vertical position using either keywords (left, center right, or top, center, bottom), length values, percentage values, or some combination of these. For example we might have
left bottom
left 100%
0% bottom
0% 100%
Which all specify that the center of the gradient ellipse should be in the left bottom corner of the element background.
Where the second value is omitted, it is treated as center (similarly, if we omit the first value as well, the center of the gradient ellipse is in the center of the element's background.)
So, let's start putting together a radial gradient. As we saw with linear gradients, a gradient is not a CSS property. Rather it is a value, that can in theory be used anywhere an image would be used, but in practice, typically only as a background image on an element. Here we'll start a radial gradient as the background image of an element, and give it a location. We'll place the gradient in the center of the element's background.
background-image: radial-gradient(50% 50%,
Notice how the horizontal and vertical center values are simply separated by a space, and then pair is then followed by a comma. Note too that this is not yet a gradient, just the start of one. We still need to specify the shape and size, plus its color values.
Radial Gradient shapes and sizes
Now we've specified the location of the center of the gradient, we need to specify the shape and size of the ellipse. These can be specified in one of two ways, implicitly, or explicitly.
Explicit shapes and sizes
We explicitly specify the shape and size of the ellipse for our radial gradient by specifying the lengths of the major and minor radius, using a length or percentage value. (as of July 2011, this aspect of radial gradients was not supported by any browser, so we'll only cover this briefly).
For example, we might specify a width of the gradient ellipse as being 50% of the width of the background element and 30% of the height of the element with the values25% 15% (note that these values specify the radius, which is half the width or height). If we specify identical values for width and height, then the two radii are the same length, and so we get a circular gradient. Here's what our gradient would look like with this explicitly declared width and height
Notice again, the width and height values are separated only by a space, and then we follow these by a comma.
Implicit shapes and sizes
Alternatively, instead of specifying an explicit width and height to give us the size and shape of our gradient, we can specify the size and shape implicitly with keywords. In practice, this is the only one of the two forms that is supported in contemporary browsers, and so is the one you should use.
Shape
This part is very straightforward, we just use one of two keywords ellipse or circle, to specify the shape of the gradient. So, we create an elliptical shape for our gradient like so
If we are declaring the size of the gradient implicitly, we specify the size of the gradient shape using one of several keywords. Each of these keywords specifies an algorithm for giving the gradient a size. These algorithms are sometimes slightly different for ellipses and circles. While they may initially seem quite complicated, they make sense once you understand the key principle of each. Here's my way of understanding what is going on with each keyword.
Keyword
For Circular gradients
For Elliptical Gradients
closest-side
with closest-side a circular gradient is sized so that it "exactly meets the side of the box closest to its center"
with closest-side an ellipse is sized so that it "exactly meets the vertical and horizontal sides of the box closest to its center"
closest-corner
with closest-corner a circular gradient is sized so that its edge exactly meets the closest corner to its center of the box
with closest-corner an elliptical gradient is sized so that its edge exactly meets the closest corner to its center of the box
farthest-side
with farthest-side a circular gradient is sized so that it "exactly meets the side of the box farthest from its center"
with farthest-side an elliptical gradient is sized so that it "exactly meets the vertical and horizontal sides of the box farthest from its center"
farthest-corner
with farthest-corner the gradient-shape is sized so that its edge exactly meets the farthest corner from its center of the box
with farthest-corner an elliptical gradient-shape is sized so that its edge exactly meets the farthest corner from its center of the box
There are two additional keywords, contain and cover. The keyword contain is the same as closest-side, while the keyword cover is the same as farthest-corner.
Here we'll give our gradient a size of closest-corner.
As with the location of the center of the gradient, the two keyword values are separated by space, then followed by a commas
Color Stops
Now we've established the size, shape and location of the gradient, all that remains is for us to specify two or more color stops. As with linear gradients, we specify a color stop with a color, and an optional stop position, which is a length or percentage value. The simplest case is color values alone.
When color stops are specified with color values only, the stops divide the size of the gradient evenly. So, if there are 3 color stops, each color covers a third of the gradient shape, and fades into its adjacent color stop(s).
Let's take a look at an example. Here's a simple circular gradient. It's implicitly sized to touch the closest size to its center, and has three color stops, red, green and blue
And here's what it this will look like in a browser which supports radial gradients.
If we add more stops, these are simply evenly spaced in the same size, as here, where we have 6 color stops, evenly spaced across the size of the gradient.
Color stops can, as we mentioned, optionally also specify a length or percentage value. So, we can make color stops a specific distance apart from one another, like so:
Notice again, the color and position of each stop is separated by a space, and again each stop is separated by a comma.
It's also possible to use length values, like px and em in place of percentages, and to mix all three forms of color stop (color alone, percentage and lengths). Keep in mind that percentage gradients will adapt to the size of the element, so that when it grows or shrinks in size the gradient remains in proportion to the element's size, and so in many cases, percentage gradient stops (or simple color stops specified only by color) are likely to be the most adaptable choice.
Coloring inside and outside the gradient
You might have noticed that in our examples, outside the gradient shape is a solid color background, the color being that of the last color stop specified. Once the gradient completes, whatever the finishing color is will then fill the remainder of the element's background.
In this last example, you might also have noticed the same thing happens inside the gradient shape. Our first color stop is at 25%, so from the center of the gradient to 25% of its width, we have a solid red color. The red only fades smoothly into the next color stop, green, from 25% out from the gradient shape's center.
Stop positions can in fact be greater than 100% of the size of the gradient, so we can fill the entire element with a gradient by specifying a final stop position large enough that the entire element is covered by the gradient.
Repeating gradients
As with linear gradients, radial gradients can repeat. This we specify with a slightly different value name - repeating-radial-gradient. If we take our previous gradient, and repeat it, here's what we get
Where we would have solid color outside the gradient shape, we now have the gradient repeating. If we reduce the size of the gradient, the effect becomes more pronounced. In this example, we reduce the size of the gradient shape, to get the following non-repeating gradient.
Shapes, sizes, centers, radii, stops... If it all sounds like a lot to learn and remember, then again we're here to help. As we've done for linear gradients, we've built a radial gradient tool, which helps you build gradients, without having to remember all the heavy lifting.
As with our linear gradient tool, in addition to just helping you create radial gradient, it has some other features.
You can tweet a link to a gradient you’ve created by simply clicking a button
You can copy the url of your gradient, and send it to someone via email, put it in a link (like I’ve done for many of these examples) or otherwise share it
Via the magic of HTML5 localStorage, it remembers your most recent gradient, and other settings next time you visit
It adds vendor prefixes for all modern browsers (as an option)
It adds the start color as a background color for older browsers
There’s a related tool for creating old-style Webkit gradients
It provides up to the minute browser compatibility information (provided I remember to update that as browsers change)
It looks really pretty, all thanks to CSS gradients of course
Despite being relatively new, and as yet not completely specified, radial gradients are safe to use in a way that is backwards compatible, and are in fact quite widely supported (we'll take a look at which browsers support them in a moment).
To ensure compatibility and accessibility when using radial gradients, as with linear gradients, it's important to
include vendor specific prefixes (-o-, -ms-, -moz, -webkit-), as well as the standard form of gradient values
include a background color for browsers which don't support gradients. Make sure the text of an element with a gradient background has sufficient contrast with the element's background color
Browser support
A quick summary of current browser support for CSS Radial Gradients (based on the information at the fantastic When Can I Use).
Safari 4 introduced radial gradients, though as noted with a different syntax from that detailed here. The vendor prefix -webkit- is required for gradients in Safari 4.1 and newer.
Safari 5.1 introduces the syntax detailed here, as well as continuing to support the older style syntax. Again, the -webkit- vendor prefix is required.
Firefox 3.6 was the first browser to support the current gradient syntax. The -moz- prefix is required, and it's currently only supported on backgrounds.
Chrome 10 and up (and probably earlier versions) supported the syntax for gradients detailed here. The -webkit- prefix is required.
Opera 11.1 introduced linear gradient support, but at present does not support radial gradients of any kind
Internet Explorer 10 also features CSS radial gradients, using the prefix -ms-, and also only on backgrounds.
Gradients can be computationally intensive, and may cause browsers running on older hardware difficulty. At present they are not able to be animated with CSS transitions in any browser which supports transitions.
Detailed support information for CSS gradients, and many other modern HTML5, CSS3 and DOM features is available at When Can I Use?
The wrap
I hope this article has been helpful in understanding a little more deeply what is really going on with radial gradients, and hope the radial gradient tool makes working with them enjoyable. Let me know if you've found them helpful on twitter!
Throughout the years, the Swiss Army Knife has been the trusted companion of scouts and explorers alike, and for front-end developers, CSS has been a trusty, if sometimes frustrating, companion. And just as blades, scissors and sundry tools have been added to the Swiss Army Knife, with CSS3, we have new tools and implements of creativity, and some tried and true tools have been honed and sharpened. Of course the key to success is knowing which of the many tools to use and how to wield them in a given situation. Join Stephanie Rewis as she explores some shiny enhancements to favorite old tools like backgrounds and borders, as well as slices and dices with new tools like CSS masks and more!
About Stephanie (Sullivan) Rewis
Stephanie (Sullivan) Rewis is the founder of W3Conversion, a web design company with a passion for web standards. A front-end developer, Stephanie created the CSS Starter Layouts in Dreamweaver CS3 and recently updated for DW CS5. Her passion for sharing knowledge has led her to write books and tutorials, pen a bi-monthly column for Web Designer Magazine, train corporate web departments, and speak at numerous conferences. Stephanie is the WaSP liaison to Adobe Systems, working with product managers to ensure the output of its web products continues to move toward today’s web standards. An admitted workaholic who rarely leaves the office, she frequently escapes to talk to the people inside her computer via Twitter. Her hobby, if only she had time? Studying brain function. Her guilty pleasure? Eighties music.
Follow Stephanie on Twitter:@stefsull"
["post_title"]=>
string(62) "Stephanie (Sullivan) Rewis - CSS3 - the Web's Swiss Army Knife"
["post_excerpt"]=>
string(401) "
In this session, we’ll take a look at all of the possibilities and explore what works and where — from the simplest effects, to creative usability enhancements including the combination of CSS with mobile Javascript frameworks.
With most browsers adding increasing support, and the simplicity of providing fallbacks for those that don’t, CSS3 gradients are something we can start to use right now. They benefit our users with faster websites and ourselves with more time in our hands to spend in other things, since they are easy to create, edit and update. A very powerful feature that can also be utilized for a surprising number of design effects, even ones that don’t resemble gradients at all. In this talk, Lea will explore CSS3 gradients in great depth and it’s almost guaranteed that no matter your expertise level, you will walk out having learned new things.
About Lea Verou
Lea Verou is a front-end engineer currently living in Greece. She discovered programming at the young age of 12 (web development a few years after) and it was love at first …line. In 2008, she co-founded Fresset Ltd, whose websites have attracted a large following in the Greek internet scene, they are currently working frantically on their first international project.
Fed up with the lack of proper web development education in Greece, she co-organised a university course which teaches all aspects of modern, standards-based Web development, including CSS3, HTML5 and ES5 as regular parts of its content.
During her spare time, she blogs about CSS, JavaScript and web usability at leaverou.me.
With most browsers adding increasing support, and the simplicity of providing fallbacks for those that don’t, CSS3 gradients are something we can start to use right now. They benefit our users with faster websites and ourselves with more time in our hands to spend in other things, since they are easy to create, edit and update. A very powerful feature that can also be utilized for a surprising number of design effects, even ones that don’t resemble gradients at all. In this talk, Lea will explore CSS3 gradients in great depth and it’s almost guaranteed that no matter your expertise level, you will walk out having learned new things.
Being a front-end designer used to mean pixel hacking and endless rounds of pain while trying to make sites and applications “look the same in each browser”. Thankfully, we now live in more interesting times. But as we strive to make our web apps a pleasure to use, the vast array of tools and techniques available to us present their own set of challenges. In this session you will learn to ask the right questions to guide your choice of tools and the design.
Find out how to creatively use new features of CSS3 (gradients, multiple backgrounds, generated content, and many more) to give life to your design ideas, make them adaptable and maintainable, and provide the best experience possible on an array of platforms.
Finally, you’ll hear how to create a library of simple and ready-to-use design patterns, that you can incorporate into your workflow to bring your designs to life much faster.
Find out how to creatively use new features of CSS3 (gradients, multiple backgrounds, generated content, and many more) to give life to your design ideas, make them adaptable and maintainable, and provide the best experience possible on an array of platforms.
One of the most powerful features of CSS3 are transforms, which allow us to take any element in an HTML document, and while not changing its effect on the page layout, rotate it, translate it (move it left, right, up and down), skew it and scale it. CSS3 provides both 2D and 3D transforms, but while 2D transforms are supported in all modern browsers, including IE9 and up, 3D transforms are currently only supported in Safari, Chrome and IE10.
In this article, we'll take a look at how to use 2D transforms and the various transform functions (such as scale and rotate). We'll also, as always, look at some gotchas when first working with transforms, and once again, there's a tool to help you play with transforms (I developed it some time ago, but I've updated it significantly for this article).
What transforms do
As in many cases, an example is worth a thousand words, so let's take a look at a couple, to illustrate how transforms work, as well as some of their most important aspects.
When you click or tap the button below, this paragraph is rotated by 45 degrees. It's also scaled to 75% of the size it would otherwise be. However note how the rest of the page layout is not affected. That's because transformations don't change the box model of an element, and so leave the page layout unchanged.
This element has been skewed horizontally and vertically. You can still select the text, and otherwise interact with the element, as you would if it weren't transformed.
Transforming elements
The syntax for CSS transforms is in many ways straightforward. There are just two new properties to contend with - transform, and transform-origin. The first specifies the transforms we want applied (scaling, rotating and so on), while the second, which is optional, specifies the origin for this transformation (for example, do we rotate around the middle of the element, its top left hand corner, and so on).
The transform property
The transform property takes as its value one or more transform functions, which each specify a transformation. Let's take a look at each of these different functions in detail. Functions all take the form of a function name, with a value inside round brackets (as indeed do all CSS functions). So for example, we translate horizontally with the function translateX(200px).
OK, enough preliminaries, let's start in with some actual transforming. We'll start with the translate function.
translate
The translate function moves the contents of an element to the left (negative values) or right (positive values), and/or upwards (negative values) and downwards (positive values).
translate takes one or two comma separated values. The first is the horizontal translation value. If there is a second, this is the vertical translation value, while if there is only one value, then the vertical translation is zero (that is, the element will only be translated horizontally).
In addition to the translate function, there are the related translateX and translateY functions, which only translate an element horizontally, or vertically, respectively. Translate functions take length or percentage values, and like CSS properties, require units for values other than zero.
But enough theory, why not have a play with them?
transform: translate(0, 0)
We mentioned a moment ago that transforms don't impact the layout of a page. There's one area where this is not exactly true. If you translate the above element completely to the right, you'll notice a horizontal scrollbar appears (or the page can now be scrolled to the right). While the page layout has not been changed, the overflow property of the transformed elements containing element is affected by transforms (Safari on Mac OS X Lion is an exception to this, and perhaps indicates where this sort of UX is headed, but for now, in desktop/laptop browsers other than this, the addition of a scrollbar will impact page layout).
This element is scaled by 200% when you click the button below. Its containing div has an overflow: auto. So, scrollbars appear when the element is transformed. In many browsers this will cause the page to reflow.
scale
The scale function lets us zoom an element up or down in size (all the while maintaining the dimensions of its box for the purposes of the layout of the page). The function name is scale, and it takes a number value-with a value of .5 meaning "scale to half the current size", and of 2 meaning "scale to twice the current size", and so on. So, if we want to make an element 75% of its current size, we use the property transform: scale(.75). And that's really all there is to it. Why not have a play with it?
transform: scale(1)
It's also possible to scale horizontally and vertically independently from one another, by using two comma separated numerical values for the scale property. The first value scales an element horizontally, and the second, vertically. Let's take a look.
transform: scale(1, 1)
As with translate there are two related scale functions, scaleX, and scaleY. scaleX scales only horizontally (scaleX(2) is the equivalent of scale(2, 1)), and scaleY, which scales only vertically (scaleY(2) is the equivalent of scale(1, 2)).
rotate
Rotating text and images is a common page design technique, until now difficult to achieve on the web without considerable hackery, if at all. Transforms make rotating an element easy.
The rotate function takes an angle value. If you've worked with CSS linear gradients, in particular the newer syntax, then you'll have seen angle units before. There are several ways you can specify an angle in CSS.
degrees
As you most likely remember from school math, there are 360 degrees in a circle. So, when specifying a rotation of an element, 90 degrees is a quarter turn clockwise, 180 degrees is a half turn, 270 degrees is three quarters turn clockwise, and 360 degrees is a full revolution. Here these are below.
Of course, it is possible to rotate an element by an arbitrary angle, for example 34.6 degrees, like so
rotate(34.6deg)
But, there are other ways we can specify rotations.
turns
perhaps the simplest way to specify a rotation is with the turn value. We can rotate an element a quarter turn clockwise with the function rotate(.25turn), half a turn with .5turn, three quarters of a turn with .75 turn, and a whole turn with the function rotate(1turn). WebKit and Opera support the turn value, while Firefox (version 6) does not.
For completeness, it's worth noting that there are two other possible angle units-radians (rad), and gradians (grad). Briefly, there are 400 gradians in a full rotation (so one grad is slightly larger than one degree), while there are 2π radians in a full rotation (radians are widely used in mathematics).
Now, if you think about rotating an element, then you might wonder what point of the element the rotation takes place around. For example - is it the center? Or one of the corners?
This element rotates around the top left hand corner when you click or tap and hold it. (transform: rotate(360deg))
We can in fact specify where the rotation (and as we'll soon see, any transformation) takes place, using the transform-origin property. transform-origin takes two length or percentage values, which specify the horizontal and vertical "origin" of the transformation. In the above example, we have transform-origin: 0 0. If we want to rotate around the center of the element, we use transform-origin: 50% 50%, while to rotate around the bottom right of the element, we use transform-origin: 100% 100%.
This element rotates around the center of the element (transform-origin: 50% 50%; transform: rotate(360deg)).
This element rotates around the bottom right hand corner of the element (transform-origin: 100% 100%; transform: rotate(360deg)).
(You might be able to guess that we can animate transformation changes, like we can most other CSS property changes using CSS Transitions. For more on this, see my article on CSS transitions and animations.)
So, let's now put rotations and transform origin together so we can play around with them.
transform: rotate(0);
transform-origin: 0 0
transform-origin can also be specified with keywords, in place of percentage (or length) values. As with background-position we can use left, center or right for the horizontal origin position and top, center or bottom for vertical. Where only one value is used, this applies to the horizontal origin, and the vertical is 50% (or center). Where no transform-origin is specified, its default value is 50% 50%.
skew
the last of the 2 dimensional transform functions is skew. Skewing is typically explained in mathematical terms, but if you recall a little school geometry, it isn't really that complicated. Horizontal skew (the skewX function) takes the box of an element, and while the top and bottom edges remain horizontal, tilts the left and right edges by the specified number of degrees to create a parallelogram. Similarly, a vertical skew (skewY), leaves the left and right edges vertical, and creates a parallelogram with the top and bottom edges rotated by the specified number of degrees. And when you skew both horizontally and vertically, you combine both of these (where it can get really quite tricky to work out what's going on). Does that help? You can play with the values below to get a sense of how skewing works in practice, including how it can create apparent 3D effects.
The skew function, like most other functions, takes one or two values. As with rotate, they are angle values, and where there are two values, they are comma separated.
transform: skew(0, 0)
Once again, as with a number of the other transform functions we've seen, there are two related functions - skewX and skewY, which each skew only in one dimension, and which take only a single, angle value.
Complex transformations
While you'll likely never need to use it, underneath all these functions is the core of CSS transformations, based on the mathematical concept of a transformation matrix. Each of the functions we've seen can be represented by a matrix value. While it's firmly in the domain of mathematics, we can for example represent the function scale(1.5,1.2) by the matrix
1.5 | 0 | 0
0 | 1.2 | 0
0 | 0 | 1
and directly apply this matrix value using the matrix function, like so
transform: matrix(1.5, 0, 0, 1.2, 0, 0)
this element has been scaled using a matrix function on the transform property.
It's possible to apply multiple transform functions at once to an element. For example we can rotate, translate and skew an element with the single transform property:
Click the button below to apply several transformation functions simultaneously, with the property transform: scale(0.75) rotate(45deg) translate(132px, -149px) skew(32deg, -32deg);
Hand coding transforms, as with much to do with CSS3, is an increasingly complex process. Not only is there a good deal of syntax to remember often for quite straightforward effects, but the outcome of at least some transforms isn't necessarily obvious to most of us simply by looking at the CSS. So, to help you learn, and explore, CSS transforms, I've developed a 2D transform tool (there's a 3D one as well, but we'll cover 3D in a later article).
If you're keen to explore transformations in more detail, and how they can be made to work together, head over and take a look, and as always, let me know what you think via twitter.
Gotchas, tips and tricks
Its fair to say that while now widely supported in modern browsers, 2D CSS transforms are still experimental, and quite quirky. Here are some of the difficulties you might encounter, and some tips and ideas for working with 2D transforms.
vendor specific prefixes
Reflecting the experimental nature of transforms, all browsers require vendor specific prefixes for the transform and transform-origin properties (note that function names are not prefixed). As all modern browsers including IE9 and up support 2D CSS transforms, using these transformation properties can get more than a little unwieldy. For example, the CSS for a simple rotation around the center of an element, if we include all vendor specific properties, would be something like:
img{
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-o-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg); //always include a standard for last
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
transform-origin: 50% 50%;
}
You might find the use of a CSS preprocessor like LESS or SASS worth exploring, as they can make stylesheets far more manageable when you use a lot of vendor prefixing.
Transforming inline elements in webkit
According to the current version of the specification, CSS Transforms should be applied to inline, as well as block elements, but while Opera and Firefox both correctly apply transforms to inline elements, WebKit browsers (Safari 5.1, Chrome 15) currently don't.
A workaround for this is to give inline elements which are to be transformed display: inline-block, which won't affect how they are laid out in the page, but will enable these browsers to transform them.
Translating rotated content
One subtle aspect of multiple transformations is that functions are performed in sequence - from first to last in the list. The order that you specify functions can make a difference. Take a look at the following paragraphs. Both have the same scale, rotate and translate functions applied. But, in the first, the element is translated to the right, while in the second, it is translated to the left. What's going on?
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) rotate(180deg) translate(-100px,0)
Clicking the button below applies several transformation functions simultaneously, with the property transform: scale(0.75) translate(-100px, 0) rotate(180deg)
Transformations don't take place in an absolute coordinate space. Rather, "up", "down", "left" and "right" are relative to the current rotation (but not skew) of the element. So, if an element is rotated half a turn, and so is "upside down" then translate(0, -100px) moves it down the page 100px. If it's rotated a quarter turn to the right, it's moved to the left. Similarly, translating "horizontally" is always relative to the element. So, if it's rotated by 180 degrees, then translate(100px, 0) moves the element to the left. In short, the X and Y axes of a transformation are relative not to the page, but the element's current rotation.
Interacting with transformed content
While the box of an element isn't changed by a transformation, elements that are transformed display various quirks when it comes to mouse events in various browsers, most likely due to the still experimental nature of transformations. Take the element below. It rotates a quarter turn clockwise when the mouse is over it, and then back to its original rotation when the mouse is out of it.
Now, if the box of the element isn't changed, then when rotated, hovering over any of the image which is outside that original box should not trigger a mouseover event, and so the element should rotate back to its original position. However, as makes intuitive sense, hovering over those parts of the rotated element that are outside the original box does cause mouseover events to be fired. But in addition, mouseover events are also fired when you hover over that part of the element's original box which no longer has content because it has been rotated away. And if you move your mouse around the element, you'll find in all browsers various locations where the rotation abruptly, though unintuitively, changes. Similar behavior can be observed for translation and other transformations.
In light of this, I'd suggest being extremely wary of transforming elements which users will interact with given the current state of browser support for transformations.
Overflowing and transformations
We mentioned earlier that while transformations don't effect the box model of an element, and so leave the layout of a page untouched, they do effect the overflow, and if we have overflow: auto, they can in fact impact the page flow.
In the element below, we have an image inside a div. The div has an overflow:auto. When we hover over the element (apologies to touch device users), the contained image scales up in size.
Now, in most browsers on most platforms (Safari on Mac OS X 10.7 is an exception) the browser adds a horizontal scrollbar to the div when you hover over the image, which adds to the height of the element, reflowing the page below it. Just something to be aware of.
It has to do with the positioning of elements. When we absolutely or fixed position an element, and give it say a top and left, these positions are offset from their containing box - which is not necessarily their parent element. Rather, the containing box is the first ancestor which itself has either relative, absolute or fixed position. However, adding a transform to an element also makes it a containing block for its descendent elements! As Eric observes, this can particularly cause difficulties with fixed positioning. Rather than rehash Eric's detailed thoughts, I'll let you head over and read them first hand.
General Rendering Problems
On different browsers you'll find various rendering problems with transformed content. For example, with Opera, rotated text appears to be rendered in a lighter font than the same text when it isn't rotated. I've also seen redrawing problems when rotating text in WebKit browsers. In Safari on iOS 4, rotated text doesn't necessarily align smoothly along its baseline. None of these are necessarily deal breakers, but it's worth keeping in mind. Transforms are still experimental, so don't necessarily expect them to be perfectly supported in all circumstances just yet.
Hardware Acceleration
There's a widely held belief that at least some browsers hardware accelerate the rendering of CSS transformations (hardware acceleration involves the CPU handing off execution of certain types of calculation to the GPU, which can increase rendering performance significantly, particularly on mobile devices).
At present the current state of hardware acceleration for CSS transforms across all browsers and devices is difficult to pin down. A webkit engineer I tracked down confirmed that current versions of Safari (5.1 on the desktop, iOS 4), but not necessarily other WebKit browsers:
animated 2D transforms in Safari are always hardware accelerated
using 3D for static 2D transforms may improve performance, but may also increase memory use - a real issue for memory limited mobile devices in particular
Now, haven't we just spent however much effort covering 2D transforms? How could this possibly help? Well, as we'll see in an upcoming article on 3D transforms, we can use 3D transforms to do 2D transforms (for example, there's rotate3D). If squeezing maximum performance for iOS devices is a need, then it may be that using a 3D version of a transform will help.
It's also worth noting that issues around what aspects of CSS transforms are hardware accelerated and how that acceleration works are implementation details in specific browsers, and not specified as part of CSS Transforms. As such, across browsers there's likely to be little uniformity of approach to hardware acceleration, and even from one version of a browser to the next, approaches may change.
Backwards Compatibility
One of the strongest aspects of CSS3 features like gradients, border-radius, shadows and the like is that they have been typically designed so as to be easily used in a way that is backwards compatible almost automatically, or provided we keep a small number of potential challenges in mind. For example, with gradients we need to ensure we have a fallback background color or image for when gradients aren't supported. For text-shadow, we need to ensure that the contrast between the text and the element background is sufficient when the shadow is not drawn.
Of all new CSS3 properties, transform is the one where backwards compatibility is the most difficult to ensure. Ironically, it's precisely because transforms don't affect the page layout that they cause such difficulty. For example, in order to accommodate say a heading rotated 90 degree to run horizontally along the left hand side of the text which follows it, we need to create whitespace to ensure the heading does not overlap the text. We might do that with margin, or padding. We're also likely to want to remove the whitespace where the heading has been rotated away from, by, for example, using negative margin on the paragraph following the heading. But, what happens if transforms aren't supported? The heading text will be overlapped by the paragraph below it.
In order to use transforms for more sophisticated page layout along these lines, a solution like Modernizr, which enables different CSS to be applied based on the support, or absence of support for various CSS3 features like transforms is indispensable.
Transformations are typically most easily used in a way that is backwards compatible where animated transforms create a transition between states in an application. We're all most likely used to sliding or flipping transitions between states in iOS and other mobile apps. CSS transforms can be used for these transitions, in conjunction with CSS Transitions, and where transforms aren't supported (in which case it's unlikely transitions will be as well), your users simply see an abrupt change in state.
However you plan to use transforms, as with every other aspect of web development, keep in mind those browsers which don't support them, and ensure your user's experience isn't diminished to the point where information or functionality is denied them because their browser doesn't support it.
Browser Support
As we mentioned, despite the still rather experimental nature of support for CSS 2D Transforms, they are now widely supported in modern browsers including:
Internet Explorer 9 and up
Firefox 3.5 up
Safari 3.2 up
Chrome 10 and up
Opera 10.6 and up
iOS 3.2 and up
Opera Mobile 11 and higher
Android 2.1 and up
So, support is widespread, and constantly improving. While there are definitely challenges associated with using 2D Transforms, they're a powerful, and worthwhile addition to the repertoire of developers, and will only gain in value. What are you going to do with them?
One of the most powerful features of CSS3 are transforms, which allow us to take any element in an HTML document, and while not changing its effect on the page layout, rotate it, translate it (move it left, right, up and down), skew it and scale it. CSS3 provides both 2D and 3D transforms, but […]
Getting your head around CSS3 radial gradients We recently took a detailed look at linear gradients in CSS3. If you’ve not read that, you might like to spend a few minutes doing so, as the concepts are very similar, and I don’t spend quite as much time in this article on the fundamentals of gradients […]
In this session, we’ll take a look at all of the possibilities and explore what works and where — from the simplest effects, to creative usability enhancements including the combination of CSS with mobile Javascript frameworks.
With most browsers adding increasing support, and the simplicity of providing fallbacks for those that don’t, CSS3 gradients are something we can start to use right now. They benefit our users with faster websites and ourselves with more time in our hands to spend in other things, since they are easy to create, edit and update. A very powerful feature that can also be utilized for a surprising number of design effects, even ones that don’t resemble gradients at all. In this talk, Lea will explore CSS3 gradients in great depth and it’s almost guaranteed that no matter your expertise level, you will walk out having learned new things.
Find out how to creatively use new features of CSS3 (gradients, multiple backgrounds, generated content, and many more) to give life to your design ideas, make them adaptable and maintainable, and provide the best experience possible on an array of platforms.