1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>All you need to know about CSS Transitions</title> 8 <link rel="stylesheet" href="https://blog.alexmaccaw.com/assets/built/screen.css?v=1FXruzGxHeJ1cx31"> 9 <link rel="preconnect" href="https://fonts.gstatic.com"> 10 <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,400;0,700;0,800;1,400;1,700&display=swap"> 11 12
12<script> 13 var siteUrl = 'https://blog.alexmaccaw.com'; 14 </script>
14 15 16
16<script> 17 var localTheme = localStorage.getItem('dawn_theme'); 18 switch (localTheme) { 19 case 'dark': 20 document.documentElement.classList.add('theme-dark'); 21 break; 22 case 'light': 23 document.documentElement.classList.add('theme-light'); 24 break; 25 default: 26 break; 27 } 28 </script>
28 29 30 <link rel="canonical" href="https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/"> 31 <meta name="referrer" content="no-referrer-when-downgrade"> 32 33 <meta property="og:site_name" content="Alex MacCaw"> 34 <meta property="og:type" content="article"> 35 <meta property="og:title" content="All you need to know about CSS Transitions"> 36 <meta property="og:description" content="CSS3 transitions bring simple and elegant animations to web applications, but 37there's a lot more to the spec than first meets the eye. 38 39In this post I'm going to delve into some of the more complicated parts of CSS 40transitions, from chaining and events to hardware acceleration and"> 41 <meta property="og:url" content="https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/"> 42 <meta property="article:published_time" content="2013-01-03T00:00:00.000Z"> 43 <meta property="article:modified_time" content="2021-03-18T23:21:01.000Z"> 44 <meta name="twitter:card" content="summary"> 45 <meta name="twitter:title" content="All you need to know about CSS Transitions"> 46 <meta name="twitter:description" content="CSS3 transitions bring simple and elegant animations to web applications, but 47there's a lot more to the spec than first meets the eye. 48 49In this post I'm going to delve into some of the more complicated parts of CSS 50transitions, from chaining and events to hardware acceleration and"> 51 <meta name="twitter:url" content="https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/"> 52 <meta name="twitter:label1" content="Written by"> 53 <meta name="twitter:data1" content="Alex MacCaw"> 54 <meta name="twitter:site" content="@maccaw"> 55 <meta name="twitter:creator" content="@maccaw"> 56 57
57<script type="application/ld+json"> 58{ 59 "@context": "https://schema.org", 60 "@type": "Article", 61 "publisher": { 62 "@type": "Organization", 63 "name": "Alex MacCaw", 64 "url": "https://blog.alexmaccaw.com/", 65 "logo": { 66 "@type": "ImageObject", 67 "url": "https://blog.alexmaccaw.com/favicon.ico", 68 "width": 48, 69 "height": 48 70 } 71 }, 72 "author": { 73 "@type": "Person", 74 "name": "Alex MacCaw", 75 "url": "https://blog.alexmaccaw.com/author/captains/", 76 "sameAs": [ 77 "https://x.com/maccaw" 78 ] 79 }, 80 "headline": "All you need to know about CSS Transitions", 81 "url": "https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/", 82 "datePublished": "2013-01-03T00:00:00.000Z", 83 "dateModified": "2021-03-18T23:21:01.000Z", 84 "description": "CSS3 transitions bring simple and elegant animations to web applications, but\nthere's a lot more to the spec than first meets the eye.\n\nIn this post I'm going to delve into some of the more complicated parts of CSS\ntransitions, from chaining and events to hardware acceleration and animation\nfunctions.\n\nLetting the browser control animations sequences allows it to optimize\nperformance and efficiency by altering the frame rate, minimizing paints and\noffloading some of the work to the GPU.\n\nBrowser", 85 "mainEntityOfPage": "https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/" 86} 87 </script>
87 88 89 <meta name="generator" content="Ghost 6.68"> 90 <link rel="alternate" type="application/rss+xml" title="Alex MacCaw" href="https://blog.alexmaccaw.com/rss/"> 91
91<script defer src="https://cdn.jsdelivr.net/ghost/portal@~2.71/umd/portal.min.js" data-i18n="true" data-ghost="https://blog.alexmaccaw.com/" data-key="570fa0443e71b0eaa0a2fde050" data-api="https://captains-log.ghost.io/ghost/api/content/" data-locale="en" crossorigin="anonymous"></script>
91<style id="gh-members-styles">.gh-post-upgrade-cta-content, 92.gh-post-upgrade-cta { 93 display: flex; 94 flex-direction: column; 95 align-items: center; 96 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; 97 text-align: center; 98 width: 100%; 99 color: #ffffff; 100 font-size: 16px; 101} 102 103.gh-post-upgrade-cta-content { 104 border-radius: 8px; 105 padding: 40px 4vw; 106} 107 108.gh-post-upgrade-cta h2 { 109 color: #ffffff; 110 font-size: 28px; 111 letter-spacing: -0.2px; 112 margin: 0; 113 padding: 0; 114} 115 116.gh-post-upgrade-cta p { 117 margin: 20px 0 0; 118 padding: 0; 119} 120 121.gh-post-upgrade-cta small { 122 font-size: 16px; 123 letter-spacing: -0.2px; 124} 125 126.gh-post-upgrade-cta a { 127 color: #ffffff; 128 cursor: pointer; 129 font-weight: 500; 130 box-shadow: none; 131 text-decoration: underline; 132} 133 134.gh-post-upgrade-cta a:hover { 135 color: #ffffff; 136 opacity: 0.8; 137 box-shadow: none; 138 text-decoration: underline; 139} 140 141.gh-post-upgrade-cta a.gh-btn { 142 display: block; 143 background: #ffffff; 144 text-decoration: none; 145 margin: 28px 0 0; 146 padding: 8px 18px; 147 border-radius: 4px; 148 font-size: 16px; 149 font-weight: 600; 150} 151 152.gh-post-upgrade-cta a.gh-btn:hover { 153 opacity: 0.92; 154}</style>
154<script async src="https://js.stripe.com/v3/"></script>
154 155
155<script defer src="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/sodo-search.min.js" data-key="570fa0443e71b0eaa0a2fde050" data-styles="https://cdn.jsdelivr.net/ghost/sodo-search@~1.8/umd/main.css" data-sodo-search="https://captains-log.ghost.io/" data-locale="en" crossorigin="anonymous"></script>
155 156 157 <link href="https://blog.alexmaccaw.com/webmentions/receive/" rel="webmention"> 158
158<script defer src="/public/cards.min.js?v=ShRHxgy4po8zN-Wf"></script>
158 159 <link rel="stylesheet" type="text/css" href="/public/cards.min.css?v=WwnU9jw5ancNC8Gc"> 160
160<script defer src="/public/member-attribution.min.js?v=AKG4hWena9j3yX3I"></script>
160 161
161<script defer src="/public/ghost-stats.min.js?v=vFcCUf6ZQ0Hyhc8h" data-stringify-payload="false" data-datasource="analytics_events" data-storage="localStorage" data-host="https://blog.alexmaccaw.com/.ghost/analytics/api/v1/page_hit" tb_site_uuid="957e9aa9-675d-4d31-b66f-c1205c9c1bc4" tb_post_uuid="1e8c1a96-3b42-4ae4-b90c-1774a320435c" tb_post_type="post" tb_member_uuid="undefined" tb_member_status="undefined" tb_gift_link=""></script>
161<style>:root {--ghost-accent-color: #8B5CF6;}</style> 162
162<script> 163 var gh_search_key = '3363af0becbc5172a77825c038'; 164 var gh_search_migration = 'v1'; 165</script>
165 166 167<style> 168 blockquote { 169 text-align: left; 170 } 171</style> 172</head> 173 174<body class="post-template"> 175 <svg width="0" height="0" style="display: none;"> 176 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="arrow-left"> 177 <path d="M26.667 14.667v2.667h-16L18 24.667l-1.893 1.893L5.547 16l10.56-10.56L18 7.333l-7.333 7.333h16z"></path> 178 </symbol> 179 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="arrow-right"> 180 <path d="M5.333 14.667v2.667h16L14 24.667l1.893 1.893L26.453 16 15.893 5.44 14 7.333l7.333 7.333h-16z"></path> 181 </symbol> 182 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="brightness-2"> 183 <path 184 d="M13.333 2.667c-2.427 0-4.707.667-6.667 1.8 4 2.307 6.667 6.6 6.667 11.533s-2.667 9.227-6.667 11.533c1.96 1.133 4.24 1.8 6.667 1.8 7.36 0 13.333-5.973 13.333-13.333S20.693 2.667 13.333 2.667z"> 185 </path> 186 </symbol> 187 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="chevron-left"> 188 <path d="M20.547 22.107L14.44 16l6.107-6.12L18.667 8l-8 8 8 8 1.88-1.893z"></path> 189 </symbol> 190 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="chevron-right"> 191 <path d="M11.453 22.107L17.56 16l-6.107-6.12L13.333 8l8 8-8 8-1.88-1.893z"></path> 192 </symbol> 193 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="circle-half-full"> 194 <path 195 d="M16 2.667c-7.36 0-13.333 5.973-13.333 13.333s5.973 13.333 13.333 13.333c7.36 0 13.333-5.973 13.333-13.333s-5.973-13.333-13.333-13.333zM16 5.333c5.893 0 10.667 4.773 10.667 10.667s-4.773 10.667-10.667 10.667v-21.333z"> 196 </path> 197 </symbol> 198 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="dots-horizontal"> 199 <path 200 d="M21.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM13.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0zM5.333 16c0-1.473 1.194-2.667 2.667-2.667v0c1.473 0 2.667 1.194 2.667 2.667v0c0 1.473-1.194 2.667-2.667 2.667v0c-1.473 0-2.667-1.194-2.667-2.667v0z"> 201 </path> 202 </symbol> 203 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="facebook-box"> 204 <path 205 d="M6.667 4h18.667c1.467 0 2.667 1.2 2.667 2.667v18.667c0 1.467-1.2 2.667-2.667 2.667H6.667A2.675 2.675 0 0 1 4 25.334V6.667C4 5.2 5.2 4 6.667 4zM24 6.667h-3.333A4.672 4.672 0 0 0 16 11.334v3.333h-2.667v4H16V28h4v-9.333h4v-4h-4V12c0-.733.6-1.333 1.333-1.333H24v-4z"> 206 </path> 207 </symbol> 208 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="facebook"> 209 <path 210 d="M22.667 2.667V8H20c-.92 0-1.333 1.08-1.333 2v3.333h4v5.333h-4v10.667h-5.333V18.666h-4v-5.333h4V8a5.332 5.332 0 0 1 5.333-5.333h4z"> 211 </path> 212 </symbol> 213 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="linkedin"> 214 <path 215 d="M25.333 4c1.473 0 2.667 1.194 2.667 2.667v0 18.667c0 1.473-1.194 2.667-2.667 2.667v0h-18.667c-1.473 0-2.667-1.194-2.667-2.667v0-18.667c0-1.473 1.194-2.667 2.667-2.667v0h18.667zM24.667 24.667v-7.067c0-2.401-1.946-4.347-4.347-4.347v0c-1.133 0-2.453 0.693-3.093 1.733v-1.48h-3.72v11.16h3.72v-6.573c0-1.027 0.827-1.867 1.853-1.867 1.031 0 1.867 0.836 1.867 1.867v0 6.573h3.72zM9.173 11.413c1.237 0 2.24-1.003 2.24-2.24v0c0-1.24-1-2.253-2.24-2.253-1.244 0-2.253 1.009-2.253 2.253v0c0 1.24 1.013 2.24 2.253 2.24zM11.027 24.667v-11.16h-3.693v11.16h3.693z"> 216 </path> 217 </symbol> 218 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" id="loader"> 219 <path opacity="0.3" fill="currentColor" 220 d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946 s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634 c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z" />
221 <path fill="currentColor" 222 d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 C22.32,8.481,24.301,9.057,26.013,10.047z"> 223 <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" 224 dur="0.5s" repeatCount="indefinite" /> 225 </path> 226 </symbol> 227 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="magnify"> 228 <path 229 d="M12.667 4a8.667 8.667 0 0 1 8.667 8.667c0 2.147-.787 4.12-2.08 5.64l.36.36h1.053l6.667 6.667-2 2-6.667-6.667v-1.053l-.36-.36a8.689 8.689 0 0 1-5.64 2.08C7.88 21.334 4 17.454 4 12.667S7.88 4 12.667 4zm0 2.667c-3.333 0-6 2.667-6 6s2.667 6 6 6 6-2.667 6-6-2.667-6-6-6z"> 230 </path> 231 </symbol> 232 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="menu-down"> 233 <path d="M9.333 13.333L16 20l6.667-6.667H9.334z"></path> 234 </symbol> 235 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="rss-box"> 236 <path 237 d="M6.667 4h18.667c1.467 0 2.667 1.2 2.667 2.667v18.667c0 1.467-1.2 2.667-2.667 2.667H6.667A2.675 2.675 0 0 1 4 25.334V6.667C4 5.2 5.2 4 6.667 4zM10 20c-1.107 0-2 .893-2 2s.893 2 2 2 2-.893 2-2-.893-2-2-2zm-2-6.667V16c4.413 0 8 3.587 8 8h2.667c0-5.893-4.773-10.667-10.667-10.667zM8 8v2.667c7.36 0 13.333 5.973 13.333 13.333H24c0-8.84-7.16-16-16-16z"> 238 </path> 239 </symbol> 240 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="star"> 241 <path 242 d="M16 23.027L24.24 28l-2.187-9.373 7.28-6.307-9.587-.827-3.747-8.827-3.747 8.827-9.587.827 7.267 6.307L7.759 28l8.24-4.973z"> 243 </path> 244 </symbol> 245 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="table-of-contents"> 246 <path d="M3 9h14V7H3v2m0 4h14v-2H3v2m0 4h14v-2H3v2m16 0h2v-2h-2v2m0-10v2h2V7h-2m0 6h2v-2h-2v2z"></path> 247 </symbol> 248 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="twitter-box"> 249 <path 250 d="M6.667 4h18.667c1.467 0 2.667 1.2 2.667 2.667v18.667c0 1.467-1.2 2.667-2.667 2.667H6.667A2.675 2.675 0 0 1 4 25.334V6.667C4 5.2 5.2 4 6.667 4zm16.946 8.44c.64-.533 1.387-1.173 1.72-1.88-.547.28-1.2.453-1.92.547.667-.48 1.213-1.107 1.493-1.96-.693.373-1.4.693-2.28.853-2.067-2.493-7.013-.467-6.133 3.267-3.48-.213-5.6-1.787-7.36-3.72-1 1.627-.133 4.093 1.053 4.773-.613-.04-1.08-.227-1.52-.44.053 2.053 1.187 3.04 2.773 3.573a4.47 4.47 0 0 1-1.52.04c.493 1.427 1.52 2.32 3.28 2.507-1.2 1.013-3.413 1.72-5.2 1.44 1.533.973 3.28 1.747 5.707 1.64 5.88-.267 9.813-4.48 9.907-10.64z"> 251 </path> 252 </symbol> 253 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="twitter"> 254 <path 255 d="M29.947 8a11.423 11.423 0 0 1-3.28.92 5.738 5.738 0 0 0 2.507-3.173 11.52 11.52 0 0 1-3.627 1.4C24.494 6 23.014 5.334 21.334 5.334c-3.133 0-5.693 2.56-5.693 5.72 0 .453.053.893.147 1.307A16.261 16.261 0 0 1 4.001 6.388a5.663 5.663 0 0 0-.773 2.867c0 1.987 1 3.747 2.547 4.747-.947 0-1.827-.267-2.6-.667v.04a5.724 5.724 0 0 0 4.587 5.613 5.644 5.644 0 0 1-2.574.093c.72 2.253 2.813 3.933 5.333 3.973-1.947 1.547-4.413 2.453-7.107 2.453-.453 0-.907-.027-1.36-.08A16.19 16.19 0 0 0 10.827 28c10.507 0 16.28-8.72 16.28-16.28 0-.253 0-.493-.013-.747A11.42 11.42 0 0 0 29.947 8z"> 256 </path> 257 </symbol> 258 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="white-balance-sunny"> 259 <path 260 d="M4.733 24.72l1.88 1.88 2.4-2.387L7.12 22.32zm9.934 5.213h2.667V26h-2.667zM16 7.333c-4.413 0-8 3.587-8 8s3.587 8 8 8 8-3.587 8-8c0-4.427-3.587-8-8-8zm10.667 9.334h4V14h-4zm-3.68 7.546l2.4 2.387 1.88-1.88-2.387-2.4zm4.28-18.266l-1.88-1.88-2.4 2.387 1.893 1.893zM17.333.733h-2.667v3.933h2.667zM5.333 14h-4v2.667h4zm3.68-7.547l-2.4-2.387-1.88 1.88 2.387 2.4 1.893-1.893z"> 261 </path> 262 </symbol> 263 <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" id="window-close"> 264 <path 265 d="M17.947 16l7.387 7.387v1.947h-1.947L16 17.947l-7.387 7.387H6.666v-1.947L14.053 16 6.666 8.613V6.666h1.947L16 14.053l7.387-7.387h1.947v1.947L17.947 16z"> 266 </path> 267 </symbol> 268</svg> 269 <div class="site"> 270 <header class="site-header container"> 271 <div class="header-left"> 272 <a class="logo" href="https://blog.alexmaccaw.com">
273 <span class="logo-text">Alex MacCaw</span> 274 </a> 275 </div> 276 <nav class="main-nav hidden-xs hidden-sm hidden-md"> 277 <a class="menu-item menu-item-home" 278 href="https://blog.alexmaccaw.com/">Home</a> 279 <a class="menu-item menu-item-about" 280 href="https://blog.alexmaccaw.com/about/">About</a> 281 282 <button class="button-text menu-item-button js-modal" data-modal="search" aria-label="Search"> 283 Search 284 </button> 285 </nav> 286 287 <button class="button-text hidden-lg hidden-xl js-modal" data-modal="search" aria-label="Search"> 288 Search 289 </button> 290 <div class="burger hidden-lg hidden-xl"> 291 <div class="burger-bar"></div> 292 <div class="burger-bar"></div> 293 </div> 294 295 <div class="mobile-menu hidden-lg hidden-xl"> 296 <div class="container"> 297 <nav class="mobile-nav"> 298 <a class="menu-item menu-item-home" 299 href="https://blog.alexmaccaw.com/">Home</a> 300 <a class="menu-item menu-item-about" 301 href="https://blog.alexmaccaw.com/about/">About</a> 302 303 <button class="button-text menu-item members-login" data-portal="signin">Login</button> 304 <button class="button-text menu-item menu-item-cta members-subscribe" data-portal="signup">Subscribe</button> 305 </nav> 306 </div> 307 </div> 308 <div class="header-right hidden-xs hidden-sm hidden-md"> 309 <button class="button-text menu-item members-login" data-portal="signin">Login</button> 310 <button class="button-text menu-item menu-item-cta members-subscribe" data-portal="signup">Subscribe</button> 311 </div> 312</header> 313 314 <header class="sticky"> 315 <div class="sticky-title">All you need to know about CSS Transitions</div> 316 <button class="button-icon sticky-toc-button" aria-label="Table of Contents"> 317 <svg class="icon"> 318 <use xlink:href="#table-of-contents"></use> 319 </svg> 320 <div class="sticky-toc"></div> 321 </button> 322 <div class="sticky-track"> 323 <div class="sticky-progress"></div> 324 </div> 325 </header> 326 <div class="site-content"> 327 328<div class="content-area"> 329 <main class="site-main"> 330 <article class="single post no-image"> 331 <header class="single-header kg-canvas"> 332 <div class="single-meta"> 333 <span class="single-meta-item single-meta-date"> 334 <time datetime="2013-01-03"> 335 Jan 3, 2013 336 </time> 337 </span> 338 <span class="single-meta-item single-meta-length"> 339 9 min read 340 </span> 341 </div> 342 <h1 class="single-title">All you need to know about CSS Transitions</h1> 343 </header> 344 <div class="single-content kg-canvas u-text-format"> 345 <p>CSS3 transitions bring simple and elegant animations to web applications, but there's a lot more to the spec than first meets the eye.</p><p>In this post I'm going to delve into some of the more complicated parts of CSS transitions, from chaining and events to hardware acceleration and animation functions.</p><p>Letting the browser control animations sequences allows it to optimize performance and efficiency by altering the frame rate, minimizing paints and offloading some of the work to the GPU.</p><h2 id="browser-support">Browser support</h2><p><a href="https://developer.mozilla.org/en-US/docs/CSS/Tutorials/Using_CSS_transitions?ref=blog.alexmaccaw.com">CSS transitions</a> are supported in practically every version of Firefox, Safari and Chrome. They're supported in IE 10 and onwards. If CSS animations aren't supported in a given browser, than the properties will be applied instantly, gracefully degrading.</p><p>Webkit based browsers (Safari and Chrome), still require <code>-webkit</code> prefixes for animations and gradients, but these are soon being <a href="https://bugs.webkit.org/show_bug.cgi?id=93136&ref=blog.alexmaccaw.com">removed</a>.</p><h2 id="applying-transitions">Applying transitions</h2><p>
345A simple way of applying transitions is with CSS pseudo-classes, such as <code>:hover</code>. Notice we're specifying the property name, the length of transition, and one of the default timing functions, <code>linear</code> [<a href="http://jsfiddle.net/maccman/Vvscq/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>.element { 346 height: 100px; 347 transition: height 2s linear; 348} 349 350.element:hover { 351 height: 200px; 352} 353</code></pre><p>When the <code>:hover</code> pseudo-class is activated, the height will be transitioned linearly from <code>100px</code> to <code>200px</code> over a period of 2 seconds.</p><p><code>duration</code> is the only required item in the transition shorthand. The browser defaults to a timing function of <code>ease</code>, and a property of <code>all</code>, unless these are provided.</p><p>We don't want to be restricted to using psuedo-classes when it comes to activating transitions - clearly that's not very flexible. The solution is to programmatically add and remove classes [<a href="http://jsfiddle.net/maccman/E9cnL/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>/* CSS */ 354.element { 355 opacity: 0.0; 356 transform: scale(0.95) translate3d(0,100%,0); 357 transition: transform 400ms ease, opacity 400ms ease; 358} 359 360.element.active { 361 opacity: 1.0; 362 transform: scale(1.0) translate3d(0,0,0); 363} 364 365.element.inactive { 366 opacity: 0.0; 367 transform: scale(1) translate3d(0,0,0); 368} 369 370// JS with jQuery 371var active = function(){ 372 $('.element').removeClass('inactive').addClass('active'); 373}; 374 375var inactive = function(){ 376 $('.element').removeClass('active').addClass('inactive'); 377}; 378</code></pre><p>In the example above, we've got two different transitions, the element slides up when activated, and fades out when deactivated. All the JavaScript does is toggle the two classes <code>active</code> and <code>inactive</code>.</p><h2 id="transitioning-gradients">Transitioning gradients</h2><p>Not every CSS property can be transitioned, and the basic rule is that you can only transition through absolute values. For example, you can't transition between a <code>height</code> of <code>0px</code> to <code>auto</code>. The browser can't calculate the intermediate transition values, so the property change is instant. Oli Studholme has conveniently provided <a href="http://oli.jp/2010/css-animatable-properties/?ref=blog.alexmaccaw.com">a full list of transition support properties</a>.</p><p>The other major property that can't be transitioned between is background gradients (although pure colors are supported). There's no technical reason behind this limitation, it's just taking a while for the browsers to implement support.</p><p>In the mean time, there are a few good workarounds. The first involves adding a transparency to the gradient, and then transitioning between background colors. For example [<a href="http://jsfiddle.net/maccman/az2Xz/?ref=blog.alexmaccaw.com">demo</a>]:</p><pre><code>.panel { 379 background-color: #000; 380 background-image: linear-gradient(rgba(255, 255, 0, 0.4), #FAFAFA); 381 transition: background-color 400ms ease; 382} 383 384.panel:hover { 385 background-color: #DDD; 386} 387</code></pre><p>If the gradient is continuous, you can transition the <code>background-position</code> as <a href="http://sapphion.com/2011/10/css3-gradient-transition-with-background-position/?ref=blog.alexmaccaw.com">documented here</a>. Otherwise, your last resort is to create two elements, one overlaid on top of the other, and transition their opacity [<a href="http://jsfiddle.net/maccman/qaQyB/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>.element { 388 width: 100px; 389 height: 100px; 390 position: relative; 391 background: linear-gradient(#C7D3DC,#5B798E); 392} 393 394.element .inner { 395 content: ''; 396 position: absolute; 397 left: 0; top: 0; right: 0; bottom: 0; 398 background: linear-gradient(#DDD, #FAFAFA); 399 opacity: 0; 400 transition: opacity 1s linear; 401} 402 403.element:hover .inner { 404 opacity: 1; 405} 406</code></pre><p>The caveats to the latter approach are that it does require extra markup, and the inner div can catch pointer events. Pseudo elements, such as <code>:before</code> and <code>:after</code> would be an ideal use-case here, but unfortunately only Firefox supports pseudo element transitions. Eliott Sprehn is working on supp
406ort for Webkit, which is <a href="https://bugs.webkit.org/show_bug.cgi?id=92591&ref=blog.alexmaccaw.com">coming soon</a>.</p><h2 id="hardware-acceleration">Hardware acceleration</h2><p>Transitioning certain properties, such as <code>left</code> and <code>margin</code> causes the browser to  <em>recalculating styles</em> every frame. This is fairly expensive, and can lead to unnecessary re-paints, especially if you have a lot of elements on the screen. This is especially noticeable in less powerful devices, such as mobiles.</p><p>This solution is to offload the rendering to the GPU using CSS transformations. In simple terms, this turns the element into an image during the transition, avoiding any style recalculations which greatly increases performance. A simple way of forcing the browser to hardware render an element is to set the transformation's z axis, which you can do with <code>translate3d</code>:</p><pre><code>transform: translate3d(0,0,0); 407</code></pre><p>Now, this isn't a magic cure to performance problems, and comes with lots of issues of its own. You should only use hardware acceleration when it's required, and certainly not enable it on every element.</p><p>For example, hardware acceleration can cause subtle font issues, such as a font appearing to lose its weight. This is due to a bug where subpixel anti-aliasing isn't supported when an element is being hardware accelerated. You can see a clear difference between the two rendering modes:</p><figure class="kg-card kg-image-card"><img src="https://svbtleusercontent.com/inline_maccman_24418277747802_raw.png" class="kg-image" alt="antialiasing.png" loading="lazy"></figure><p>The short-term fix, <a href="http://news.ycombinator.com/item?id=4954482&ref=blog.alexmaccaw.com">albeit</a> <a href="http://www.usabilitypost.com/2010/08/26/font-smoothing/?ref=blog.alexmaccaw.com">controversial</a>, is to disable subpixel anti-aliasing completely. However, be sure to understand the <a href="http://lists.w3.org/Archives/Public/www-style/2012Oct/0014.html?ref=blog.alexmaccaw.com">caveats in doing so</a>.</p><pre><code> font-smoothing: antialiased; 408</code></pre><p>In addition, different browsers use different hardware acceleration libraries, which can cause cross-browser problems. For example, whilst Chrome and Safari are both built on WebKit, Chrome uses Skia for graphics rendering while Safari uses CoreGraphics. The differences between the two are subtle, but real.</p><p>You can use Chrome's Inspector to Profile the page, showing all the repaints. Additionally you can show <em>paint triangles</em> in the Inspector's options, and even turn on Composited Render Layer Borders in about:flags to see which layers are operating on the GPU. The key is to reduce paints by batch updating the DOM, and move as much as possible to the GPU.</p><figure class="kg-card kg-image-card"><img src="https://svbtleusercontent.com/inline_maccman_24424148470284_raw.png" class="kg-image" alt="Painting" loading="lazy"></figure><p>If you're having display issues between browsers with hardware acceleration, such as flickering or juddering, make sure you're not nestling elements with the <code>transform3d()</code> CSS property set. As a last resort, try having browser specific transformations.</p><p>It's worth noting that the <code>translate3d</code> hack is becoming less relevant. In fact recent builds of Chrome automatically use the GPU for opacity and 2d transitions. iOS6 Safari has explicitly disabled this trick, and requires <a href="http://indiegamr.com/ios6-html-hardware-acceleration-changes-and-how-to-fix-them/?ref=blog.alexmaccaw.com">yet more workarounds</a>.</p><h2 id="clipping">Clipping</h2><p>To take advantage of GPU rendering, you'll need to avoid style recalculations by using CSS transformations rather than properties like <code>width</code>. What do you do though if you <em>do</em> need to animate an element's width? The solution is clipping.</p><p>In the example below, you can see a search box with two transition states. The second expanded state is hidden by a clipping element.</p><figure class="kg-card kg-image-card"><img src="https://svbtleusercontent.com/inline_maccman_24418694845836_raw.png" class="kg-image" alt="Clipping" loading="lazy"></figure><p>
408To transition to the expanded width, all we need to is translate the X axis left. The key thing here is that we're using <code>translate3d</code> rather than altering the element's width [<a href="http://jsfiddle.net/maccman/tqNaM/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>.clipped { 409 overflow: hidden; 410 position: relative; 411} 412 413.clipped .clip { 414 right: 0px; 415 width: 45px; 416 height: 45px; 417 background: url(/images/clip.png) no-repeat 418} 419 420input:focus { 421 -webkit-transform: translate3d(-50px, 0, 0); 422} 423</code></pre><p>By ensuring that we're not recalculating the element's width every frame, the transition will a whole lot smoother and performant.</p><h2 id="timing-functions">Timing functions</h2><p>So far we've been using some of the browser's pre-defined timing functions: <code>linear</code>, <code>ease</code>, <code>ease-in</code>, <code>ease-out</code> and <code>ease-in-out</code>. For more complex timing functions we're going to have to write our own timing function by specifying four points along a cubic-bezier curve.</p><pre><code>transition: -webkit-transform 1s cubic-bezier(.17,.67,.69,1.33); 424</code></pre><p>Rather than guessing at values, it's often easier to either use a bunch of <a href="http://easings.net/?ref=blog.alexmaccaw.com">pre-defined curves</a>, or play around with a <a href="http://cubic-bezier.com/?ref=blog.alexmaccaw.com">graphing tool</a>.</p><figure class="kg-card kg-image-card"><img src="https://svbtleusercontent.com/inline_maccman_24418729821816_raw.png" class="kg-image" alt="Cubic-bezier" loading="lazy"></figure><p>Notice you can drag the values out of bounds and produce a bouncing transition, for example:</p><pre><code>transition: all 600ms cubicâbezier(0.175, 0.885, 0.32, 1.275); 425</code></pre><h2 id="programmatic-transitions">Programmatic transitions</h2><p>Writing transitions in CSS is all very well, but sometimes you need a bit more control, especially when it comes to chaining transitions. Luckily we can not only invoke transitions from JavaScript, but also define them.</p><p>CSS transitions take a magical <code>all</code> property which ensures that any property changes are transitioned. Let's see how to use this in practice [<a href="http://jsfiddle.net/maccman/5QdSf/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>var defaults = { 426 duration: 400, 427 easing: '' 428}; 429 430$.fn.transition = function (properties, options) { 431 options = $.extend({}, defaults, options); 432 properties['webkitTransition'] = 'all ' + options.duration + 'ms ' + options.easing; 433 $(this).css(properties); 434}; 435</code></pre><p>Now we have this jQuery function <code>$.fn.transition</code>, which we can use to programmatically invoke transitions.</p><pre><code>$('.element').transition({background: 'red'}); 436</code></pre><h2 id="transition-callback">Transition callback</h2><p>The next step to chaining transitions is having transition end callbacks. You can achieve this in Webkit, by listening to the <code>webkitTransitionEnd</code> event. For other browsers, you'll need to do a <a href="https://gist.github.com/4414792?ref=blog.alexmaccaw.com">bit of sniffing</a> to find the right event name.</p><pre><code> var callback = function () { 437 // ... 438 } 439 440 $(this).one('webkitTransitionEnd', callback) 441 $(this).css(properties); 442</code></pre><p>Be aware that sometimes this event doesn't fire, usually in the case when properties don't change or a paint isn't triggered. To ensure we always get a callback, let's set a timeout that'll trigger the event manually.</p><pre><code>$.fn.emulateTransitionEnd = function(duration) { 443 var called = false, $el = this; 444 $(this).one('webkitTransitionEnd', function() { called = true; }); 445 var callback = function() { if (!called) $($el).trigger('webkitTransitionEnd'); }; 446 setTimeout(callback, duration); 447}; 448</code></pre><p>Now we can invoke <code>$.fn.emulateTransitionEnd()</code> before we set the element's CSS to ensure our transition end callback is triggered [<a href="http://jsfiddle.net/maccman/YUuQU/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>$(this).one('webkitTransitionEnd', callback); 449$(this).emulateTransitionEnd(options.duration + 50); 450$(this).css(properties); 451</code></pre><h2 id="chaining-transitions">Chaining transitions</h2><p>So now we can programmatically apply transitions, getting callbacks when they finish, we can start queuing transitions. We could write our own queue to do this, but as we're using jQuery we might as well tap into the library's existing functionality.</p><p>jQuery provides two main functions to communicate with its queuing API, <code>$.fn.queue(callback)</code> and <code>$.fn.dequeue()</code>. The former adds a callback to the queue, while the latter executes the next item on the queue.</p><p>In other words we need to set our CSS transition inside a <code>$.fn.queue</code> callback, and then make sure we invoke <code>$.fn.dequeue</code> when the transition is complete [<a href="http://jsfiddle.net/maccman/ZB3Gb/?ref=blog.alexmaccaw.com">demo</a>].</p><pre><code>var $el = $(this); 452$el.queue(function(){ 453 $el.one('webkitTransitionEnd', function(){ 454 $el.dequeue(); 455 }); 456 $el.css(properties); 457}); 458</code></pre><p>That's example is fairly simple, but it lets us build up complex chained animations, and even use jQuery's delay() function; for example:</p><pre><code>$('.element').transition({left: '20px'}) 459 .delay(200) 460 .transition({background: 'red'}); 461</code></pre><h2 id="redrawing">Redrawing</h2><p>Often when transitioning, you'll have two sets of CSS properties. The initial properties that the animation should start at, and the final set of properties the transition should end on.</p><pre><code>$('.element').css({left: '10px'}) 462 .transition({left: '20px'}); 463</code></pre><p>However, you'll find that if you apply both sets of properties, one immediately after the other, then the browser tries to optimize the property changes, ignoring your initial properties and preventing a transition. Behind the scenes, browsers batch up property changes before painting which, while usually speeding up rendering, can sometimes have adverse affects.</p><p>The solution is to force a redraw between applying the two sets of properties. A simple method of doing this is just by accessing a DOM element's <code>offsetHeight</code> property, like so [<a href="http://jsfiddle.net/maccman/3uuWf/?ref=blog.alexmaccaw.com">demo</a>]:</p><pre><code>$.fn.redraw = function(){ 464 $(this).each(function(){ 465 var redraw = this.offsetHeight; 466 }); 467}; 468</code></pre><p>This will work in most browsers, but I've had occasions in Android where this hasn't been enough. The alternative is to either use timeouts, or by toggling a class name.</p><pre><code>$('.element').css({left: '10px'}) 469 .redraw() 470 .transition({left: '20px'}); 471</code></pre><h2 id="the-future">The future</h2><p>Transitions are being actively worked on, and the <a href="https://dvcs.w3.org/hg/FXTF/raw-file/tip/web-anim/index.html?ref=blog.alexmaccaw.com">next spec</a> looks really promising. The proposals include a new JavaScript API focussing on addressing some of the existing limitations to transitions, and giving developers much more flexibility.</p><p>In fact, you can find a <a href="https://github.com/web-animations/web-animations-js?ref=blog.alexmaccaw.com">shim on the new API on GitHub</a>. It involves instantiating a <code>Animation</code> constructor, passing in an element to animate, the properties to animate to, and various other options such as a delay.</p><pre><code>var anim = new Animation(elem, { left: '100px' }, 3); 472anim.play(); 473</code></pre><p>With this new API you can synchronize animations, provide custom timing functions, and get completion callbacks. This is truly exciting stuff!</p><h2 id="transitions">Transitions</h2><p>By now, you hopefully have a deeper understanding of CSS transitions, and how a simple API can be combined to produce complex and rich effects.</p><p>Most of the JavaScript examples come straight out of the source of <a href="https://github.com/maccman/gfx?ref=blog.alexmaccaw.com">GFX</a>, a jQuery CSS transition library. As well as the <a href="https://github.com/maccman/gfx/blob/master/src/gfx.coffee?ref=blog.alexmaccaw.com">core library</a>, I've included a number of <a href="https://github.com/maccman/gfx/blob/master/src/gfx.effects.c
473offee?ref=blog.alexmaccaw.com">additional effects</a>, such as slide in/out, explode in/out and 3d flipping.</p><hr><p><em>Thanks to <a href="http://paulirish.com/?ref=blog.alexmaccaw.com">Paul Irish</a> for reviewing this article.</em></p><p><em>Incidentally, I've been turning the contents of this post into a talk. If you know or organize a conference that would be suitable for this material, please do get in touch! Over the last year I spoke at six conferences, and I'm keen to do even more in 2013.</em></p> 474 <section class="single-cta"> 475 <h2 class="single-cta-title">Enjoying these posts? Subscribe for more</h2> 476 <button class="button single-cta-button" data-portal="signup">Subscribe now</button> 477 <br> 478 <button class="button-text single-cta-footer" data-portal="signin">Already have an account? Sign in</button> 479 </section> 480 </div> 481 <footer class="single-footer container medium"> 482 <div class="single-footer-left"> 483 <div class="navigation navigation-previous"> 484 <a class="navigation-link" href="/humble-beginnings/" 485 aria-label="Previous post"> 486 <svg class="icon navigation-icon"> 487 <use xlink:href="#arrow-left"></use> 488 </svg> 489 </a> 490 </div> 491 </div> 492 <div class="single-footer-middle"> 493 <div class="single-footer-top"> 494 <h3 class="single-footer-title">Published by:</h3> 495 <div class="author-list"> 496 <div 497 class="author-image-placeholder u-placeholder square"> 498 <a href="/author/captains/" title="Alex MacCaw"> 499 <img class="author-image lazyload u-object-fit" 500 data-srcset="" 501 src="" 502 srcset="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 503 alt="Alex MacCaw"> 504 </a> 505 </div> 506 </div> 507 </div> 508 <div class="single-footer-bottom"> 509 <div class="share"> 510 <a class="share-link share-link-facebook" 511 href="https://www.facebook.com/sharer.php?u=https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/" 512 target="_blank" rel="noopener noreferrer"> 513 <svg class="icon icon-facebook"> 514 <use xlink:href="#facebook"></use> 515 </svg> 516 Share 517 </a> 518 <a class="share-link share-link-twitter" 519 href="https://twitter.com/intent/tweet?url=https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/&text=All%20you%20need%20to%20know%20about%20CSS%20Transitions" 520 target="_blank" rel="noopener noreferrer"> 521 <svg class="icon icon-twitter"> 522 <use xlink:href="#twitter"></use> 523 </svg> 524 Tweet 525 </a> 526 </div> 527 </div> 528 </div> 529 <div class="single-footer-right"> 530 <div class="navigation navigation-next"> 531 <a class="navigation-link" href="/life-todo/" 532 aria-label="Next post"> 533 <svg class="icon navigation-icon"> 534 <use xlink:href="#arrow-right"></use> 535 </svg> 536 </a> 537 </div> 538 </div> 539 </footer> 540</article> </main> 541</div> 542 </div> 543 <footer class="site-footer container"> 544 <div class="social"> 545 <a class="social-item social-item-twitter" 546 href="https://x.com/maccaw" target="_blank" 547 rel="noopener noreferrer" aria-label="Twitter"> 548 <svg class="icon"> 549 <use xlink:href="#twitter-box"></use> 550 </svg> 551 </a> 552 <a class="social-item social-item-rss" 553 href="https://feedly.com/i/subscription/feed/https://blog.alexmaccaw.com/rss/"
554 target="_blank" rel="noopener noreferrer" aria-label="RSS"> 555 <svg class="icon"> 556 <use xlink:href="#rss-box"></use> 557 </svg> 558 </a> 559 </div> 560 561 <nav class="footer-nav"> 562 563 <a class="menu-item js-theme" href="#" data-system="System theme" data-dark="Dark theme" data-light="Light theme"> 564 <svg class="icon theme-icon theme-icon-system"> 565 <use xlink:href="#circle-half-full"></use> 566 </svg> 567 <svg class="icon theme-icon theme-icon-dark"> 568 <use xlink:href="#brightness-2"></use> 569 </svg> 570 <svg class="icon theme-icon theme-icon-light"> 571 <use xlink:href="#white-balance-sunny"></use> 572 </svg> 573 <span class="theme-text">Toggle theme</span> 574 </a> 575 </nav> 576</footer> <div class="modal-overlay"> 577 <div class="modal modal-search"> 578 <div class="form-wrapper"> 579 <input class="modal-input search-input" type="search" placeholder="Enter keyword..."> 580 <button class="form-button search-button" aria-label="Search"> 581 <svg class="icon icon-search"> 582 <use xlink:href="#magnify"></use> 583 </svg> 584 <svg class="icon icon-close"> 585 <use xlink:href="#window-close"></use> 586 </svg> 587 </button> 588 </div> 589 <div class="popular-wrapper"> 590 <h4 class="popular-title">Popular tags</h4> 591 <div class="popular-feed"> 592 <a class="popular" href="/tag/lifestyle/">lifestyle</a> 593 </div> 594 </div> 595 <div class="search-result"></div> 596 </div> 597 <button class="button-icon modal-close" aria-label="Close"> 598 <svg class="icon icon-close"> 599 <use xlink:href="#window-close"></use> 600 </svg> 601 </button> 602</div> <!-- Root element of PhotoSwipe. Must have class pswp. --> 603<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> 604 <!-- Background of PhotoSwipe. 605 It's a separate element as animating opacity is faster than rgba(). --> 606 <div class="pswp__bg"></div> 607 608 <!-- Slides wrapper with overflow:hidden. --> 609 <div class="pswp__scroll-wrap"> 610 <!-- Container that holds slides. 611 PhotoSwipe keeps only 3 of them in the DOM to save memory. 612 Don't modify these 3 pswp__item elements, data is added later on. --> 613 <div class="pswp__container"> 614 <div class="pswp__item"></div> 615 <div class="pswp__item"></div> 616 <div class="pswp__item"></div> 617 </div> 618 619 <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. --> 620 <div class="pswp__ui pswp__ui--hidden"> 621 <div class="pswp__top-bar"> 622 <!-- Controls are self-explanatory. Order can be changed. --> 623 <div class="pswp__counter"></div> 624 625 <button class="pswp__button pswp__button--close" title="Close (Esc)"></button> 626 <button class="pswp__button pswp__button--share" title="Share"></button> 627 <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button> 628 <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button> 629 630 <!-- Preloader demo https://codepen.io/dimsemenov/pen/yyBWoR --> 631 <!-- element will get class pswp__preloader--active when preloader is running --> 632 <div class="pswp__preloader"> 633 <div class="pswp__preloader__icn"> 634 <div class="pswp__preloader__cut"> 635 <div class="pswp__preloader__donut"></div> 636 </div> 637 </div> 638 </div> 639 </div> 640 641 <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap"> 642 <div class="pswp__share-tooltip"></div> 643 </div> 644 645 <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)"></button> 646 <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)"></button> 647 648 <div class="pswp__caption"> 649 <div class="pswp__caption__center"></div> 650 </div> 651 </div> 652 </div> 653</div> </div> 654 655
655<script 656 src="https://code.jquery.com/jquery-3.5.1.min.js" 657 integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" 658 crossorigin="anonymous"> 659 </script>
659 660
660<script src="https://blog.alexmaccaw.com/assets/built/main.min.js?v=x4xJC3WsRoeFKQ_B"></script>
660 661 662 663</body> 664 665</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.