It’s all started with a tweet:
Context
So we’re all on the same page, what Hugo means is, there are two different ways you can “move” elements.
- Give the element
relative
,absolute
, orfixed
positioning. Then you can use thetop
,right
,left
,bottom
(or any combination therein) to move the objects around. - Ensure the element had a
display
value ofblock
orinline-block
and then use the transform valuetranslate()
,translateX()
, ortranslateY()
to move the element.
“Better”, v1
My first thought on what “better” meant in this context is which one is more appropriate to use under different circumstances. Which leads me to say: “don’t confuse positioning with design-y motion.”
Case in point. You have a button. You want to apply an effect to that button so that in it’s :active
state it nudges down 2 pixels to mimic a “pushed” effect. That is a design-y motion that should be done with translate()
. You could do it with top
or bottom
and relative positioning, but then you are confusing the concepts of positioning and design-y motion.
Let’s say somewhere else in the app you absolutely position a button (perfectly legit). Now when that top: 2px;
gets applied to the button in it’s :active state, that button will likely go zooming off someplace you didn’t expect, possibly making the button unclickable.
Using translate()
will always “nudge” the element from it’s current position which is perfect for an effect like this, or really any design-specific motion.
“Better”, v2
What Hugo was more likely getting at is performance. It has become common generic advice that using translate()
to move elements has better performance than using top/right/bottom/left. But does the data hold up? Let’s take a look.
To start, I made a very simple animation of a red ball animating back and forth.
To my naked eye, in the latest stable Chrome (23) and a Retina MacBook Pro loaded with RAM, the translate()
version does perform slightly better. I can see very slightly choppiness on the top/left version. Perception is important, but let’s look at real data.
In the Chrome dev tools, you can click over to the “Timeline” tab, then onto “Frames”, and then press the circle “Record” button along the bottom. With the animation running, start the recording for a little bit then stop it. The data is best if no other web sites are visible particularly if they are doing any animation.
In the top/left version, you can see occasional spikes above the line marked “60 FPS”, or sixty frames per second. That’s the line we try and stay under as that equates to perfectly smooth perceived motion.
But wait
This gets more complicated. I started talking with Paul Irish who works on the Google Chrome team. Paul thought that because these “paints” are so simple, it’s probably not the best true performance indicator. Paul took my demos and upped the complexity. Instead of a red ball, Josh Hibberts MacBook Pro. Instead of a white background, Nate Eagle’s upholstery.
Things got weird when Paul’s examples showed the reverse of what we expected. The top/left version looks smoother than the translate()
version. And surprisingly, the Frames timeline didn’t show any big differences.
This is where Paul started to dig a lot deeper into this weird world. He came up with lots of interesting stuff! Paul talked to another Paul on the Chrome Team, Paul Lewis, who agreed that it is “smarter to use translate()
for design-y motion.” But went on to say that there is more to this than frame rate. With translate()
, you get sub-pixel animation which is a kind of blurring between pixels that usually leads to smoother animation.
With subpixel [animations] you lose clarity, which is correct. The key is to hold for longer on rounded values at the extremes so your eyes get the satisfaction of clarity but the smoothness of motion.
Paul Irish Digs Way Deeper
I’m gonna just pass this over to Paul. He did a 13-minute video you should watch. It explains all this fancy GPU stuff and subpixel rendering and all that.
Very interesting. Great tweet, Hugo!
Thanks, Chris and Paul for taking the time to work this through.
Hey Chris, thanks a lot for such a post! You and Paul did a wonderful job to cover the topic here. Problem solved! ;)
Great tweet, Hugo!
It has been a good experience especially watching Paul’s screencast.
Hello, i tried with chrome and it was much smoother with translate. Weird !
Transitions and animations are almost always smoother on webkit :)
yep. translate was smoother for me. o.O
Same for me on firefox.
Great article Chris.
Those first two red ball links go to the same place though :)
Correct link for top/left one: http://codepen.io/chriscoyier/pen/pBCax
Sorry, should use the full link rather than the pen link: http://codepen.io/chriscoyier/full/pBCax
(What a pity I can’t edit my first comment. There go an enormous number of vertical pixels.)
Thanks, fixed. Gonna bury since it was a temporary issue.
Was looking forward to the answer to this question. Thank you both for the in depth research!
In Safari 6 the translate version was way smoother than the top/left version.
I agree.
On iOS6, translate is much faster as well.
Yah it’s important to look at how all the other browsers perform with the different methods as well, desktop and mobile. The good news being: they all do better with translate.
Same thing for Firefox Nightly 20.
In Chrome on iPad the translate version is much smoother than the top/left version.
the top/left version looks ugly!
Changing top/left/right/left moves the DOM element inside window. So it means everything is recalculate and redraw (since those modifications could change how other elements behave).
using translate(), you’re not touching anything in the DOM & how it behaves. Only how it renders. That’s a HUGE difference that explains the performance difference first, then also make things working differently. The element itself move, with all its CSS, rather than changing its CSS parameters.
You can see this difference using a background-attachment: fixed and then change top/left values, or change translateX() value.
And as a result, correct me if I’m wrong, doesn’t the clickable area of an element move around with the trbl method, but NOT with the translate?
Andy, as the entire layer moves, I believe that ‘clickable area’ does move: http://jsfiddle.net/joshnh/pyagP/
Right you are. I swore I saw a demo somewhere where the thing moved on :hover and the hot area stayed put . . . Must have been something else.
And a brave soul to use JSFiddle instead of CodePen around these parts! :)
As CM pointed out, the first demo link is stronger.
Also have to agree with other commenters, for the heavy demo, in Chrome, the translate is smoother which is the opposite of what your post suggest.
strong = wrong* :P
Such an interesting read, as per usual! Thank you!
This feels like a dumb question, but, is there any difference in browser compatibility of the two methods? and/or any difference in ease of writing browser-compatible CSS? (is either more or less compatible, does either lend itself to simpler coding with fewer CSS work-arounds, etc.?)
Things got weird when Paul’s examples showed the reverse of what we expected. The top/left version looks smoother than the translate() version. — In Firefox 17.0.1 in Win7 x64
translate()
looks WAY smoother thantop/left
, but only after the object has moved the first time. The first time the object moves, it does look choppy.Subtle, but really interesting to see the variation in your examples, now I know it is worth trying both ways when things don’t look quite right.
This is great! I’ve always remained a top/left/bottom/right guy for doing stuff like sliding in menus simply because translate isn’t supported in IE8, and I didn’t feel like writing extra CSS. However, this definitively proves that using translate is worth the extra effort. Duly noted.
With IE10 the translate() looks perfectly smooth but the other is pretty choppy with 10 MBPs. The ball they look the same. Even with one MBP though the top/left is a bit choppy
So my answer turned out to be correct then. Good!
I noticed the SwipeJS library was using
translate
for 1:1 swiping and animations on smart phones. I was curious why the author was using translate, so I replaced it with a negative margin and then withposition:relative
to compare. The difference was huge, so I quickly switched back totranslate
. On mobile clients, where computing power is limited, it’s the difference between very choppy, and smooth animations.I read that in order to activate iPhones hardware acceleration you needed to use translate…
I found this to be true when I made a simple dropdown using jQuery slideDown/slideUp…it was choppy on the iPhone…but when I switched to just switching out classes and using transitions and translate the performance was much better…
I’d be interested to see how translate3d measures up. I use translate3d in my Liquid Slider because I thought there was a performance boost, specifically on iOS devices. Is this still accurate?
Thank you both for posting this. It was great to toy with the Chrome Dev Tools on some of my own animations. Keep it coming!
Here on FF17, translate() is MUCH better, especially when I hit “Add 10 more Macbooks”.
Using top/left, the animation is very choppy and the sub-elements (like the opening) lid do not all move together with the rest of the macbook.
Mind. Blown.
Watched Paul’s video, too, fantastic stuff. Did a project a while back that was super heavy on left/right animation, might just have to go back and update it.
Very good article. Thanks for sharing!
nice tweet and post!
the discussion is good and it could be expanded to other browsers, like Firefox or Opera for good C:
Interestingly, on Ubuntu with firefox, of the red ball version, the top/left was slightly smoother. With the macbook example, the translate was much smoother.
This just proves why multiple weekly visits to css-tricks/Coyierland is imperative. They address every little web nuance with scientific discipline, drilling down to accurate info time after time. One of the www’s consistently best info resources. Minor but interesting question, brilliant links and responses for advanced knowledge. Kudos again.
Did someone say my name?
I’m delighted that my super-complicated radial gradients have finally been of service to mankind.
I know I’m a little late to the party, but I thought you guys might find this interesting…
I’m seeing that top/left is MUCH faster in most browsers when more elements are animated. See the comparison at http://www.greensock.com/js/speed.html. The translate() technique is literally 400% slower (or more) under heavy stress. the only exception is iOS Safari. Weird.
So I think the performance gains you’re seeing with translate() are only applicable in certain scenarios like when a few elements are animating concurrently and/or they use effects like opacity, box-shadow, etc. But there’s a threshold where the “hardware acceleration” juice actually becomes a significant bottleneck (thanks to Paul Lewis for pointing that out). Then again, the sub-pixel rendering can be nice if you’re not animating many elements.
Great discussion, guys.
Just to add my findings: Chrome latest (23.0.1271.97) looks much smoother in the complex example using translate() with 1 Macbook, but most weirdly the performance doesn’t degrade when adding tonnes more Macbook images, whereas the top/left grinds to a halt exponentially! Must be some kind of super-awesome optimization going on that I could never hope to understand.
Nice post, I have found that the latest builds of FF and Chrome are much smoother, but the fact remains that we want to move towards using lots of nice CSS3 effects, but the user’s are holding this back on projects… At the end of the day as a developer you must build a site that is as usable as possible for the user base.
Muy Interesante me gusto :D
Careful if you use this method to animate a panel containing form elements (Firefox bug): when those elements are focus (or text inputs are typed in) the panel will move independently of any values you use to detect or reposition the panel (and the values will be out-of-sync). It’s annoying. There’s a bug report somewhere at mozilla.
in the mac book examples the translate is very smooth and top/left is laggy for me in both firefox and chrome. how do you say top/left is smoother??