Save 37% off PRO during our Black Friday Sale! »


96270e4c3e5e9806cf7245475c00b275?s=47 Addy Osmani
February 15, 2011



Don't share. Just a draft. Thx.


Addy Osmani

February 15, 2011


  1. Rendering Performance Case Studies Gone in 60 frames per second

    Velocity Europe @addyosmani
  2. #perfmatters

  3. What we build for the web is evolving.

  4. None
  5. Users ❤ snappy experiences.

  6. Silky smooth scrolling Buttery animation Great performance everywhere. High performance

    web apps have:
  7. None
  8. Speed must be treated as an essential design feature.

  9. The fastest web page is..

  10. None
  11. Everything we add increases the work the browser has to

    do to put pixels on the screen
  12. None
  13. Network Compute Render 3 Pillars Of Performance

  14. Mobile web performance goals 1. Connectivity - Show above the

    fold content in < 1s - Serve critical path CSS in first 14KB 2. Max of 200ms server response time 3. 60fps scrolling, 60fps transitions 4. Speed index under 1000* * average time visual parts of the page display per WebPageTest
  15. Today we’ll focus on this. 1. Connectivity - Show above

    the fold content in < 1s - Serve critical path CSS in first 14KB 2. Max of 200ms server response time 3. 60fps scrolling, 60fps transitions 4. Speed index under 1000
  16. Rendering performance impacts user experience.

  17. "In an A/B test, we slowed down scrolling from 60fps

    down to 30fps. Engagement collapsed" ~ Shane O'Sullivan * in their native app, fluctuating between 30 to 45fps. * Consistent 30fps performed second best
  18. None
  19. "We tested pre-fetching JS in search results, which caused jank

    in our pages. All business metrics got worse" ~ Jonathan Klein
  20. Response rates matter.

  21. See the flow of how Chrome renders pages

  22. DevTools Timeline

  23. None
  24. drag here to filter record/stop 30fps = 33ms per frame,

    60fps = 16ms per frame
  25. what do these records mean?

  26. Let’s dive in!

  27. Parse HTML

  28. GET / HTTP /1.1 host: Make a request

  29. None
  30. <!DOCTYPE html> <html class="no-js"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <title>MA RESPONSE</title> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="css/main.css"> </head> <body> <section> <h1>HTML wizaaaaard</h1> <p>I am teh HTML masterz.</p> </section> </body> </html> Get a response
  31. <!DOCTYPE html> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title MA RESPONSE</title>

    <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="css/main.css"> </head> HTML wizaaaaard</h1> I am teh HTML masterz.</p> </section> </body> </html> Parse HTML Get a response <html> <head> <title> <link> <body> <section> <h1> <p>
  32. <html> <body> <script> <section> <h1> <img> <p> <head> <title> <link>

    Get a response
  33. Recalculate Style

  34. DOM CSS + Recalculate Style Styling the DOM

  35. Render tree Styling the DOM

  36. <html> <body> <section> <h1> <img> <p> Styling the DOM

  37. <html> <body> <section> <h1> <img> Styling the DOM section p

    { display: none; }
  38. <html> <body> <section> <h1> <img> Styling the DOM section h1:after

    { content: "<333 pseudo elemz" } <h1:after>
  39. Layout

  40. html, body { marg: 0; width: 300px; height: 700px; background:

    white; color: white; } body { background: #888; } section { display: block; margin-top:30%; padding-top:60px; width:100%; background:#444; } section h1:after{ content: '<3 pseudo'; height: 40px; margin-top: 10px; display: block; } img { margin: 30px; border-radius: 4px; border: 3px solid white; box-shadow: 0 2px 2px rgba(0,0,0,3); } Layout <html> <body> <section> <h1> <h1:after> <img> Laying out the document
  41. Vector Raster Rasterizer

  42. drawPoints drawOval drawRectangle drawRoundedRect drawPath drawBitmap drawText drawLine drawArc clear

    translate save restore clipPath moveTo lineTo Rasterizer
  43. Paint

  44. Rasterizer

  45. Image Resize

  46. Image Decode + Resize Draw Bitmap

  47. Move Elements

  48. Composite Layers

  49. Composite Layers Layers

  50. All together, you should expect to see..

  51. width margin border left/top box-shadow border-radius background outline transform opacity

  52. DOM to pixels on the screen Recalc styles Calc styles

    that apply to elements Layout Generate geometry for each element Paint Fill pixels for each element into layers (Paint) Composite layers Draw layers out to the screen
  53. What about frame rate?

  54. Frame rate Rate at which a device produces consecutive images

    to the screen
  55. To see what’s impacting rendering, look at FPS

  56. A consistent frame rate is our ideal

  57. Why target 60fps?

  58. Match the refresh rate of the devices you are targeting.

  59. Jank Disruption in consistent frame rate that manifests itself visually

  60. < 15fps Your users will perceive jerkiness and jank

  61. None
  62. 30fps Smooth as long as it’s a constant 30fps

  63. 60fps Smooth animations and transitions with no stutter

  64. Frame budget At 60fps, you have 16.7ms budget for Logic

    processing Compute processing Rendering
  65. Frame budget It’s more like 8-10ms budget because - Browser,

    JS engine, renderer processes - Margin for slower devices like mobile.
  66. What causes jank?

  67. Properties that trigger layout (reflow) Correct as of November, 2013.

  68. Correct as of November, 2013.

  69. Drop-shadows Blurs Linear-gradients Fixed background images Heavy styles can cause

    jank* Correct as of November, 2013.
  70. CSS Styles that affect paint, layout

  71. None
  72. Recalculate style triggered when styles are computed or changed. Heavy

    use of JS to rearrange the page (e.g onscroll) is bad
  73. Heavy onscroll() handlers Doing shit inside of scroll is terrible

  74. None
  75. Scrolling Correct as of November, 2013. Watch out for: Unnecessary

    paints: position:fixed overflow:scroll hover effects touch listeners Long paints: Complex CSS Image decodes Large empty layers
  76. Long image decodes and resizes Remember to pre-scale your images!

  77. None
  78. DOM elements with measurably high paint cost Measure what elements

    might be slowing you down.
  79. Too much inside your event handlers

  80. None
  81. Heavy animation or data processing Where possible rely on rAF

    or Web Workers
  82. Position transform: translate(npx, npx); Scale transform: scale(n); Rotation transform: rotate(ndeg);

    Opacity opacity: 0....1; 4 things a browser can animate cheaply Move all your visual effects to these things. Transition at your own risk. translateZ/3d may be required*
  83. None
  84. None
  85. Over-complexity JS is single threaded if timers fired, input handlers

    running. Your rAF callback just won't run
  86. Hardware acceleration GPU compositing

  87. Old-skool painting All your elements get painted into one big

  88. Old-skool painting What if we had separate bitmaps, or "layers"?

  89. Old-skool painting What if we had separate bitmaps, or "layers"?

  90. Layers & Compositing Hardware compositing uses the GPU to help

    build the page Elements are broken out to a bunch of layers Those layers are uploaded to the GPU as textures The GPU composites those textures together
  91. More: DevTools Settings

  92. Useful Settings red shaded rectangles around repainted regions orange borders

    around composited layers yellow border around touch handler listeners
  93. Layer promotion hacks -webkit-transform: translateZ(0); -webkit-transform: translate3d(0,0,0); 1 -webkit-transform: translate3d(0,0,0)

    Use with caution!! Blink/Webkit iOS -webkit-perspective: 1000; -webkit-backface-visibility: hidden; 1 -webkit-transform: translate3d(0,0,0)
  94. None
  95. New! Layers panel Visualize elements promoted to a layer with

    the new layers panel (experimental)
  96. None
  97. Layout thrashing

  98. When JS violently writes, then reads from the DOM repeatedly

    causing reflow
  99. None
  100. The slow way while (i--) { var greenBlockWidth = sizer.offsetWidth;

    ps[i].style.width = greenBlockWidth + 'px'; }
  101. The right way var greenBlockWidth = sizer.offsetWidth; while (i--) {

    ps[i].style.width = greenBlockWidth + 'px'; }
  102. None
  103. Writes to the DOM invalidate layout Browser wants to wait

    until the end of the current frame to reflow.
  104. Querying geometric values before a frame completes, forces early layout.

    Forced synchronous layout
  105. None
  106. It’s a performance killer.

  107. FastDOM Batches DOM reads/writes on the next frame using rAF

    for scheduling.
  108. None
  109. ~ Paul Irish

  110. Case studies

  111. Don’t guess it, test it!

  112. Case study: Flickr with thanks to Scott Schiller @ Flickr

  113. Web seeing a trend of vertical parallax effects.


  115. None
  116. (optimized)

  117. None
  118. But scroll used to be significantly slower.

  119. For each Y pixels of vertical axis scrolling, move an

    absolutely positioned image in the same direction.
  120. For each Y pixels of vertical axis scrolling, move an

    absolutely positioned image in the same direction. window.onscroll() backgroundPosition marginTop or el
  121. window.onscroll = function(e) { var parallax = document.getElementById('parallax-background'); =

    (window.scrollY/2) + 'px'; } Minimal parallax example
  122. Neither marginTop or backgroundPosition alone perform well. They don’t use

    hardware compositing.
  123. Demo (slow)

  124. None
  125. Timeline view

  126. Have the GPU help with accelerating compositing of the expensive

    parts Trick
  127. Elements can be promoted to a layer using translateZ() or

    translate3D() Avoid expensive paints Reminder
  128. window.onscroll = function(e) { var parallax = document.getElementById('parallax-background'); =

    'translate3d(0px,' + (window.scrollY/2) + 'px, 0px)'; } Optimized parallax example
  129. Promoting the element to a new layer

  130. Demo (fast)

  131. None
  132. Timeline view

  133. Twitter Bootstrap 3

  134. None
  135. None
  136. background- image: linear- gradient( to bottom, #ffffff, #e6e6e6);

  137. 100% faster paint time.

  138. BS3 much more viable for sites that need to work

    well on under-powered mobile and tablet devices
  139. BS3 much more viable for sites that need to work

    well on under-powered mobile and tablet devices
  140. Pitchfork

  141. Why is scrolling in this Daft Punk site so slow?

  142. None
  143. None
  144. Pre-scale images where possible to avoid resize cost.

  145. None
  146. Live case study: Pinterest

  147. Post-optimization

  148. None
  149. Pre-optimization

  150. None
  151. None
  152. None
  153. Case study: Google+ with thanks to Steve Kobes @ Google+

  154. Perf went from 12fps to 60fps

  155. None
  156. Jank bustin’

  157. Simplified G+ layout

  158. Simplified G+ layout position:fixed position:fixed

  159. Problem.

  160. A position:fixed element causes a repaint when moved within its

  161. To avoid the repaint, put the element in its own

  162. Simplified G+ layout translateZ(0) translateZ(0)

  163. Caveats of translateZ - more layers = more time compositing

    layers - text anti-aliasing requires an opaque background within the layer - triggers Safari positioning bugs inside iframes
  164. Too many layers? Sometimes a style creates compositing layers for

    all positioned descendants.
  165. Another problem.

  166. G+ styles for card-flip animation

  167. -webkit-backface-visibility: hidden

  168. Causes every descendent element to get its own layer

  169. Remove it, apply it through JS for duration of the

    card animation The Fix!
  170. one last problem

  171. Forced synchronous layouts Modifying the DOM invalidates layout. element.innerHTML =

    '...'; // Layout invalidated.
  172. Measuring the DOM depends on the layout If previously invalidated,

    this forces synchronous layout (since execution cannot continue until the correct value is obtained). alert(element.offsetHeight); // Layout forced.
  173. G+ reduced synchronous layouts cards.forEach(function(card){ appendHTML(card); measure(card); }); write read

    write read.. cards.forEach(function(card){ appendHTML(card); }); cards.forEach(function(card){ measure(card); }); write write read read.. They reduced them from O(n) to O(1) by refactoring a loop
  174. Forced Synchronous Layouts Timeline shows where your code is causing

    synchronous layouts Remember to scroll down for the second stack trace.
  175. Bonus optimization Disable hover effects while scrolling

  176. Bonus optimization Animate with translate instead of left/top

  177. Paint performance tooling in other browsers

  178. There’s now lots of tooling to improve the responsiveness of

  179. IE F12 Developer Tools UI Responsiveness Tool shows frame rate

  180. Firefox DevTools: Paint flashing Highlight areas being painted

  181. WebKit Nightlies: Paint counts of layers

  182. WebKit Nightlies: Reasons for compositing

  183. In summary...

  184. Frame rate matters and can impact engagement

  185. Don’t overdue to the layout. Do reads before writes.

  186. Be mindful of paint costs. Use the DevTools.

  187. Check your perf on desktop and mobile.

  188. Mobile-first performance benchmarking Test on low-end hardware. Get 60fps there.

  189. If you’re building something, set performance objectives up front.

  190. Hit those objectives, add tests to measure and then never

  191. If all goes well, this could be you!

  192. To learn more checkout

  193. Use tools. not rules.

  194. Thank you. @addyosmani +AddyOsmani