PageSourceSearch

https://blog.alexmaccaw.com/all-you-need-to-know-about-css-transitions/

html alexmaccaw.com collected 2026-10-02 05:42:54 UTC 46,498 bytes, 665 lines download raw bytes

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&#x27;s a lot more to the spec than first meets the eye.
38
39In this post I&#x27;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&#x27;s a lot more to the spec than first meets the eye.
48
49In this post I&#x27;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.