CINXE.COM
<!doctype html><html lang="en"><head><title data-rh="true">Airbnb's Trip to Linaria | The Airbnb Tech Blog</title><meta data-rh="true" charset="utf-8"/><meta data-rh="true" name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,maximum-scale=1"/><meta data-rh="true" name="theme-color" content="#000000"/><meta data-rh="true" name="twitter:app:name:iphone" content="Medium"/><meta data-rh="true" name="twitter:app:id:iphone" content="828256236"/><meta data-rh="true" property="al:ios:app_name" content="Medium"/><meta data-rh="true" property="al:ios:app_store_id" content="828256236"/><meta data-rh="true" property="al:android:package" content="com.medium.reader"/><meta data-rh="true" property="fb:app_id" content="542599432471018"/><meta data-rh="true" property="og:site_name" content="Medium"/><meta data-rh="true" property="og:type" content="article"/><meta data-rh="true" property="article:published_time" content="2022-06-16T17:41:48.753Z"/><meta data-rh="true" name="title" content="Airbnb's Trip to Linaria | The Airbnb Tech Blog"/><meta data-rh="true" property="og:title" content="Airbnb’s Trip to Linaria"/><meta data-rh="true" property="al:android:url" content="medium://p/dc169230bd12"/><meta data-rh="true" property="al:ios:url" content="medium://p/dc169230bd12"/><meta data-rh="true" property="al:android:app_name" content="Medium"/><meta data-rh="true" name="description" content="How Linaria, Airbnb's newest choice for web styling, improved both developer experience and web performance"/><meta data-rh="true" property="og:description" content="Learn how Linaria, Airbnb’s newest choice for web styling, improved both developer experience and web performance"/><meta data-rh="true" property="og:url" content="https://medium.com/airbnb-engineering/airbnbs-trip-to-linaria-dc169230bd12"/><meta data-rh="true" property="al:web:url" content="https://medium.com/airbnb-engineering/airbnbs-trip-to-linaria-dc169230bd12"/><meta data-rh="true" property="og:image" content="https://miro.medium.com/v2/resize:fit:1200/1*-qT4pQIPIsxHBZj22sQtag.jpeg"/><meta data-rh="true" property="article:author" content="https://lencioni.medium.com"/><meta data-rh="true" name="author" content="Joe Lencioni"/><meta data-rh="true" name="robots" content="index,noarchive,follow,max-image-preview:large"/><meta data-rh="true" name="referrer" content="unsafe-url"/><meta data-rh="true" property="twitter:title" content="Airbnb’s Trip to Linaria"/><meta data-rh="true" name="twitter:site" content="@AirbnbEng"/><meta data-rh="true" name="twitter:app:url:iphone" content="medium://p/dc169230bd12"/><meta data-rh="true" property="twitter:description" content="Learn how Linaria, Airbnb’s newest choice for web styling, improved both developer experience and web performance"/><meta data-rh="true" name="twitter:image:src" content="https://miro.medium.com/v2/resize:fit:1200/1*-qT4pQIPIsxHBZj22sQtag.jpeg"/><meta data-rh="true" name="twitter:card" content="summary_large_image"/><meta data-rh="true" name="twitter:creator" content="@lencioni"/><meta data-rh="true" name="twitter:label1" content="Reading time"/><meta data-rh="true" name="twitter:data1" content="11 min read"/><link data-rh="true" rel="icon" href="https://miro.medium.com/v2/5d8de952517e8160e40ef9841c781cdc14a5db313057fa3c3de41c6f5b494b19"/><link data-rh="true" rel="search" type="application/opensearchdescription+xml" title="Medium" href="/osd.xml"/><link data-rh="true" rel="apple-touch-icon" sizes="152x152" href="https://miro.medium.com/v2/resize:fill:304:304/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="apple-touch-icon" sizes="120x120" href="https://miro.medium.com/v2/resize:fill:240:240/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="apple-touch-icon" sizes="76x76" href="https://miro.medium.com/v2/resize:fill:152:152/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="apple-touch-icon" sizes="60x60" href="https://miro.medium.com/v2/resize:fill:120:120/10fd5c419ac61637245384e7099e131627900034828f4f386bdaa47a74eae156"/><link data-rh="true" rel="mask-icon" href="https://miro.medium.com/v2/resize:fill:1000:1000/7*GAOKVe--MXbEJmV9230oOQ.png" color="#171717"/><link data-rh="true" rel="preconnect" href="https://glyph.medium.com" crossOrigin=""/><link data-rh="true" id="glyph_preload_link" rel="preload" as="style" type="text/css" href="https://glyph.medium.com/css/unbound.css"/><link data-rh="true" id="glyph_link" rel="stylesheet" type="text/css" href="https://glyph.medium.com/css/unbound.css"/><link data-rh="true" rel="author" href="https://lencioni.medium.com"/><link data-rh="true" rel="canonical" href="https://medium.com/airbnb-engineering/airbnbs-trip-to-linaria-dc169230bd12"/><link data-rh="true" rel="alternate" href="android-app://com.medium.reader/https/medium.com/p/dc169230bd12"/><script data-rh="true" type="application/ld+json">{"@context":"http:\u002F\u002Fschema.org","@type":"NewsArticle","image":["https:\u002F\u002Fmiro.medium.com\u002Fv2\u002Fresize:fit:1200\u002F1*-qT4pQIPIsxHBZj22sQtag.jpeg"],"url":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fairbnbs-trip-to-linaria-dc169230bd12","dateCreated":"2022-06-16T17:41:48.753Z","datePublished":"2022-06-16T17:41:48.753Z","dateModified":"2022-06-16T17:44:30.541Z","headline":"Airbnb's Trip to Linaria | The Airbnb Tech Blog","name":"Airbnb's Trip to Linaria | The Airbnb Tech Blog","description":"How Linaria, Airbnb's newest choice for web styling, improved both developer experience and web performance","identifier":"dc169230bd12","author":{"@type":"Person","name":"Joe Lencioni","url":"https:\u002F\u002Flencioni.medium.com"},"creator":["Joe Lencioni"],"publisher":{"@type":"Organization","name":"The Airbnb Tech Blog","url":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering","logo":{"@type":"ImageObject","width":60,"height":60,"url":"https:\u002F\u002Fmiro.medium.com\u002Fv2\u002Fresize:fit:120\u002F1*JZl-TXoSiG0VmYn3qWLdTA.png"}},"mainEntityOfPage":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fairbnbs-trip-to-linaria-dc169230bd12"}</script><style type="text/css" data-fela-rehydration="554" data-fela-type="STATIC">html{box-sizing:border-box;-webkit-text-size-adjust:100%}*, *:before, *:after{box-sizing:inherit}body{margin:0;padding:0;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:rgba(0,0,0,0.8);position:relative;min-height:100vh}h1, h2, h3, h4, h5, h6, dl, dd, ol, ul, menu, figure, blockquote, p, pre, form{margin:0}menu, ol, ul{padding:0;list-style:none;list-style-image:none}main{display:block}a{color:inherit;text-decoration:none}a, button, input{-webkit-tap-highlight-color:transparent}img, svg{vertical-align:middle}button{background:transparent;overflow:visible}button, input, optgroup, select, textarea{margin:0}:root{--reach-tabs:1;--reach-menu-button:1}#speechify-root{font-family:Sohne, sans-serif}div[data-popper-reference-hidden="true"]{visibility:hidden;pointer-events:none}.grecaptcha-badge{visibility:hidden} /*XCode style (c) Angel Garcia <angelgarcia.mail@gmail.com>*/.hljs {background: #fff;color: black; }/* Gray DOCTYPE selectors like WebKit */ .xml .hljs-meta {color: #c0c0c0; }.hljs-comment, .hljs-quote {color: #007400; }.hljs-tag, .hljs-attribute, .hljs-keyword, .hljs-selector-tag, .hljs-literal, .hljs-name {color: #aa0d91; }.hljs-variable, .hljs-template-variable {color: #3F6E74; }.hljs-code, .hljs-string, .hljs-meta .hljs-string {color: #c41a16; }.hljs-regexp, .hljs-link {color: #0E0EFF; }.hljs-title, .hljs-symbol, .hljs-bullet, .hljs-number {color: #1c00cf; }.hljs-section, .hljs-meta {color: #643820; }.hljs-title.class_, .hljs-class .hljs-title, .hljs-type, .hljs-built_in, .hljs-params {color: #5c2699; }.hljs-attr {color: #836C28; }.hljs-subst {color: #000; }.hljs-formula {background-color: #eee;font-style: italic; }.hljs-addition {background-color: #baeeba; }.hljs-deletion {background-color: #ffc8bd; }.hljs-selector-id, .hljs-selector-class {color: #9b703f; }.hljs-doctag, .hljs-strong {font-weight: bold; }.hljs-emphasis {font-style: italic; } </style><style type="text/css" data-fela-rehydration="554" data-fela-type="KEYFRAME">@-webkit-keyframes k1{0%{opacity:0.8}50%{opacity:0.5}100%{opacity:0.8}}@-moz-keyframes k1{0%{opacity:0.8}50%{opacity:0.5}100%{opacity:0.8}}@keyframes k1{0%{opacity:0.8}50%{opacity:0.5}100%{opacity:0.8}}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE">.a{font-family:medium-content-sans-serif-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif}.b{font-weight:400}.c{background-color:rgba(255, 255, 255, 1)}.l{display:block}.m{position:sticky}.n{top:0}.o{z-index:500}.p{padding:0 24px}.q{align-items:center}.r{border-bottom:solid 1px #F2F2F2}.y{height:41px}.z{line-height:20px}.ab{display:flex}.ac{height:57px}.ae{flex:1 0 auto}.af{color:inherit}.ag{fill:inherit}.ah{font-size:inherit}.ai{border:inherit}.aj{font-family:inherit}.ak{letter-spacing:inherit}.al{font-weight:inherit}.am{padding:0}.an{margin:0}.ao{cursor:pointer}.ap:disabled{cursor:not-allowed}.aq:disabled{color:#6B6B6B}.ar:disabled{fill:#6B6B6B}.au{width:auto}.av path{fill:#242424}.aw{height:25px}.ax{margin-left:16px}.ay{border:none}.az{border-radius:20px}.ba{width:240px}.bb{background:#F9F9F9}.bc path{fill:#6B6B6B}.be{outline:none}.bf{font-family:sohne, "Helvetica Neue", Helvetica, Arial, sans-serif}.bg{font-size:14px}.bh{width:100%}.bi{padding:10px 20px 10px 0}.bj{background-color:transparent}.bk{color:#242424}.bl::placeholder{color:#6B6B6B}.bm{display:inline-block}.bn{margin-left:12px}.bo{margin-right:12px}.bp{border-radius:4px}.bq{margin-left:24px}.br{height:24px}.bx{background-color:#F9F9F9}.by{border-radius:50%}.bz{height:32px}.ca{width:32px}.cb{justify-content:center}.ch{max-width:680px}.ci{min-width:0}.cj{animation:k1 1.2s ease-in-out infinite}.ck{height:100vh}.cl{margin-bottom:16px}.cm{margin-top:48px}.cn{align-items:flex-start}.co{flex-direction:column}.cp{justify-content:space-between}.cq{margin-bottom:24px}.cw{width:80%}.cx{background-color:#F2F2F2}.dd{height:44px}.de{width:44px}.df{margin:auto 0}.dg{margin-bottom:4px}.dh{height:16px}.di{width:120px}.dj{width:80px}.dp{margin-bottom:8px}.dq{width:96%}.dr{width:98%}.ds{width:81%}.dt{margin-left:8px}.du{color:#6B6B6B}.dv{font-size:13px}.dw{height:100%}.ep{color:#FFFFFF}.eq{fill:#FFFFFF}.er{background:rgba(48, 150, 154, 1)}.es{border-color:rgba(48, 150, 154, 1)}.ew:disabled{cursor:inherit !important}.ex:disabled{opacity:0.3}.ey:disabled:hover{background:rgba(48, 150, 154, 1)}.ez:disabled:hover{border-color:rgba(48, 150, 154, 1)}.fa{border-radius:99em}.fb{border-width:1px}.fc{border-style:solid}.fd{box-sizing:border-box}.fe{text-decoration:none}.ff{text-align:center}.fi{margin-right:32px}.fj{position:relative}.fk{fill:#6B6B6B}.fn{background:transparent}.fo svg{margin-left:4px}.fp svg{fill:#6B6B6B}.fr{box-shadow:inset 0 0 0 1px rgba(0, 0, 0, 0.05)}.fs{position:absolute}.fz{margin:0 24px}.gd{background:rgba(255, 255, 255, 1)}.ge{border:1px solid #F2F2F2}.gf{box-shadow:0 1px 4px #F2F2F2}.gg{max-height:100vh}.gh{overflow-y:auto}.gi{left:0}.gj{top:calc(100vh + 100px)}.gk{bottom:calc(100vh + 100px)}.gl{width:10px}.gm{pointer-events:none}.gn{word-break:break-word}.go{word-wrap:break-word}.gp:after{display:block}.gq:after{content:""}.gr:after{clear:both}.gs{line-height:1.23}.gt{letter-spacing:0}.gu{font-style:normal}.gv{font-weight:700}.hq{margin-bottom:-0.27em}.hr{line-height:1.394}.im{align-items:baseline}.in{width:48px}.io{height:48px}.ip{border:2px solid rgba(255, 255, 255, 1)}.iq{z-index:0}.ir{box-shadow:none}.is{border:1px solid rgba(0, 0, 0, 0.05)}.it{margin-left:-12px}.iu{width:28px}.iv{height:28px}.iw{z-index:1}.ix{width:24px}.iy{margin-bottom:2px}.iz{flex-wrap:nowrap}.ja{font-size:16px}.jb{line-height:24px}.jd{margin:0 8px}.je{display:inline}.jf{color:rgba(48, 150, 154, 1)}.jg{fill:rgba(48, 150, 154, 1)}.jj{flex:0 0 auto}.jm{flex-wrap:wrap}.jp{white-space:pre-wrap}.jq{margin-right:4px}.jr{overflow:hidden}.js{max-height:20px}.jt{text-overflow:ellipsis}.ju{display:-webkit-box}.jv{-webkit-line-clamp:1}.jw{-webkit-box-orient:vertical}.jx{word-break:break-all}.jz{padding-left:8px}.ka{padding-right:8px}.lb> *{flex-shrink:0}.lc{overflow-x:scroll}.ld::-webkit-scrollbar{display:none}.le{scrollbar-width:none}.lf{-ms-overflow-style:none}.lg{width:74px}.lh{flex-direction:row}.li{z-index:2}.ll{-webkit-user-select:none}.lm{border:0}.ln{fill:rgba(117, 117, 117, 1)}.lq{outline:0}.lr{user-select:none}.ls> svg{pointer-events:none}.mb{cursor:progress}.mc{margin-left:4px}.md{margin-top:0px}.me{opacity:1}.mf{padding:4px 0}.mi{width:16px}.mk{display:inline-flex}.mq{max-width:100%}.mr{padding:8px 2px}.ms svg{color:#6B6B6B}.nj{margin-left:auto}.nk{margin-right:auto}.nl{max-width:4000px}.nr{clear:both}.nt{cursor:zoom-in}.nu{z-index:auto}.nw{height:auto}.nx{line-height:1.58}.ny{letter-spacing:-0.004em}.nz{font-family:source-serif-pro, Georgia, Cambria, "Times New Roman", Times, serif}.os{margin-bottom:-0.46em}.ot{text-decoration:underline}.ou{line-height:1.12}.ov{letter-spacing:-0.022em}.ow{font-weight:600}.pp{margin-bottom:-0.28em}.pv{margin:auto}.pw{padding-bottom:56.199999999999996%}.px{height:0}.py{padding-bottom:100%}.pz{list-style-type:disc}.qa{margin-left:30px}.qb{padding-left:0px}.qh{max-width:500px}.qi{margin-top:10px}.qj{max-width:728px}.qm{list-style-type:decimal}.qn{font-style:italic}.qo{max-width:1600px}.qp{box-shadow:inset 3px 0 0 0 #242424}.qq{padding-left:23px}.qr{margin-left:-20px}.qs{margin-top:32px}.qt{margin-bottom:14px}.qu{padding-top:24px}.qv{padding-bottom:10px}.qw{background-color:#000000}.qx{height:3px}.qy{width:3px}.qz{margin-right:20px}.ra{margin-bottom:26px}.rb{margin-top:6px}.rc{margin-top:8px}.rd{margin-right:8px}.re{padding:8px 16px}.rf{border-radius:100px}.rg{transition:background 300ms ease}.ri{white-space:nowrap}.rj{border-top:none}.rp{height:52px}.rq{max-height:52px}.rr{box-sizing:content-box}.rs{position:static}.ru{max-width:155px}.sf{margin-bottom:48px}.st{border-radius:2px}.sv{height:64px}.sw{width:64px}.sx{align-self:flex-end}.sy{flex:1 1 auto}.te{padding-right:4px}.tf{font-weight:500}.ts{margin-top:16px}.tt{color:rgba(255, 255, 255, 1)}.tu{fill:rgba(255, 255, 255, 1)}.tv{background:rgba(25, 25, 25, 1)}.tw{border-color:rgba(25, 25, 25, 1)}.tz:disabled{opacity:0.1}.ua:disabled:hover{background:rgba(25, 25, 25, 1)}.ub:disabled:hover{border-color:rgba(25, 25, 25, 1)}.uc{height:0px}.ud{border-bottom:solid 1px #E5E5E5}.ue{margin-top:56px}.uf{margin-top:72px}.ug{padding:24px 0}.uh{margin-bottom:0px}.ui{margin-right:16px}.as:hover:not(:disabled){color:rgba(25, 25, 25, 1)}.at:hover:not(:disabled){fill:rgba(25, 25, 25, 1)}.et:hover{background:rgba(51, 128, 131, 1)}.eu:hover{border-color:rgba(51, 128, 131, 1)}.ev:hover{cursor:pointer}.fl:hover{color:#242424}.fm:hover{fill:#242424}.fq:hover svg{fill:#242424}.ft:hover{background-color:rgba(0, 0, 0, 0.1)}.jc:hover{text-decoration:underline}.jh:hover:not(:disabled){color:rgba(51, 128, 131, 1)}.ji:hover:not(:disabled){fill:rgba(51, 128, 131, 1)}.lp:hover{fill:rgba(8, 8, 8, 1)}.mg:hover{fill:#000000}.mh:hover p{color:#000000}.mj:hover{color:#000000}.mt:hover svg{color:#000000}.rh:hover{background-color:#F2F2F2}.su:hover{background-color:none}.tx:hover{background:#000000}.ty:hover{border-color:#242424}.bd:focus-within path{fill:#242424}.lo:focus{fill:rgba(8, 8, 8, 1)}.mu:focus svg{color:#000000}.nv:focus{transform:scale(1.01)}.lt:active{border-style:none}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (min-width: 1080px)">.d{display:none}.bw{width:64px}.cg{margin:0 64px}.cv{height:48px}.dc{margin-bottom:52px}.do{margin-bottom:48px}.ef{font-size:14px}.eg{line-height:20px}.em{font-size:13px}.eo{padding:5px 12px}.fh{display:flex}.fy{margin-bottom:68px}.gc{max-width:680px}.hm{font-size:42px}.hn{margin-top:1.19em}.ho{line-height:52px}.hp{letter-spacing:-0.011em}.ie{font-size:22px}.if{margin-top:0.92em}.ig{line-height:28px}.il{align-items:center}.kn{border-top:solid 1px #F2F2F2}.ko{border-bottom:solid 1px #F2F2F2}.kp{margin:32px 0 0}.kq{padding:3px 8px}.kz> *{margin-right:24px}.la> :last-child{margin-right:0}.ma{margin-top:0px}.mp{margin:0}.nq{margin-top:56px}.oo{font-size:20px}.op{margin-top:2.14em}.oq{line-height:32px}.or{letter-spacing:-0.003em}.pl{font-size:24px}.pm{margin-top:1.95em}.pn{line-height:30px}.po{letter-spacing:-0.016em}.pu{margin-top:0.94em}.qg{margin-top:1.14em}.ro{margin-bottom:88px}.rz{display:inline-block}.se{padding-top:72px}.sg{flex-direction:row}.sj{margin-bottom:0}.sk{margin-right:20px}.sz{max-width:500px}.tq{line-height:24px}.tr{letter-spacing:0}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (max-width: 1079.98px)">.e{display:none}.lz{margin-top:0px}.qk{margin-left:auto}.ql{text-align:center}.ry{display:inline-block}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (max-width: 903.98px)">.f{display:none}.ly{margin-top:0px}.rx{display:inline-block}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (max-width: 727.98px)">.g{display:none}.lw{margin-top:0px}.lx{margin-right:0px}.rw{display:inline-block}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (max-width: 551.98px)">.h{display:none}.s{display:flex}.t{justify-content:space-between}.bs{width:24px}.cc{margin:0 24px}.cr{height:40px}.cy{margin-bottom:44px}.dk{margin-bottom:32px}.dx{font-size:13px}.dy{line-height:20px}.eh{padding:0px 8px 1px}.fu{margin-bottom:4px}.gw{font-size:32px}.gx{margin-top:1.01em}.gy{line-height:38px}.gz{letter-spacing:-0.014em}.hs{font-size:18px}.ht{margin-top:0.79em}.hu{line-height:24px}.ih{align-items:flex-start}.jk{flex-direction:column}.jn{margin-bottom:2px}.kb{margin:24px -24px 0}.kc{padding:0}.kr> *{margin-right:8px}.ks> :last-child{margin-right:24px}.lj{margin-left:0px}.lu{margin-top:0px}.lv{margin-right:0px}.ml{margin:0}.mv{border:1px solid #F2F2F2}.mw{border-radius:99em}.mx{padding:0px 16px 0px 12px}.my{height:38px}.mz{align-items:center}.nb svg{margin-right:8px}.nm{margin-top:40px}.oa{margin-top:1.56em}.ob{line-height:28px}.oc{letter-spacing:-0.003em}.ox{font-size:20px}.oy{margin-top:1.2em}.oz{letter-spacing:0}.pq{margin-top:0.67em}.qc{margin-top:1.34em}.rk{margin-bottom:80px}.rv{display:inline-block}.sa{padding-top:48px}.sr{margin-bottom:20px}.ss{margin-right:0}.td{max-width:100%}.tg{font-size:24px}.th{line-height:30px}.ti{letter-spacing:-0.016em}.na:hover{border-color:#E5E5E5}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (min-width: 904px) and (max-width: 1079.98px)">.i{display:none}.bv{width:64px}.cf{margin:0 64px}.cu{height:48px}.db{margin-bottom:52px}.dn{margin-bottom:48px}.ed{font-size:14px}.ee{line-height:20px}.ek{font-size:13px}.el{padding:5px 12px}.fg{display:flex}.fx{margin-bottom:68px}.gb{max-width:680px}.hi{font-size:42px}.hj{margin-top:1.19em}.hk{line-height:52px}.hl{letter-spacing:-0.011em}.ib{font-size:22px}.ic{margin-top:0.92em}.id{line-height:28px}.ik{align-items:center}.kj{border-top:solid 1px #F2F2F2}.kk{border-bottom:solid 1px #F2F2F2}.kl{margin:32px 0 0}.km{padding:3px 8px}.kx> *{margin-right:24px}.ky> :last-child{margin-right:0}.mo{margin:0}.np{margin-top:56px}.ok{font-size:20px}.ol{margin-top:2.14em}.om{line-height:32px}.on{letter-spacing:-0.003em}.ph{font-size:24px}.pi{margin-top:1.95em}.pj{line-height:30px}.pk{letter-spacing:-0.016em}.pt{margin-top:0.94em}.qf{margin-top:1.14em}.rn{margin-bottom:88px}.sd{padding-top:72px}.sh{flex-direction:row}.sl{margin-bottom:0}.sm{margin-right:20px}.ta{max-width:500px}.to{line-height:24px}.tp{letter-spacing:0}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (min-width: 728px) and (max-width: 903.98px)">.j{display:none}.w{display:flex}.x{justify-content:space-between}.bu{width:64px}.ce{margin:0 48px}.ct{height:48px}.da{margin-bottom:52px}.dm{margin-bottom:48px}.eb{font-size:13px}.ec{line-height:20px}.ej{padding:0px 8px 1px}.fw{margin-bottom:68px}.ga{max-width:680px}.he{font-size:42px}.hf{margin-top:1.19em}.hg{line-height:52px}.hh{letter-spacing:-0.011em}.hy{font-size:22px}.hz{margin-top:0.92em}.ia{line-height:28px}.ij{align-items:center}.kf{border-top:solid 1px #F2F2F2}.kg{border-bottom:solid 1px #F2F2F2}.kh{margin:32px 0 0}.ki{padding:3px 8px}.kv> *{margin-right:24px}.kw> :last-child{margin-right:0}.mn{margin:0}.no{margin-top:56px}.og{font-size:20px}.oh{margin-top:2.14em}.oi{line-height:32px}.oj{letter-spacing:-0.003em}.pd{font-size:24px}.pe{margin-top:1.95em}.pf{line-height:30px}.pg{letter-spacing:-0.016em}.ps{margin-top:0.94em}.qe{margin-top:1.14em}.rm{margin-bottom:88px}.sc{padding-top:72px}.si{flex-direction:row}.sn{margin-bottom:0}.so{margin-right:20px}.tb{max-width:500px}.tm{line-height:24px}.tn{letter-spacing:0}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="all and (min-width: 552px) and (max-width: 727.98px)">.k{display:none}.u{display:flex}.v{justify-content:space-between}.bt{width:24px}.cd{margin:0 24px}.cs{height:40px}.cz{margin-bottom:44px}.dl{margin-bottom:32px}.dz{font-size:13px}.ea{line-height:20px}.ei{padding:0px 8px 1px}.fv{margin-bottom:4px}.ha{font-size:32px}.hb{margin-top:1.01em}.hc{line-height:38px}.hd{letter-spacing:-0.014em}.hv{font-size:18px}.hw{margin-top:0.79em}.hx{line-height:24px}.ii{align-items:flex-start}.jl{flex-direction:column}.jo{margin-bottom:2px}.kd{margin:24px 0 0}.ke{padding:0}.kt> *{margin-right:8px}.ku> :last-child{margin-right:8px}.lk{margin-left:0px}.mm{margin:0}.nc{border:1px solid #F2F2F2}.nd{border-radius:99em}.ne{padding:0px 16px 0px 12px}.nf{height:38px}.ng{align-items:center}.ni svg{margin-right:8px}.nn{margin-top:40px}.od{margin-top:1.56em}.oe{line-height:28px}.of{letter-spacing:-0.003em}.pa{font-size:20px}.pb{margin-top:1.2em}.pc{letter-spacing:0}.pr{margin-top:0.67em}.qd{margin-top:1.34em}.rl{margin-bottom:80px}.sb{padding-top:48px}.sp{margin-bottom:20px}.sq{margin-right:0}.tc{max-width:100%}.tj{font-size:24px}.tk{line-height:30px}.tl{letter-spacing:-0.016em}.nh:hover{border-color:#E5E5E5}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="print">.rt{display:none}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="(orientation: landscape) and (max-width: 903.98px)">.jy{max-height:none}</style><style type="text/css" data-fela-rehydration="554" data-fela-type="RULE" media="(prefers-reduced-motion: no-preference)">.ns{transition:transform 300ms cubic-bezier(0.2, 0, 0.2, 1)}</style></head><body><div id="root"><div class="a b c"><div class="d e f g h i j k"></div><script>document.domain = document.domain;</script><div class="l c"><div class="l m n o c"><div class="p q r s t u v w x i d y z"><a class="du ag dv bf ak b am an ao ap aq ar as at s u w i d q dw z" href="https://rsci.app.link/?%24canonical_url=https%3A%2F%2Fmedium.com%2Fp%2Fdc169230bd12&%7Efeature=LoOpenInAppButton&%7Echannel=ShowPostUnderCollection&source=---top_nav_layout_nav----------------------------------" rel="noopener follow">Open in app<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="none" viewBox="0 0 10 10" class="dt"><path fill="currentColor" d="M.985 8.485a.375.375 0 1 0 .53.53zM8.75 1.25h.375A.375.375 0 0 0 8.75.875zM8.375 6.5a.375.375 0 1 0 .75 0zM3.5.875a.375.375 0 1 0 0 .75zm-1.985 8.14 7.5-7.5-.53-.53-7.5 7.5zm6.86-7.765V6.5h.75V1.25zM3.5 1.625h5.25v-.75H3.5z"></path></svg></a><div class="ab q"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><button class="bf b dx dy eh dz ea ei eb ec ej ek ee el em eg eo ep eq er es et eu ev ew ex ey ez fa fb fc fd bm fe ff" data-testid="headerSignUpButton">Sign up</button></span></p><div class="ax l"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerSignInButton" rel="noopener follow" href="/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&source=post_page---top_nav_layout_nav-----------------------global_nav-----------">Sign in</a></span></p></div></div></div><div class="p q r ab ac"><div class="ab q ae"><a class="af ag ah ai aj ak al am an ao ap aq ar as at ab" aria-label="Homepage" data-testid="headerMediumLogo" rel="noopener follow" href="/?source=---top_nav_layout_nav----------------------------------"><svg xmlns="http://www.w3.org/2000/svg" width="719" height="160" fill="none" viewBox="0 0 719 160" class="au av aw"><path fill="#242424" d="m174.104 9.734.215-.047V8.02H130.39L89.6 103.89 48.81 8.021H1.472v1.666l.212.047c8.018 1.81 12.09 4.509 12.09 14.242V137.93c0 9.734-4.087 12.433-12.106 14.243l-.212.047v1.671h32.118v-1.665l-.213-.048c-8.018-1.809-12.089-4.509-12.089-14.242V30.586l52.399 123.305h2.972l53.925-126.743V140.75c-.687 7.688-4.721 10.062-11.982 11.701l-.215.05v1.652h55.948v-1.652l-.215-.05c-7.269-1.639-11.4-4.013-12.087-11.701l-.037-116.774h.037c0-9.733 4.071-12.432 12.087-14.242m25.555 75.488c.915-20.474 8.268-35.252 20.606-35.507 3.806.063 6.998 1.312 9.479 3.714 5.272 5.118 7.751 15.812 7.368 31.793zm-.553 5.77h65.573v-.275c-.186-15.656-4.721-27.834-13.466-36.196-7.559-7.227-18.751-11.203-30.507-11.203h-.263c-6.101 0-13.584 1.48-18.909 4.16-6.061 2.807-11.407 7.003-15.855 12.511-7.161 8.874-11.499 20.866-12.554 34.343q-.05.606-.092 1.212a50 50 0 0 0-.065 1.151 85.807 85.807 0 0 0-.094 5.689c.71 30.524 17.198 54.917 46.483 54.917 25.705 0 40.675-18.791 44.407-44.013l-1.886-.664c-6.557 13.556-18.334 21.771-31.738 20.769-18.297-1.369-32.314-19.922-31.042-42.395m139.722 41.359c-2.151 5.101-6.639 7.908-12.653 7.908s-11.513-4.129-15.418-11.63c-4.197-8.053-6.405-19.436-6.405-32.92 0-28.067 8.729-46.22 22.24-46.22 5.657 0 10.111 2.807 12.236 7.704zm43.499 20.008c-8.019-1.897-12.089-4.722-12.089-14.951V1.309l-48.716 14.353v1.757l.299-.024c6.72-.543 11.278.386 13.925 2.83 2.072 1.915 3.082 4.853 3.082 8.987v18.66c-4.803-3.067-10.516-4.56-17.448-4.56-14.059 0-26.909 5.92-36.176 16.672-9.66 11.205-14.767 26.518-14.767 44.278-.003 31.72 15.612 53.039 38.851 53.039 13.595 0 24.533-7.449 29.54-20.013v16.865h43.711v-1.746zM424.1 19.819c0-9.904-7.468-17.374-17.375-17.374-9.859 0-17.573 7.632-17.573 17.374s7.721 17.374 17.573 17.374c9.907 0 17.375-7.47 17.375-17.374m11.499 132.546c-8.019-1.897-12.089-4.722-12.089-14.951h-.035V43.635l-43.714 12.551v1.705l.263.024c9.458.842 12.047 4.1 12.047 15.152v81.086h43.751v-1.746zm112.013 0c-8.018-1.897-12.089-4.722-12.089-14.951V43.635l-41.621 12.137v1.71l.246.026c7.733.813 9.967 4.257 9.967 15.36v59.279c-2.578 5.102-7.415 8.131-13.274 8.336-9.503 0-14.736-6.419-14.736-18.073V43.638l-43.714 12.55v1.703l.262.024c9.459.84 12.05 4.097 12.05 15.152v50.17a56.3 56.3 0 0 0 .91 10.444l.787 3.423c3.701 13.262 13.398 20.197 28.59 20.197 12.868 0 24.147-7.966 29.115-20.43v17.311h43.714v-1.747zm169.818 1.788v-1.749l-.213-.05c-8.7-2.006-12.089-5.789-12.089-13.49v-63.79c0-19.89-11.171-31.761-29.883-31.761-13.64 0-25.141 7.882-29.569 20.16-3.517-13.01-13.639-20.16-28.606-20.16-13.146 0-23.449 6.938-27.869 18.657V43.643L545.487 55.68v1.715l.263.024c9.345.829 12.047 4.181 12.047 14.95v81.784h40.787v-1.746l-.215-.053c-6.941-1.631-9.181-4.606-9.181-12.239V66.998c1.836-4.289 5.537-9.37 12.853-9.37 9.086 0 13.692 6.296 13.692 18.697v77.828h40.797v-1.746l-.215-.053c-6.94-1.631-9.18-4.606-9.18-12.239V75.066a42 42 0 0 0-.578-7.26c1.947-4.661 5.86-10.177 13.475-10.177 9.214 0 13.691 6.114 13.691 18.696v77.828z"></path></svg></a><div class="ax h"><div class="ab ay az ba bb q bc bd"><div class="bm" aria-hidden="false" aria-describedby="searchResults" aria-labelledby="searchResults"></div><div class="bn bo ab"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M4.092 11.06a6.95 6.95 0 1 1 13.9 0 6.95 6.95 0 0 1-13.9 0m6.95-8.05a8.05 8.05 0 1 0 5.13 14.26l3.75 3.75a.56.56 0 1 0 .79-.79l-3.73-3.73A8.05 8.05 0 0 0 11.042 3z" clip-rule="evenodd"></path></svg></div><input role="combobox" aria-controls="searchResults" aria-expanded="false" aria-label="search" data-testid="headerSearchInput" tabindex="0" class="ay be bf bg z bh bi bj bk bl" placeholder="Search" value=""/></div></div></div><div class="h k w fg fh"><div class="fi ab"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerWriteButton" rel="noopener follow" href="/m/signin?operation=register&redirect=https%3A%2F%2Fmedium.com%2Fnew-story&source=---top_nav_layout_nav-----------------------new_post_topnav-----------"><div class="bf b bg z du fj fk ab q fl fm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" aria-label="Write"><path fill="currentColor" d="M14 4a.5.5 0 0 0 0-1zm7 6a.5.5 0 0 0-1 0zm-7-7H4v1h10zM3 4v16h1V4zm1 17h16v-1H4zm17-1V10h-1v10zm-1 1a1 1 0 0 0 1-1h-1zM3 20a1 1 0 0 0 1 1v-1zM4 3a1 1 0 0 0-1 1h1z"></path><path stroke="currentColor" d="m17.5 4.5-8.458 8.458a.25.25 0 0 0-.06.098l-.824 2.47a.25.25 0 0 0 .316.316l2.47-.823a.25.25 0 0 0 .098-.06L19.5 6.5m-2-2 2.323-2.323a.25.25 0 0 1 .354 0l1.646 1.646a.25.25 0 0 1 0 .354L19.5 6.5m-2-2 2 2"></path></svg><div class="dt l">Write</div></div></a></span></div></div><div class="k j i d"><div class="fi ab"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerSearchButton" rel="noopener follow" href="/search?source=---top_nav_layout_nav----------------------------------"><div class="bf b bg z du fj fk ab q fl fm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24" aria-label="Search"><path fill="currentColor" fill-rule="evenodd" d="M4.092 11.06a6.95 6.95 0 1 1 13.9 0 6.95 6.95 0 0 1-13.9 0m6.95-8.05a8.05 8.05 0 1 0 5.13 14.26l3.75 3.75a.56.56 0 1 0 .79-.79l-3.73-3.73A8.05 8.05 0 0 0 11.042 3z" clip-rule="evenodd"></path></svg></div></a></div></div><div class="fi h k j"><div class="ab q"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><button class="bf b dx dy eh dz ea ei eb ec ej ek ee el em eg eo ep eq er es et eu ev ew ex ey ez fa fb fc fd bm fe ff" data-testid="headerSignUpButton">Sign up</button></span></p><div class="ax l"><p class="bf b dx dy dz ea eb ec ed ee ef eg du"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerSignInButton" rel="noopener follow" href="/m/signin?operation=login&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&source=post_page---top_nav_layout_nav-----------------------global_nav-----------">Sign in</a></span></p></div></div></div><div class="l" aria-hidden="false"><button class="ay fn am ab q ao fo fp fq" aria-label="user options menu" data-testid="headerUserIcon"><div class="l fj"><img alt="" class="l fd by bz ca cx" src="https://miro.medium.com/v2/resize:fill:64:64/1*dmbNkD5D-u45r44go_cf0g.png" width="32" height="32" loading="lazy" role="presentation"/><div class="fr by l bz ca fs n ay ft"></div></div></button></div></div></div><div class="l"><div class="fu fv fw fx fy l"><div class="ab cb"><div class="ci bh fz ga gb gc"></div></div><article><div class="l"><div class="l"><span class="l"></span><section><div><div class="fs gi gj gk gl gm"></div><div class="gn go gp gq gr"><div class="ab cb"><div class="ci bh fz ga gb gc"><div><h1 id="14e6" class="pw-post-title gs gt gu bf gv gw gx gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq bk" data-testid="storyTitle"><strong class="al">Airbnb’s Trip to Linaria</strong></h1></div><div><h2 id="0d0b" class="pw-subtitle-paragraph hr gt gu bf b hs ht hu hv hw hx hy hz ia ib ic id ie if ig cq du">Learn how Linaria, Airbnb’s newest choice for web styling, improved both developer experience and web performance</h2><div><div class="speechify-ignore ab cp"><div class="speechify-ignore bh l"><div class="ih ii ij ik il ab"><div><div class="ab im"><div><div class="bm" aria-hidden="false"><a rel="noopener follow" href="/@lencioni?source=post_page---byline--dc169230bd12--------------------------------"><div class="l in io by ip iq"><div class="l fj"><img alt="Joe Lencioni" class="l fd by dd de cx" src="https://miro.medium.com/v2/resize:fill:88:88/1*r4bT1s_VG5WFqtCX5M-2lA.jpeg" width="44" height="44" loading="lazy" data-testid="authorPhoto"/><div class="ir by l dd de fs n is ft"></div></div></div></a></div></div><div class="it ab fj"><div><div class="bm" aria-hidden="false"><a href="https://medium.com/airbnb-engineering?source=post_page---byline--dc169230bd12--------------------------------" rel="noopener follow"><div class="l iu iv by ip iw"><div class="l fj"><img alt="The Airbnb Tech Blog" class="l fd by br ix cx" src="https://miro.medium.com/v2/resize:fill:48:48/1*MlNQKg-sieBGW5prWoe9HQ.jpeg" width="24" height="24" loading="lazy" data-testid="publicationPhoto"/><div class="ir by l br ix fs n is ft"></div></div></div></a></div></div></div></div></div><div class="bn bh l"><div class="ab"><div style="flex:1"><span class="bf b bg z bk"><div class="iy ab q"><div class="ab q iz"><div class="ab q"><div><div class="bm" aria-hidden="false"><p class="bf b ja jb bk"><a class="af ag ah ai aj ak al am an ao ap aq ar jc" data-testid="authorName" rel="noopener follow" href="/@lencioni?source=post_page---byline--dc169230bd12--------------------------------">Joe Lencioni</a></p></div></div></div><span class="jd je" aria-hidden="true"><span class="bf b bg z du">·</span></span><p class="bf b ja jb du"><span><a class="jf jg ah ai aj ak al am an ao ap aq ar ex jh ji" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fsubscribe%2Fuser%2Fe52389684329&operation=register&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&user=Joe+Lencioni&userId=e52389684329&source=post_page-e52389684329--byline--dc169230bd12---------------------post_header-----------">Follow</a></span></p></div></div></span></div></div><div class="l jj"><span class="bf b bg z du"><div class="ab cn jk jl jm"><div class="jn jo ab"><div class="bf b bg z du ab jp"><span class="jq l jj">Published in</span><div><div class="l" aria-hidden="false"><a class="af ag ah ai aj ak al am an ao ap aq ar jc ab q" data-testid="publicationName" href="https://medium.com/airbnb-engineering?source=post_page---byline--dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b bg z jr js jt ju jv jw jx jy bk">The Airbnb Tech Blog</p></a></div></div></div><div class="h k"><span class="jd je" aria-hidden="true"><span class="bf b bg z du">·</span></span></div></div><span class="bf b bg z du"><div class="ab ae"><span data-testid="storyReadTime">11 min read</span><div class="jz ka l" aria-hidden="true"><span class="l" aria-hidden="true"><span class="bf b bg z du">·</span></span></div><span data-testid="storyPublishDate">Jun 16, 2022</span></div></span></div></span></div></div></div><div class="ab cp kb kc kd ke kf kg kh ki kj kk kl km kn ko kp kq"><div class="h k w fg fh q"><div class="lg l"><div class="ab q lh li"><div class="pw-multi-vote-icon fj jq lj lk ll"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerClapButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fvote%2Fairbnb-engineering%2Fdc169230bd12&operation=register&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&user=Joe+Lencioni&userId=e52389684329&source=---header_actions--dc169230bd12---------------------clap_footer-----------"><div><div class="bm" aria-hidden="false"><div class="lm ao ln lo lp lq am lr ls lt ll"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-label="clap"><path fill-rule="evenodd" d="M11.37.828 12 3.282l.63-2.454zM13.916 3.953l1.523-2.112-1.184-.39zM8.589 1.84l1.522 2.112-.337-2.501zM18.523 18.92c-.86.86-1.75 1.246-2.62 1.33a6 6 0 0 0 .407-.372c2.388-2.389 2.86-4.951 1.399-7.623l-.912-1.603-.79-1.672c-.26-.56-.194-.98.203-1.288a.7.7 0 0 1 .546-.132c.283.046.546.231.728.5l2.363 4.157c.976 1.624 1.141 4.237-1.324 6.702m-10.999-.438L3.37 14.328a.828.828 0 0 1 .585-1.408.83.83 0 0 1 .585.242l2.158 2.157a.365.365 0 0 0 .516-.516l-2.157-2.158-1.449-1.449a.826.826 0 0 1 1.167-1.17l3.438 3.44a.363.363 0 0 0 .516 0 .364.364 0 0 0 0-.516L5.293 9.513l-.97-.97a.826.826 0 0 1 0-1.166.84.84 0 0 1 1.167 0l.97.968 3.437 3.436a.36.36 0 0 0 .517 0 .366.366 0 0 0 0-.516L6.977 7.83a.82.82 0 0 1-.241-.584.82.82 0 0 1 .824-.826c.219 0 .43.087.584.242l5.787 5.787a.366.366 0 0 0 .587-.415l-1.117-2.363c-.26-.56-.194-.98.204-1.289a.7.7 0 0 1 .546-.132c.283.046.545.232.727.501l2.193 3.86c1.302 2.38.883 4.59-1.277 6.75-1.156 1.156-2.602 1.627-4.19 1.367-1.418-.236-2.866-1.033-4.079-2.246M10.75 5.971l2.12 2.12c-.41.502-.465 1.17-.128 1.89l.22.465-3.523-3.523a.8.8 0 0 1-.097-.368c0-.22.086-.428.241-.584a.847.847 0 0 1 1.167 0m7.355 1.705c-.31-.461-.746-.758-1.23-.837a1.44 1.44 0 0 0-1.11.275c-.312.24-.505.543-.59.881a1.74 1.74 0 0 0-.906-.465 1.47 1.47 0 0 0-.82.106l-2.182-2.182a1.56 1.56 0 0 0-2.2 0 1.54 1.54 0 0 0-.396.701 1.56 1.56 0 0 0-2.21-.01 1.55 1.55 0 0 0-.416.753c-.624-.624-1.649-.624-2.237-.037a1.557 1.557 0 0 0 0 2.2c-.239.1-.501.238-.715.453a1.56 1.56 0 0 0 0 2.2l.516.515a1.556 1.556 0 0 0-.753 2.615L7.01 19c1.32 1.319 2.909 2.189 4.475 2.449q.482.08.971.08c.85 0 1.653-.198 2.393-.579.231.033.46.054.686.054 1.266 0 2.457-.52 3.505-1.567 2.763-2.763 2.552-5.734 1.439-7.586z" clip-rule="evenodd"></path></svg></div></div></div></a></span></div><div class="pw-multi-vote-count l lu lv lw lx ly lz ma"><p class="bf b dv z du"><span class="mb">--</span></p></div></div></div><div><div class="bm" aria-hidden="false"><button class="ao lm me mf ab q fk mg mh" aria-label="responses"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="md"><path d="M18.006 16.803c1.533-1.456 2.234-3.325 2.234-5.321C20.24 7.357 16.709 4 12.191 4S4 7.357 4 11.482c0 4.126 3.674 7.482 8.191 7.482.817 0 1.622-.111 2.393-.327.231.2.48.391.744.559 1.06.693 2.203 1.044 3.399 1.044.224-.008.4-.112.486-.287a.49.49 0 0 0-.042-.518c-.495-.67-.845-1.364-1.04-2.057a4 4 0 0 1-.125-.598zm-3.122 1.055-.067-.223-.315.096a8 8 0 0 1-2.311.338c-4.023 0-7.292-2.955-7.292-6.587 0-3.633 3.269-6.588 7.292-6.588 4.014 0 7.112 2.958 7.112 6.593 0 1.794-.608 3.469-2.027 4.72l-.195.168v.255c0 .056 0 .151.016.295.025.231.081.478.154.733.154.558.398 1.117.722 1.659a5.3 5.3 0 0 1-2.165-.845c-.276-.176-.714-.383-.941-.59z"></path></svg><p class="bf b dv z du"><span class="pw-responses-count mc md">6</span></p></button></div></div></div><div class="ab q kr ks kt ku kv kw kx ky kz la lb lc ld le lf"><div class="mi k j i d"></div><div class="h k"><div><div class="bm" aria-hidden="false"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="headerBookmarkButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fbookmark%2Fp%2Fdc169230bd12&operation=register&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&source=---header_actions--dc169230bd12---------------------bookmark_footer-----------"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="none" viewBox="0 0 25 25" class="du mj" aria-label="Add to list bookmark button"><path fill="currentColor" d="M18 2.5a.5.5 0 0 1 1 0V5h2.5a.5.5 0 0 1 0 1H19v2.5a.5.5 0 1 1-1 0V6h-2.5a.5.5 0 0 1 0-1H18zM7 7a1 1 0 0 1 1-1h3.5a.5.5 0 0 0 0-1H8a2 2 0 0 0-2 2v14a.5.5 0 0 0 .805.396L12.5 17l5.695 4.396A.5.5 0 0 0 19 21v-8.5a.5.5 0 0 0-1 0v7.485l-5.195-4.012a.5.5 0 0 0-.61 0L7 19.985z"></path></svg></a></span></div></div></div><div class="fd mk cn"><div class="l ae"><div class="ab cb"><div class="ml mm mn mo mp mq ci bh"><div class="ab"><div class="bm bh" aria-hidden="false"><div><div class="bm" aria-hidden="false"><button aria-label="Listen" data-testid="audioPlayButton" class="af fk ah ai aj ak al mr an ao ap ex ms mt mh mu mv mw mx my s mz na nb nc nd ne nf u ng nh ni"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M3 12a9 9 0 1 1 18 0 9 9 0 0 1-18 0m9-10C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2m3.376 10.416-4.599 3.066a.5.5 0 0 1-.777-.416V8.934a.5.5 0 0 1 .777-.416l4.599 3.066a.5.5 0 0 1 0 .832" clip-rule="evenodd"></path></svg><div class="j i d"><p class="bf b bg z du">Listen</p></div></button></div></div></div></div></div></div></div></div><div class="bm" aria-hidden="false" aria-describedby="postFooterSocialMenu" aria-labelledby="postFooterSocialMenu"><div><div class="bm" aria-hidden="false"><button aria-controls="postFooterSocialMenu" aria-expanded="false" aria-label="Share Post" data-testid="headerSocialShareButton" class="af fk ah ai aj ak al mr an ao ap ex ms mt mh mu mv mw mx my s mz na nb nc nd ne nf u ng nh ni"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M15.218 4.931a.4.4 0 0 1-.118.132l.012.006a.45.45 0 0 1-.292.074.5.5 0 0 1-.3-.13l-2.02-2.02v7.07c0 .28-.23.5-.5.5s-.5-.22-.5-.5v-7.04l-2 2a.45.45 0 0 1-.57.04h-.02a.4.4 0 0 1-.16-.3.4.4 0 0 1 .1-.32l2.8-2.8a.5.5 0 0 1 .7 0l2.8 2.79a.42.42 0 0 1 .068.498m-.106.138.008.004v-.01zM16 7.063h1.5a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-11c-1.1 0-2-.9-2-2v-10a2 2 0 0 1 2-2H8a.5.5 0 0 1 .35.15.5.5 0 0 1 .15.35.5.5 0 0 1-.15.35.5.5 0 0 1-.35.15H6.4c-.5 0-.9.4-.9.9v10.2a.9.9 0 0 0 .9.9h11.2c.5 0 .9-.4.9-.9v-10.2c0-.5-.4-.9-.9-.9H16a.5.5 0 0 1 0-1" clip-rule="evenodd"></path></svg><div class="j i d"><p class="bf b bg z du">Share</p></div></button></div></div></div></div></div></div></div></div></div><figure class="nm nn no np nq nr nj nk paragraph-image"><div role="button" tabindex="0" class="ns nt fj nu bh nv"><div class="nj nk nl"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/1*-qT4pQIPIsxHBZj22sQtag.jpeg 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/1*-qT4pQIPIsxHBZj22sQtag.jpeg 640w, https://miro.medium.com/v2/resize:fit:720/1*-qT4pQIPIsxHBZj22sQtag.jpeg 720w, https://miro.medium.com/v2/resize:fit:750/1*-qT4pQIPIsxHBZj22sQtag.jpeg 750w, https://miro.medium.com/v2/resize:fit:786/1*-qT4pQIPIsxHBZj22sQtag.jpeg 786w, https://miro.medium.com/v2/resize:fit:828/1*-qT4pQIPIsxHBZj22sQtag.jpeg 828w, https://miro.medium.com/v2/resize:fit:1100/1*-qT4pQIPIsxHBZj22sQtag.jpeg 1100w, https://miro.medium.com/v2/resize:fit:1400/1*-qT4pQIPIsxHBZj22sQtag.jpeg 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh mq nw c" width="700" height="468" loading="eager" role="presentation"/></picture></div></div></figure><p id="655f" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">CSS is a critical component of every web application, and many solutions have evolved for how styles are written by developers and delivered to visitors. In this post we’ll take you through Airbnb’s journey from Sass to CSS-in-JS and show you why we landed on <a class="af ot" href="https://github.com/callstack/linaria" rel="noopener ugc nofollow" target="_blank">Linaria, a zero-runtime CSS-in-JS library</a>, and the impact it has had on the developer experience and performance of Airbnb’s web app.</p><h1 id="77ce" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">From Sass to CSS-in-JS</h1><p id="e1c6" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">In 2016, our web frontend was in a monolithic <a class="af ot" href="https://rubyonrails.org/" rel="noopener ugc nofollow" target="_blank">Ruby on Rails</a> app using a combination of <a class="af ot" href="https://github.com/rails/sprockets" rel="noopener ugc nofollow" target="_blank">Sprockets</a>, <a class="af ot" href="https://browserify.org/" rel="noopener ugc nofollow" target="_blank">Browserify</a>, and <a class="af ot" href="https://sass-lang.com/" rel="noopener ugc nofollow" target="_blank">Sass</a>. We had a <a class="af ot" href="https://getbootstrap.com/" rel="noopener ugc nofollow" target="_blank">Bootstrap</a>-inspired internal toolkit for styling, but we weren’t using anything like <a class="af ot" href="https://github.com/css-modules/css-modules" rel="noopener ugc nofollow" target="_blank">CSS Modules</a> or <a class="af ot" href="http://getbem.com/" rel="noopener ugc nofollow" target="_blank">BEM</a>.</p><p id="aafb" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Production bugs were often caused by our styling — sometimes the correct stylesheet was missing from some pages and other times styles from different stylesheets conflicted unexpectedly.</p><figure class="nm nn no np nq nr"><div class="pv jr l fj"><div class="pw px l"></div></div></figure><p id="d300" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Additionally, developers <a class="af ot" href="https://css-tricks.com/how-do-you-remove-unused-css-from-a-site/" rel="noopener ugc nofollow" target="_blank">rarely removed styles once added since it was hard to know whether they were still needed</a>. These issues compounded as our product surface area rapidly expanded.</p><p id="bbcf" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">As we began to build our <a class="af ot" href="https://www.youtube.com/watch?v=fHQ1WSx41CA" rel="noopener ugc nofollow" target="_blank">Design System</a> in React, we landed on CSS-in-JS as an exciting new option. At the time, CSS-in-JS was still in its infancy–only a few libraries existed and <a class="af ot" href="https://styled-components.com/" rel="noopener ugc nofollow" target="_blank">Styled Components</a> had not been invented yet. We chose <a class="af ot" href="https://github.com/khan/aphrodite" rel="noopener ugc nofollow" target="_blank">Aphrodite</a>, but didn’t want to be directly coupled to Aphrodite’s implementation for two reasons: since CSS-in-JS was a nascent space we wanted to have the flexibility to switch implementations at a later date, and we also wanted something that would work for open source projects where people might not want Aphrodite. So we created an abstraction layer called <a class="af ot" href="https://github.com/airbnb/react-with-styles" rel="noopener ugc nofollow" target="_blank">react-with-styles</a>, which gave us a <a class="af ot" href="https://reactjs.org/docs/higher-order-components.html" rel="noopener ugc nofollow" target="_blank">higher-order component (HOC)</a> to define themeable styles.</p><figure class="nm nn no np nq nr"><div class="pv jr l fj"><div class="py px l"></div></div></figure><p id="329e" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">This allowed components to be styled in the same file, making repo organization more convenient. More importantly, <strong class="nz gv">moving from a globally-aware styling system to a component-based styling system gave us guarantees around how styles would be applied and what files were needed to render every component correctly on every page</strong>. This enabled us to rely on <a class="af ot" href="https://happo.io/" rel="noopener ugc nofollow" target="_blank">Happo, our screenshot testing tool of choice</a>, and as a result visual regressions plummeted (disclosure: I am the co-creator of Happo).</p><p id="2c14" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Though react-with-styles has served us well for years, it comes with <strong class="nz gv">performance</strong> and <strong class="nz gv">developer experience</strong> tradeoffs. The styles and runtime libraries increase critical path JS bundle size, and applying styles at render-time comes with a CPU cost (10–20% of our component mount times). While we get the aforementioned guarantees about styles, actually writing styles in JavaScript objects feels awkward compared to regular CSS syntax. These tradeoffs led us to reconsider how we style the web at Airbnb.</p><h1 id="30b1" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Considering Our Options</h1><p id="7b23" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">To address the problems with react-with-styles, we formed a working group of engineers from various teams. We considered a number of directions, which fit into the following high-level categories:</p><ul class=""><li id="adfa" class="nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os pz qa qb bk">Static extraction of CSS from react-with-styles at build time</li><li id="761f" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Write our own framework</li><li id="f326" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Investigate and adopt an existing framework</li></ul><p id="decd" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">We decided against <strong class="nz gv">static extraction</strong> from react-with-styles at build time because it would require a lot of effort. Additionally, it would be home-grown and therefore lack benefits of a community. Finally, it does not address developer ergonomics issues.</p><p id="3a5c" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Similarly, <strong class="nz gv">writing our own framework</strong> would have had a high cost of initial implementation, maintenance, and support. Additionally, there were existing solutions for this problem that we wanted to leverage and contribute back to.</p><figure class="nm nn no np nq nr nj nk paragraph-image"><div class="nj nk qh"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*7Kwk-MuLZOIUhgnv 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*7Kwk-MuLZOIUhgnv 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*7Kwk-MuLZOIUhgnv 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*7Kwk-MuLZOIUhgnv 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*7Kwk-MuLZOIUhgnv 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*7Kwk-MuLZOIUhgnv 1100w, https://miro.medium.com/v2/resize:fit:1000/format:webp/0*7Kwk-MuLZOIUhgnv 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*7Kwk-MuLZOIUhgnv 640w, https://miro.medium.com/v2/resize:fit:720/0*7Kwk-MuLZOIUhgnv 720w, https://miro.medium.com/v2/resize:fit:750/0*7Kwk-MuLZOIUhgnv 750w, https://miro.medium.com/v2/resize:fit:786/0*7Kwk-MuLZOIUhgnv 786w, https://miro.medium.com/v2/resize:fit:828/0*7Kwk-MuLZOIUhgnv 828w, https://miro.medium.com/v2/resize:fit:1100/0*7Kwk-MuLZOIUhgnv 1100w, https://miro.medium.com/v2/resize:fit:1000/0*7Kwk-MuLZOIUhgnv 1000w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 500px"/><img alt="An xkcd comic titled “How Standards Proliferate: (see: A/C chargers, character encodings, instant messaging, etc). Panel 1: Situation: There are 14 competing standards. Panel 2: “14?! Ridiculous! We need to develop one universal standard that covers everyone’s use cases.” “Yeah!” Panel 3: Soon: Situation: There are 15 competing standards." class="bh mq nw c" width="500" height="283" loading="lazy"/></picture></div><figcaption class="qi ff qj nj nk qk ql bf b bg z du">Comic from <a class="af ot" href="https://xkcd.com/927/" rel="noopener ugc nofollow" target="_blank">https://xkcd.com/927/</a> by Randall Munroe and is used under a CC-BY-NC 2.5 license.</figcaption></figure><p id="6666" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">After evaluating several <strong class="nz gv">existing frameworks</strong> against our requirements, we narrowed down candidates for building a proof of concept:</p><ul class=""><li id="0a23" class="nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os pz qa qb bk"><a class="af ot" href="https://emotion.sh/docs/introduction" rel="noopener ugc nofollow" target="_blank">Emotion</a>: CSS-in-JS, with a low runtime cost</li><li id="6872" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk"><a class="af ot" href="https://github.com/callstack/linaria" rel="noopener ugc nofollow" target="_blank">Linaria</a>: zero-runtime CSS-in-JS (static CSS extraction)</li><li id="bb46" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk"><a class="af ot" href="https://github.com/seek-oss/treat" rel="noopener ugc nofollow" target="_blank">Treat</a>: near zero-runtime CSS-in-JS (static CSS extraction)</li></ul><p id="da82" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">The proof-of-concepting work was done in a new repo that implemented a server-rendered client-hydrated unstyled version of Airbnb’s logged in homepage. For each framework, this allowed us to:</p><ul class=""><li id="9ee9" class="nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os pz qa qb bk">Understand what changes might need to be made to our build system</li><li id="f5b7" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Try out framework APIs and get a feel for developer ergonomics</li><li id="d4fe" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Assess how each framework supports our web styling requirements</li><li id="092a" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Gather performance metrics</li><li id="5935" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Serve as a starting point for a migration plan</li></ul><p id="f6cd" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Frameworks were evaluated against each other based on the following ranked list of criteria:</p><ol class=""><li id="7204" class="nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os qm qa qb bk"><strong class="nz gv">Performance</strong></li><li id="602e" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os qm qa qb bk"><strong class="nz gv">Community</strong> (i.e. support and adoption)</li><li id="15c7" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os qm qa qb bk"><strong class="nz gv">Developer experience</strong></li></ol><h1 id="8b61" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Performance Analysis</h1><p id="4e2e" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">Using <a class="af ot" href="https://www.speedcurve.com/" rel="noopener ugc nofollow" target="_blank">SpeedCurve</a>, local benchmarking, and the <a class="af ot" href="https://reactjs.org/docs/profiler.html" rel="noopener ugc nofollow" target="_blank">React <Profiler /></a>, we ran performance benchmarking tests for each framework. All results were calculated as the median of 200 runs on a throttled MacBook Pro, and are statistically significantly different from control with a p-value of <= 0.05.</p><p id="d82e" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Informed by <a class="af ot" rel="noopener" href="/airbnb-engineering/creating-airbnbs-page-performance-score-5f664be0936">Airbnb’s Page Performance Score</a> (similar to <a class="af ot" href="https://web.dev/performance-scoring/" rel="noopener ugc nofollow" target="_blank">Lighthouse’s performance score</a>), we focused on the following metrics to give us an idea of how each framework performed and would impact the user experience:</p><ul class=""><li id="5d16" class="nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os pz qa qb bk"><a class="af ot" href="https://web.dev/tbt/" rel="noopener ugc nofollow" target="_blank">Total blocking time (TBT)</a></li><li id="2cbf" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Bundle size</li><li id="1d63" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Update layout tree count and duration</li><li id="d74b" class="nx ny gu nz b hs qc ob oc hv qd oe of og qe oi oj ok qf om on oo qg oq or os pz qa qb bk">Composite layers count and duration</li></ul><figure class="nm nn no np nq nr"><div class="pv jr l fj"><div class="py px l"></div></div></figure><p id="cf54" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">It is clear that the frameworks are divided into two groups: <strong class="nz gv">runtime frameworks</strong> (react-with-styles, Emotion) and <strong class="nz gv">build-time frameworks</strong> (Linaria, Treat).</p><p id="074d" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Benchmarks of the server-rendered and client-hydrated version of our homepage showed Treat and Linaria performing 36% and 22% better than Emotion on <strong class="nz gv">Total Blocking Time</strong>, respectively. All frameworks performed significantly better than react-with-styles, ranging from a 32–56% improvement. <em class="qn">(Note that these numbers should not be used to estimate expected improvements in production, as this is a very specific benchmark designed to test differences between frameworks, not expected savings in production.)</em></p><p id="62ed" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk"><strong class="nz gv">Bundle size</strong> differences also fall into these two categories — with savings on the order of 80 KiB (~12%) for the Linaria/Treat group.</p><p id="15ba" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">The CSS metrics (<strong class="nz gv">update layout tree</strong> and <strong class="nz gv">composite layers</strong>) show that, on average, there is roughly one more layout tree update and layer composition event for react-with-styles/Emotion. This is likely due to the insertion and hydration of stylesheets with JavaScript that is not necessary with a CSS extraction library like Linaria or Treat.</p><p id="eafb" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">This performance investigation shows that either Linaria or Treat would be promising options to adopt, and that all frameworks considered are a statistically significant improvement over react-with-styles with Aphrodite.</p><h1 id="41a8" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">What We Liked About Linaria</h1><p id="0c96" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">The above <strong class="nz gv">performance</strong> improvements were largely thanks to Linaria extracting the styles from JS to static CSS files at build time, so there is no JS bundle or runtime CPU overhead — giving it a slight edge over the near-zero runtime Treat. Also, this brings caching benefits since these static CSS files may change at a different cadence than the JS files. Since the styles are extracted at build time, Linaria has the opportunity to automatically remove unused styles — this also opens the door to the possibility of deduplicating styles (i.e. <a class="af ot" href="https://css-tricks.com/lets-define-exactly-atomic-css/" rel="noopener ugc nofollow" target="_blank">Atomic CSS</a>). Additionally, Linaria supports injecting the critical CSS for server-side rendering, which we had wanted to preserve from our react-with-styles integration.</p><p id="8fc0" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk"><a class="af ot" href="https://snyk.io/advisor/npm-package/linaria" rel="noopener ugc nofollow" target="_blank">Linaria also seemed to be a healthy project</a> that saw a good amount of activity, <strong class="nz gv">community</strong> involvement, documentation, and adoption. Its good trajectory gave us confidence that it would continue to improve and that we would be able to contribute back.</p><p id="f5f4" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">We found Linaria’s <a class="af ot" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates" rel="noopener ugc nofollow" target="_blank">tagged template literal</a> API that enables developers to use CSS syntax to be an attractive improvement over the JS object HOC API that we built for react-with-styles. Additionally, off-the-shelf integrations were available for stylelint, CSS autocompletion, and syntax highlighting, which enriched the <strong class="nz gv">developer experience</strong>.</p><figure class="nm nn no np nq nr nj nk paragraph-image"><div role="button" tabindex="0" class="ns nt fj nu bh nv"><div class="nj nk qo"><picture><source srcSet="https://miro.medium.com/v2/resize:fit:640/format:webp/0*hyXFKX-bB-ixvHsE 640w, https://miro.medium.com/v2/resize:fit:720/format:webp/0*hyXFKX-bB-ixvHsE 720w, https://miro.medium.com/v2/resize:fit:750/format:webp/0*hyXFKX-bB-ixvHsE 750w, https://miro.medium.com/v2/resize:fit:786/format:webp/0*hyXFKX-bB-ixvHsE 786w, https://miro.medium.com/v2/resize:fit:828/format:webp/0*hyXFKX-bB-ixvHsE 828w, https://miro.medium.com/v2/resize:fit:1100/format:webp/0*hyXFKX-bB-ixvHsE 1100w, https://miro.medium.com/v2/resize:fit:1400/format:webp/0*hyXFKX-bB-ixvHsE 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px" type="image/webp"/><source data-testid="og" srcSet="https://miro.medium.com/v2/resize:fit:640/0*hyXFKX-bB-ixvHsE 640w, https://miro.medium.com/v2/resize:fit:720/0*hyXFKX-bB-ixvHsE 720w, https://miro.medium.com/v2/resize:fit:750/0*hyXFKX-bB-ixvHsE 750w, https://miro.medium.com/v2/resize:fit:786/0*hyXFKX-bB-ixvHsE 786w, https://miro.medium.com/v2/resize:fit:828/0*hyXFKX-bB-ixvHsE 828w, https://miro.medium.com/v2/resize:fit:1100/0*hyXFKX-bB-ixvHsE 1100w, https://miro.medium.com/v2/resize:fit:1400/0*hyXFKX-bB-ixvHsE 1400w" sizes="(min-resolution: 4dppx) and (max-width: 700px) 50vw, (-webkit-min-device-pixel-ratio: 4) and (max-width: 700px) 50vw, (min-resolution: 3dppx) and (max-width: 700px) 67vw, (-webkit-min-device-pixel-ratio: 3) and (max-width: 700px) 65vw, (min-resolution: 2.5dppx) and (max-width: 700px) 80vw, (-webkit-min-device-pixel-ratio: 2.5) and (max-width: 700px) 80vw, (min-resolution: 2dppx) and (max-width: 700px) 100vw, (-webkit-min-device-pixel-ratio: 2) and (max-width: 700px) 100vw, 700px"/><img alt="" class="bh mq nw c" width="700" height="287" loading="lazy" role="presentation"/></picture></div></div><figcaption class="qi ff qj nj nk qk ql bf b bg z du">Off-the-shelf integrations for stylelint, CSS autocompletion, and syntax highlighting working with Linaria in action.</figcaption></figure><p id="0c17" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">We also found value in the similarities between Linaria and our existing solution. The co-location of styles within the component file was a big feature that tipped the scales in favor of Linaria over Treat for us, and the familiar API smoothed the transition for developers and gave us confidence that migration efforts could be eased with automation.</p><h1 id="e110" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Migration Strategy</h1><p id="32b2" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">To roll out this big change, we adopted an incremental migration strategy that is largely automated by <a class="af ot" rel="noopener" href="/airbnb-engineering/turbocharged-javascript-refactoring-with-codemods-b0cae8b326b9">codemods</a> we’ve written. We are leaning heavily on our <a class="af ot" href="https://happo.io/" rel="noopener ugc nofollow" target="_blank">Happo screenshot tests</a> to ensure that our components look the same after they are migrated. This allows sections of our codebase to be migrated by running a script and following up with any necessary tweaks, similar to <a class="af ot" rel="noopener" href="/airbnb-engineering/ts-migrate-a-tool-for-migrating-to-typescript-at-scale-cd23bfeb5cc">the approach we took when adopting TypeScript</a>.</p><p id="bb4f" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">The first phase of the migration was handled by the web styling working group and targeted converting a subset of components on a few select pages with varying performance characteristics. This phase was gated on A/B tests which ensured that our initial understanding of the performance held up under the specifics of our app and assured us that there were no hidden problems.</p><p id="d71f" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Once we were confident about the performance and correctness of our Linaria integration, we allowed teams to start using Linaria in new code. We also encouraged teams to migrate their existing code using our codemods. Although the migration has proceeded at a good pace organically, we plan to ensure that all code has moved off of react-with-styles so that we can eventually remove the runtime dependencies from the bundles entirely. This consistency will give us an additional performance boost and reduce the cost of <a class="af ot" href="https://en.wikipedia.org/wiki/Decision_fatigue" rel="noopener ugc nofollow" target="_blank">decision fatigue</a>.</p><h1 id="dd3b" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Contributing Back</h1><p id="21d1" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">Once we started using Linaria, we discovered that automatic style deduplication (i.e. Atomic CSS) would give us not just a performance boost, but also would fix some non-performance-related hiccups we ran into.</p><p id="ad78" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">The selectors that Linaria generates are all of the same <a class="af ot" href="https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity" rel="noopener ugc nofollow" target="_blank">specificity</a>. Since CSS selectors of the same specificity depend on their declaration order, the order that the bundler builds these files becomes important. This is problematic when sharing styles between files, since we cannot predict or maintain the order of the styles as the shape of the dependency graph changes.</p><p id="f5c8" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">We initially approached this problem by creating a new <a class="af ot" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates" rel="noopener ugc nofollow" target="_blank">tagged template literal</a> for CSS fragments which allows for the styles to be interpolated into Linaria’s CSS tagged template literals. This works okay, but it is unintuitive, defeats <a class="af ot" href="https://github.com/prettier/prettier/blob/d13feed42b6478710bebbcd3225ab6f203a914c1/src/language-js/embed.js#L90-L121" rel="noopener ugc nofollow" target="_blank">tooling that expects styles to be defined in CSS tagged template literals</a>, and leads to the styles being included several times in the CSS bundles (which is suboptimal for performance).</p><p id="8f7f" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Josh Nelson, a member of our web styling working group, <a class="af ot" href="https://github.com/callstack/linaria/pull/867" rel="noopener ugc nofollow" target="_blank">contributed Atomic CSS support back to Linaria</a> and the Linaria community has been very supportive. The change adds a new <a class="af ot" href="https://npmjs.com/@linaria/atomic" rel="noopener ugc nofollow" target="_blank">@linaria/atomic</a> package that when imported instead of <a class="af ot" href="https://www.npmjs.com/package/@linaria/core" rel="noopener ugc nofollow" target="_blank">@linaria/core</a> will generate Atomic CSS at build time. This means that if you write your code like this:</p><figure class="nm nn no np nq nr"><div class="pv jr l fj"><div class="py px l"></div></div></figure><p id="eae7" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Instead of generating output like this (without Atomic CSS):</p><figure class="nm nn no np nq nr"><div class="pv jr l fj"><div class="py px l"></div></div></figure><p id="2c93" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">The generated output will look something like this (with Atomic CSS):</p><figure class="nm nn no np nq nr"><div class="pv jr l fj"><div class="py px l"></div></div></figure><p id="c27e" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">The order of appearance problem is solved by build time analysis that chains class names based on the order they are passed in to the cx function to increase specificity when necessary.</p><h1 id="e264" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Reception</h1><p id="b2a3" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">Our engineers have reacted positively to Linaria. Here are some quotes:</p><blockquote class="qp qq qr"><p id="1587" class="nx ny qn nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">“Linaria opens up a world where we can code like it’s 1999, in old school pure on CSS. It advises against bad patterns, but gives us the flexibility to build amazing experiences. We’re not fighting the platform anymore, we’re harnessing it and it feels incredibly powerful.” — Callie Riggins</p><p id="2dad" class="nx ny qn nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">“Compared to react-with-styles, I care more about what I’m creating now. Linaria is so good.” — Ian Demattei-Selby</p><p id="0900" class="nx ny qn nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">“I really liked being able to write CSS again. It gives you so much more control over what you can style in the component.” — Brie Bunge</p><p id="7a37" class="nx ny qn nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">“It’s great to be writing actual CSS again.” — Victor Lin</p></blockquote><p id="ad61" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Thanks to its familiar CSS syntax, style extraction into static stylesheets, and application of styles using class names, Linaria <strong class="nz gv">increases product development speed</strong> and <strong class="nz gv">unlocks new styling capabilities not possible with react-with-styles and Aphrodite</strong>.</p><h1 id="44a5" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Performance Impact</h1><p id="1067" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">Though we are still at the beginning of our migration, we have run some A/B tests that give us an encouraging look at the real world performance impact of switching to Linaria for a large group of visitors in the wild.</p><p id="456a" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">In one experiment, we converted about 10% of the components rendered on the airbnb.com homepage from react-with-styles to Linaria, and saw Homepage <a class="af ot" rel="noopener" href="/airbnb-engineering/creating-airbnbs-page-performance-score-5f664be0936">Page Performance Score</a> improve by 0.26%. <a class="af ot" href="https://web.dev/fcp/" rel="noopener ugc nofollow" target="_blank">Time to First Contentful Paint (TTFCP)</a> improved by 0.54% (mean of 790ms), while <a class="af ot" href="https://web.dev/tbt/" rel="noopener ugc nofollow" target="_blank">Total Blocking Time (TBT)</a> also had a strong improvement of 1.6% (mean of 1200ms). To put this in perspective, hydrating the homepage with React takes around 200ms for most people, so improvements of this order of magnitude are significant. We believe these performance improvements with Linaria are attributable to no longer generating CSS styles at render-time, which improves render times on both server and client.</p><p id="8fcf" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Assuming the performance improvements will scale linearly (which is a big assumption), converting the remaining 90% of the components <em class="qn">might</em> result in a 2.6% improvement to Page Performance Score, 5.4% improvement to Time to First Contentful Paint (TTFCP), and 16% improvement to Total Blocking Time (TBT).</p><p id="971a" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Note that direct comparisons with other industry numbers are a little tricky here, given the different ways we define pages especially with regard to client routing.</p><h1 id="8fd0" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">What Does This Mean for react-with-styles?</h1><p id="449c" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">Given that we still have many components that still depend on react-with-styles and that it will take a while for us to complete our migration, <strong class="nz gv">we will put react-with-styles in maintenance mode</strong> until we approach the end of our migration. At that point, <strong class="nz gv">we intend to sunset react-with-styles</strong> and the related packages.</p><p id="feba" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">By removing an option from the marketplace we hope to help the community coalesce towards a common solution and invest in better frameworks. If you are looking for a new tool, we think Linaria is a great choice!</p><h1 id="cea4" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Conclusion</h1><p id="98ef" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">Styling infrastructure is still an exciting space, rich with opportunities. At Airbnb, we’ve found big improvements to the <strong class="nz gv">developer experience</strong> by adopting a framework that allows regular CSS syntax to be used alongside our React component code. And by replacing a runtime styling library with one that compiles to static CSS files at build time, we are able to continue driving toward faster <strong class="nz gv">performance</strong>. Thanks to the Linaria <strong class="nz gv">community</strong> and our collaboration, we expect this library to continue to improve for many years.</p><p id="0d26" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk">Interested in working at Airbnb? Check out these open roles:</p><p id="4588" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk"><a class="af ot" href="https://grnh.se/ebfa55151us" rel="noopener ugc nofollow" target="_blank">Frontend Infrastructure Engineer, Web Platform</a><br/><a class="af ot" href="https://grnh.se/b5afa9151us" rel="noopener ugc nofollow" target="_blank">Staff Software Engineer, Data Governance </a><br/><a class="af ot" href="https://grnh.se/92c32fed1us" rel="noopener ugc nofollow" target="_blank">Staff Software Engineer, Cloud Infrastructure </a><br/><a class="af ot" href="https://grnh.se/bbe55fe81us" rel="noopener ugc nofollow" target="_blank">Staff Database Engineer </a><br/><a class="af ot" href="https://grnh.se/21e5c2011us" rel="noopener ugc nofollow" target="_blank">Staff Software Engineer — ML Ops Platform </a><br/><a class="af ot" href="https://grnh.se/ee114dfc1us" rel="noopener ugc nofollow" target="_blank">Senior/Staff Software Engineer, Service Capabilities</a></p><h1 id="3e5b" class="ou ov gu bf ow ox oy hu oz pa pb hx pc pd pe pf pg ph pi pj pk pl pm pn po pp bk">Acknowledgments</h1><p id="2e09" class="pw-post-body-paragraph nx ny gu nz b hs pq ob oc hv pr oe of og ps oi oj ok pt om on oo pu oq or os gn bk">We have a lot of appreciation for the folks at <a class="af ot" href="https://www.callstack.com/" rel="noopener ugc nofollow" target="_blank">callstack</a> and the <a class="af ot" href="https://github.com/callstack/linaria#contributors" rel="noopener ugc nofollow" target="_blank">Linaria community</a> for building such a great tool and for collaborating with us to make it even better. Also for <a class="af ot" href="https://www.khanacademy.org/" rel="noopener ugc nofollow" target="_blank">Khan Academy</a> for giving us Aphrodite which served us well for many years. This has been a huge effort at Airbnb that would not have been possible without all the work put in by so many people at Airbnb, including Mars Jullian, Josh Nelson, Nora Tarano, Alan Wright, Jimmy Guo, Ian Demattei-Selby, Victor Lin, Nnenna John, Adrianne Soike, Garrett Berg, Andrew Huth, Austin Wood, Chris Sorenson, and Miles Johnson. Finally, thank you to Surashree Kulkarni for help editing this blog post. Thank you all!</p></div></div></div><div class="ab cb qs qt qu qv" role="separator"><span class="qw by bm qx qy qz"></span><span class="qw by bm qx qy qz"></span><span class="qw by bm qx qy"></span></div><div class="gn go gp gq gr"><div class="ab cb"><div class="ci bh fz ga gb gc"><p id="d1bc" class="pw-post-body-paragraph nx ny gu nz b hs oa ob oc hv od oe of og oh oi oj ok ol om on oo op oq or os gn bk"><em class="qn">All product names, logos, and brands are property of their respective owners. All company, product and service names used in this website are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.</em></p></div></div></div></div></section></div></div></article></div><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="ra rb ab jm"><div class="rc ab"><a class="rd ay am ao" rel="noopener follow" href="/tag/css?source=post_page-----dc169230bd12--------------------------------"><div class="re fj cx rf ge rg rh bf b bg z bk ri">CSS</div></a></div><div class="rc ab"><a class="rd ay am ao" rel="noopener follow" href="/tag/web-performance?source=post_page-----dc169230bd12--------------------------------"><div class="re fj cx rf ge rg rh bf b bg z bk ri">Web Performance</div></a></div><div class="rc ab"><a class="rd ay am ao" rel="noopener follow" href="/tag/css-in-js?source=post_page-----dc169230bd12--------------------------------"><div class="re fj cx rf ge rg rh bf b bg z bk ri">Css In Js</div></a></div><div class="rc ab"><a class="rd ay am ao" rel="noopener follow" href="/tag/atomic-css?source=post_page-----dc169230bd12--------------------------------"><div class="re fj cx rf ge rg rh bf b bg z bk ri">Atomic Css</div></a></div><div class="rc ab"><a class="rd ay am ao" rel="noopener follow" href="/tag/open-source?source=post_page-----dc169230bd12--------------------------------"><div class="re fj cx rf ge rg rh bf b bg z bk ri">Open Source</div></a></div></div></div></div><div class="l"></div><footer class="rj rk rl rm rn ro rp rq rr ab q rs iw c"><div class="l ae"><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="ab cp rt"><div class="ab q lh"><div class="ru l"><span class="l rv rw rx e d"><div class="ab q lh li"><div class="pw-multi-vote-icon fj jq lj lk ll"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="footerClapButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fvote%2Fairbnb-engineering%2Fdc169230bd12&operation=register&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&user=Joe+Lencioni&userId=e52389684329&source=---footer_actions--dc169230bd12---------------------clap_footer-----------"><div><div class="bm" aria-hidden="false"><div class="lm ao ln lo lp lq am lr ls lt ll"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-label="clap"><path fill-rule="evenodd" d="M11.37.828 12 3.282l.63-2.454zM13.916 3.953l1.523-2.112-1.184-.39zM8.589 1.84l1.522 2.112-.337-2.501zM18.523 18.92c-.86.86-1.75 1.246-2.62 1.33a6 6 0 0 0 .407-.372c2.388-2.389 2.86-4.951 1.399-7.623l-.912-1.603-.79-1.672c-.26-.56-.194-.98.203-1.288a.7.7 0 0 1 .546-.132c.283.046.546.231.728.5l2.363 4.157c.976 1.624 1.141 4.237-1.324 6.702m-10.999-.438L3.37 14.328a.828.828 0 0 1 .585-1.408.83.83 0 0 1 .585.242l2.158 2.157a.365.365 0 0 0 .516-.516l-2.157-2.158-1.449-1.449a.826.826 0 0 1 1.167-1.17l3.438 3.44a.363.363 0 0 0 .516 0 .364.364 0 0 0 0-.516L5.293 9.513l-.97-.97a.826.826 0 0 1 0-1.166.84.84 0 0 1 1.167 0l.97.968 3.437 3.436a.36.36 0 0 0 .517 0 .366.366 0 0 0 0-.516L6.977 7.83a.82.82 0 0 1-.241-.584.82.82 0 0 1 .824-.826c.219 0 .43.087.584.242l5.787 5.787a.366.366 0 0 0 .587-.415l-1.117-2.363c-.26-.56-.194-.98.204-1.289a.7.7 0 0 1 .546-.132c.283.046.545.232.727.501l2.193 3.86c1.302 2.38.883 4.59-1.277 6.75-1.156 1.156-2.602 1.627-4.19 1.367-1.418-.236-2.866-1.033-4.079-2.246M10.75 5.971l2.12 2.12c-.41.502-.465 1.17-.128 1.89l.22.465-3.523-3.523a.8.8 0 0 1-.097-.368c0-.22.086-.428.241-.584a.847.847 0 0 1 1.167 0m7.355 1.705c-.31-.461-.746-.758-1.23-.837a1.44 1.44 0 0 0-1.11.275c-.312.24-.505.543-.59.881a1.74 1.74 0 0 0-.906-.465 1.47 1.47 0 0 0-.82.106l-2.182-2.182a1.56 1.56 0 0 0-2.2 0 1.54 1.54 0 0 0-.396.701 1.56 1.56 0 0 0-2.21-.01 1.55 1.55 0 0 0-.416.753c-.624-.624-1.649-.624-2.237-.037a1.557 1.557 0 0 0 0 2.2c-.239.1-.501.238-.715.453a1.56 1.56 0 0 0 0 2.2l.516.515a1.556 1.556 0 0 0-.753 2.615L7.01 19c1.32 1.319 2.909 2.189 4.475 2.449q.482.08.971.08c.85 0 1.653-.198 2.393-.579.231.033.46.054.686.054 1.266 0 2.457-.52 3.505-1.567 2.763-2.763 2.552-5.734 1.439-7.586z" clip-rule="evenodd"></path></svg></div></div></div></a></span></div><div class="pw-multi-vote-count l lu lv lw lx ly lz ma"><p class="bf b dv z du"><span class="mb">--</span></p></div></div></span><span class="l h g f ry rz"><div class="ab q lh li"><div class="pw-multi-vote-icon fj jq lj lk ll"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="footerClapButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fvote%2Fairbnb-engineering%2Fdc169230bd12&operation=register&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&user=Joe+Lencioni&userId=e52389684329&source=---footer_actions--dc169230bd12---------------------clap_footer-----------"><div><div class="bm" aria-hidden="false"><div class="lm ao ln lo lp lq am lr ls lt ll"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-label="clap"><path fill-rule="evenodd" d="M11.37.828 12 3.282l.63-2.454zM13.916 3.953l1.523-2.112-1.184-.39zM8.589 1.84l1.522 2.112-.337-2.501zM18.523 18.92c-.86.86-1.75 1.246-2.62 1.33a6 6 0 0 0 .407-.372c2.388-2.389 2.86-4.951 1.399-7.623l-.912-1.603-.79-1.672c-.26-.56-.194-.98.203-1.288a.7.7 0 0 1 .546-.132c.283.046.546.231.728.5l2.363 4.157c.976 1.624 1.141 4.237-1.324 6.702m-10.999-.438L3.37 14.328a.828.828 0 0 1 .585-1.408.83.83 0 0 1 .585.242l2.158 2.157a.365.365 0 0 0 .516-.516l-2.157-2.158-1.449-1.449a.826.826 0 0 1 1.167-1.17l3.438 3.44a.363.363 0 0 0 .516 0 .364.364 0 0 0 0-.516L5.293 9.513l-.97-.97a.826.826 0 0 1 0-1.166.84.84 0 0 1 1.167 0l.97.968 3.437 3.436a.36.36 0 0 0 .517 0 .366.366 0 0 0 0-.516L6.977 7.83a.82.82 0 0 1-.241-.584.82.82 0 0 1 .824-.826c.219 0 .43.087.584.242l5.787 5.787a.366.366 0 0 0 .587-.415l-1.117-2.363c-.26-.56-.194-.98.204-1.289a.7.7 0 0 1 .546-.132c.283.046.545.232.727.501l2.193 3.86c1.302 2.38.883 4.59-1.277 6.75-1.156 1.156-2.602 1.627-4.19 1.367-1.418-.236-2.866-1.033-4.079-2.246M10.75 5.971l2.12 2.12c-.41.502-.465 1.17-.128 1.89l.22.465-3.523-3.523a.8.8 0 0 1-.097-.368c0-.22.086-.428.241-.584a.847.847 0 0 1 1.167 0m7.355 1.705c-.31-.461-.746-.758-1.23-.837a1.44 1.44 0 0 0-1.11.275c-.312.24-.505.543-.59.881a1.74 1.74 0 0 0-.906-.465 1.47 1.47 0 0 0-.82.106l-2.182-2.182a1.56 1.56 0 0 0-2.2 0 1.54 1.54 0 0 0-.396.701 1.56 1.56 0 0 0-2.21-.01 1.55 1.55 0 0 0-.416.753c-.624-.624-1.649-.624-2.237-.037a1.557 1.557 0 0 0 0 2.2c-.239.1-.501.238-.715.453a1.56 1.56 0 0 0 0 2.2l.516.515a1.556 1.556 0 0 0-.753 2.615L7.01 19c1.32 1.319 2.909 2.189 4.475 2.449q.482.08.971.08c.85 0 1.653-.198 2.393-.579.231.033.46.054.686.054 1.266 0 2.457-.52 3.505-1.567 2.763-2.763 2.552-5.734 1.439-7.586z" clip-rule="evenodd"></path></svg></div></div></div></a></span></div><div class="pw-multi-vote-count l lu lv lw lx ly lz ma"><p class="bf b dv z du"><span class="mb">--</span></p></div></div></span></div><div class="bq ab"><div><div class="bm" aria-hidden="false"><button class="ao lm me mf ab q fk mg mh" aria-label="responses"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="md"><path d="M18.006 16.803c1.533-1.456 2.234-3.325 2.234-5.321C20.24 7.357 16.709 4 12.191 4S4 7.357 4 11.482c0 4.126 3.674 7.482 8.191 7.482.817 0 1.622-.111 2.393-.327.231.2.48.391.744.559 1.06.693 2.203 1.044 3.399 1.044.224-.008.4-.112.486-.287a.49.49 0 0 0-.042-.518c-.495-.67-.845-1.364-1.04-2.057a4 4 0 0 1-.125-.598zm-3.122 1.055-.067-.223-.315.096a8 8 0 0 1-2.311.338c-4.023 0-7.292-2.955-7.292-6.587 0-3.633 3.269-6.588 7.292-6.588 4.014 0 7.112 2.958 7.112 6.593 0 1.794-.608 3.469-2.027 4.72l-.195.168v.255c0 .056 0 .151.016.295.025.231.081.478.154.733.154.558.398 1.117.722 1.659a5.3 5.3 0 0 1-2.165-.845c-.276-.176-.714-.383-.941-.59z"></path></svg><p class="bf b bg z du"><span class="pw-responses-count mc md">6</span></p></button></div></div></div></div><div class="ab q"><div class="qz l jj"><div><div class="bm" aria-hidden="false"><span><a class="af ag ah ai aj ak al am an ao ap aq ar as at" data-testid="footerBookmarkButton" rel="noopener follow" href="/m/signin?actionUrl=https%3A%2F%2Fmedium.com%2F_%2Fbookmark%2Fp%2Fdc169230bd12&operation=register&redirect=https%3A%2F%2Fmedium.com%2Fairbnb-engineering%2Fairbnbs-trip-to-linaria-dc169230bd12&source=---footer_actions--dc169230bd12---------------------bookmark_footer-----------"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="none" viewBox="0 0 25 25" class="du mj" aria-label="Add to list bookmark button"><path fill="currentColor" d="M18 2.5a.5.5 0 0 1 1 0V5h2.5a.5.5 0 0 1 0 1H19v2.5a.5.5 0 1 1-1 0V6h-2.5a.5.5 0 0 1 0-1H18zM7 7a1 1 0 0 1 1-1h3.5a.5.5 0 0 0 0-1H8a2 2 0 0 0-2 2v14a.5.5 0 0 0 .805.396L12.5 17l5.695 4.396A.5.5 0 0 0 19 21v-8.5a.5.5 0 0 0-1 0v7.485l-5.195-4.012a.5.5 0 0 0-.61 0L7 19.985z"></path></svg></a></span></div></div></div><div class="qz l jj"><div class="bm" aria-hidden="false" aria-describedby="postFooterSocialMenu" aria-labelledby="postFooterSocialMenu"><div><div class="bm" aria-hidden="false"><button aria-controls="postFooterSocialMenu" aria-expanded="false" aria-label="Share Post" data-testid="footerSocialShareButton" class="af fk ah ai aj ak al mr an ao ap ex ms mt mh mu"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" d="M15.218 4.931a.4.4 0 0 1-.118.132l.012.006a.45.45 0 0 1-.292.074.5.5 0 0 1-.3-.13l-2.02-2.02v7.07c0 .28-.23.5-.5.5s-.5-.22-.5-.5v-7.04l-2 2a.45.45 0 0 1-.57.04h-.02a.4.4 0 0 1-.16-.3.4.4 0 0 1 .1-.32l2.8-2.8a.5.5 0 0 1 .7 0l2.8 2.79a.42.42 0 0 1 .068.498m-.106.138.008.004v-.01zM16 7.063h1.5a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-11c-1.1 0-2-.9-2-2v-10a2 2 0 0 1 2-2H8a.5.5 0 0 1 .35.15.5.5 0 0 1 .15.35.5.5 0 0 1-.15.35.5.5 0 0 1-.35.15H6.4c-.5 0-.9.4-.9.9v10.2a.9.9 0 0 0 .9.9h11.2c.5 0 .9-.4.9-.9v-10.2c0-.5-.4-.9-.9-.9H16a.5.5 0 0 1 0-1" clip-rule="evenodd"></path></svg></button></div></div></div></div></div></div></div></div></div></footer><div class="sa sb sc sd se l bx"><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="sf l"><div class="ab sg sh si jl jk"><div class="sj sk sl sm sn so sp sq sr ss ab cp"><div class="h k"><a href="https://medium.com/airbnb-engineering?source=post_page---post_publication_info--dc169230bd12--------------------------------" rel="noopener follow"><div class="fj ab"><img alt="The Airbnb Tech Blog" class="st in io cx" src="https://miro.medium.com/v2/resize:fill:96:96/1*MlNQKg-sieBGW5prWoe9HQ.jpeg" width="48" height="48" loading="lazy"/><div class="st l io in fs n fr su"></div></div></a></div><div class="j i d"><a href="https://medium.com/airbnb-engineering?source=post_page---post_publication_info--dc169230bd12--------------------------------" rel="noopener follow"><div class="fj ab"><img alt="The Airbnb Tech Blog" class="st sw sv cx" src="https://miro.medium.com/v2/resize:fill:128:128/1*MlNQKg-sieBGW5prWoe9HQ.jpeg" width="64" height="64" loading="lazy"/><div class="st l sv sw fs n fr su"></div></div></a></div><div class="j i d sx jj"><div class="ab"></div></div></div><div class="ab co sy"><div class="sz ta tb tc td l"><a class="af ag ah aj ak al am an ao ap aq ar as at ab q" href="https://medium.com/airbnb-engineering?source=post_page---post_publication_info--dc169230bd12--------------------------------" rel="noopener follow"><h2 class="pw-author-name bf tf tg th ti tj tk tl og tm tn ok to tp oo tq tr bk"><span class="gn te">Published in <!-- -->The Airbnb Tech Blog</span></h2></a><div class="rc ab im"><div class="l jj"><span class="pw-follower-count bf b bg z du"><a class="af ag ah ai aj ak al am an ao ap aq ar jc" rel="noopener follow" href="/airbnb-engineering/followers?source=post_page---post_publication_info--dc169230bd12--------------------------------">148K Followers</a></span></div><div class="bf b bg z du ab jp"><span class="jd l" aria-hidden="true"><span class="bf b bg z du">·</span></span><a class="af ag ah ai aj ak al am an ao ap aq ar jc" rel="noopener follow" href="/airbnb-engineering/from-data-to-insights-segmenting-airbnbs-supply-c88aa2bb9399?source=post_page---post_publication_info--dc169230bd12--------------------------------">Last published <!-- -->1 day ago</a></div></div><div class="ts l"><p class="bf b bg z bk">Creative engineers and data scientists building a world where you can belong anywhere. <a class="af ag ah ai aj ak al am an ao ap aq ar ot go" href="http://airbnb.io" rel="noopener ugc nofollow">http://airbnb.io</a></p></div></div></div><div class="h k"><div class="ab"></div></div></div></div><div class="ab sg sh si jl jk"><div class="sj sk sl sm sn so sp sq sr ss ab cp"><div class="h k"><a tabindex="0" rel="noopener follow" href="/@lencioni?source=post_page---post_author_info--dc169230bd12--------------------------------"><div class="l fj"><img alt="Joe Lencioni" class="l fd by io in cx" src="https://miro.medium.com/v2/resize:fill:96:96/1*r4bT1s_VG5WFqtCX5M-2lA.jpeg" width="48" height="48" loading="lazy"/><div class="fr by l io in fs n ay su"></div></div></a></div><div class="j i d"><a tabindex="0" rel="noopener follow" href="/@lencioni?source=post_page---post_author_info--dc169230bd12--------------------------------"><div class="l fj"><img alt="Joe Lencioni" class="l fd by sv sw cx" src="https://miro.medium.com/v2/resize:fill:128:128/1*r4bT1s_VG5WFqtCX5M-2lA.jpeg" width="64" height="64" loading="lazy"/><div class="fr by l sv sw fs n ay su"></div></div></a></div><div class="j i d sx jj"><div class="ab"><span><button class="bf b bg z tt re tu tv tw tx ty ev ew tz ua ub fa fb fc fd bm fe ff">Follow</button></span></div></div></div><div class="ab co sy"><div class="sz ta tb tc td l"><a class="af ag ah aj ak al am an ao ap aq ar as at ab q" rel="noopener follow" href="/@lencioni?source=post_page---post_author_info--dc169230bd12--------------------------------"><h2 class="pw-author-name bf tf tg th ti tj tk tl og tm tn ok to tp oo tq tr bk"><span class="gn te">Written by <!-- -->Joe Lencioni</span></h2></a><div class="rc ab im"><div class="l jj"><span class="pw-follower-count bf b bg z du"><a class="af ag ah ai aj ak al am an ao ap aq ar jc" rel="noopener follow" href="/@lencioni/followers?source=post_page---post_author_info--dc169230bd12--------------------------------">1.8K Followers</a></span></div><div class="bf b bg z du ab jp"><span class="jd l" aria-hidden="true"><span class="bf b bg z du">·</span></span><a class="af ag ah ai aj ak al am an ao ap aq ar jc" rel="noopener follow" href="/@lencioni/following?source=post_page---post_author_info--dc169230bd12--------------------------------">288 Following</a></div></div><div class="ts l"><p class="bf b bg z bk">Web infrastructure at @airbnb. Making web since the 90s. Co-created <a class="af ag ah ai aj ak al am an ao ap aq ar ot go" href="http://happo.io" rel="noopener ugc nofollow">happo.io</a>. he/him Minnesotan, liberal, dad. Follow @lencioni on Twitter.</p></div></div></div><div class="h k"><div class="ab"><span><button class="bf b bg z tt re tu tv tw tx ty ev ew tz ua ub fa fb fc fd bm fe ff">Follow</button></span></div></div></div><div class="uc bh ud ue"></div></div></div><div class="h k j"><div class="uc bh ud uf"></div><div class="ab cb"><div class="ci bh fz ga gb gc"><div class="ug ab lh jm"><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://help.medium.com/hc/en-us?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Help</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://medium.statuspage.io/?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Status</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" rel="noopener follow" href="/about?autoplay=1&source=post_page-----dc169230bd12--------------------------------"><p class="bf b dv z du">About</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" rel="noopener follow" href="/jobs-at-medium/work-at-medium-959d1a85284e?source=post_page-----dc169230bd12--------------------------------"><p class="bf b dv z du">Careers</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="pressinquiries@medium.com?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Press</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://blog.medium.com/?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Blog</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://policy.medium.com/medium-privacy-policy-f03bf92035c9?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Privacy</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://policy.medium.com/medium-terms-of-service-9db0094a1e0f?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Terms</p></a></div><div class="uh ui l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" href="https://speechify.com/medium?source=post_page-----dc169230bd12--------------------------------" rel="noopener follow"><p class="bf b dv z du">Text to speech</p></a></div><div class="uh l"><a class="af ag ah ai aj ak al am an ao ap aq ar as at" rel="noopener follow" href="/business?source=post_page-----dc169230bd12--------------------------------"><p class="bf b dv z du">Teams</p></a></div></div></div></div></div></div></div></div></div></div><script>window.__BUILD_ID__="main-20241126-181518-0cb59a020f"</script><script>window.__GRAPHQL_URI__ = "https://medium.com/_/graphql"</script><script>window.__PRELOADED_STATE__ = {"algolia":{"queries":{}},"cache":{"experimentGroupSet":true,"reason":"","group":"enabled","tags":["group-edgeCachePosts","post-dc169230bd12","user-e52389684329","collection-53c7c27702d5"],"serverVariantState":"44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","middlewareEnabled":true,"cacheStatus":"DYNAMIC","shouldUseCache":true,"vary":[],"lohpSummerUpsellEnabled":false,"publicationHierarchyEnabledWeb":false,"postBottomResponsesEnabled":false},"client":{"hydrated":false,"isUs":false,"isNativeMedium":false,"isSafariMobile":false,"isSafari":false,"isFirefox":false,"routingEntity":{"type":"DEFAULT","explicit":false},"viewerIsBot":false},"debug":{"requestId":"708ee140-f7c4-487f-a2a7-44b7c3d3412b","hybridDevServices":[],"originalSpanCarrier":{"traceparent":"00-cc8448b7aa461a825fe42cf55b496dd6-472617ba7298ed96-01"}},"multiVote":{"clapsPerPost":{}},"navigation":{"branch":{"show":null,"hasRendered":null,"blockedByCTA":false},"hideGoogleOneTap":false,"hasRenderedAlternateUserBanner":null,"currentLocation":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fairbnbs-trip-to-linaria-dc169230bd12","host":"medium.com","hostname":"medium.com","referrer":"","hasSetReferrer":false,"susiModal":{"step":null,"operation":"register"},"postRead":false,"partnerProgram":{"selectedCountryCode":null},"queryString":"","currentHash":""},"config":{"nodeEnv":"production","version":"main-20241126-181518-0cb59a020f","target":"production","productName":"Medium","publicUrl":"https:\u002F\u002Fcdn-client.medium.com\u002Flite","authDomain":"medium.com","authGoogleClientId":"216296035834-k1k6qe060s2tp2a2jam4ljdcms00sttg.apps.googleusercontent.com","favicon":"production","glyphUrl":"https:\u002F\u002Fglyph.medium.com","branchKey":"key_live_ofxXr2qTrrU9NqURK8ZwEhknBxiI6KBm","algolia":{"appId":"MQ57UUUQZ2","apiKeySearch":"394474ced050e3911ae2249ecc774921","indexPrefix":"medium_","host":"-dsn.algolia.net"},"recaptchaKey":"6Lfc37IUAAAAAKGGtC6rLS13R1Hrw_BqADfS1LRk","recaptcha3Key":"6Lf8R9wUAAAAABMI_85Wb8melS7Zj6ziuf99Yot5","recaptchaEnterpriseKeyId":"6Le-uGgpAAAAAPprRaokM8AKthQ9KNGdoxaGUvVp","datadog":{"applicationId":"6702d87d-a7e0-42fe-bbcb-95b469547ea0","clientToken":"pub853ea8d17ad6821d9f8f11861d23dfed","rumToken":"pubf9cc52896502b9413b68ba36fc0c7162","context":{"deployment":{"target":"production","tag":"main-20241126-181518-0cb59a020f","commit":"0cb59a020f4453d0900f671f1a6576feecc55e74"}},"datacenter":"us"},"googleAnalyticsCode":"G-7JY7T788PK","googlePay":{"apiVersion":"2","apiVersionMinor":"0","merchantId":"BCR2DN6TV7EMTGBM","merchantName":"Medium","instanceMerchantId":"13685562959212738550"},"applePay":{"version":3},"signInWallCustomDomainCollectionIds":["3a8144eabfe3","336d898217ee","61061eb0c96b","138adf9c44c","819cc2aaeee0"],"mediumMastodonDomainName":"me.dm","mediumOwnedAndOperatedCollectionIds":["8a9336e5bb4","b7e45b22fec3","193b68bd4fba","8d6b8a439e32","54c98c43354d","3f6ecf56618","d944778ce714","92d2092dc598","ae2a65f35510","1285ba81cada","544c7006046e","fc8964313712","40187e704f1c","88d9857e584e","7b6769f2748b","bcc38c8f6edf","cef6983b292","cb8577c9149e","444d13b52878","713d7dbc99b0","ef8e90590e66","191186aaafa0","55760f21cdc5","9dc80918cc93","bdc4052bbdba","8ccfed20cbb2"],"tierOneDomains":["medium.com","thebolditalic.com","arcdigital.media","towardsdatascience.com","uxdesign.cc","codeburst.io","psiloveyou.xyz","writingcooperative.com","entrepreneurshandbook.co","prototypr.io","betterhumans.coach.me","theascent.pub"],"topicsToFollow":["d61cf867d93f","8a146bc21b28","1eca0103fff3","4d562ee63426","aef1078a3ef5","e15e46793f8d","6158eb913466","55f1c20aba7a","3d18b94f6858","4861fee224fd","63c6f1f93ee","1d98b3a9a871","decb52b64abf","ae5d4995e225","830cded25262"],"topicToTagMappings":{"accessibility":"accessibility","addiction":"addiction","android-development":"android-development","art":"art","artificial-intelligence":"artificial-intelligence","astrology":"astrology","basic-income":"basic-income","beauty":"beauty","biotech":"biotech","blockchain":"blockchain","books":"books","business":"business","cannabis":"cannabis","cities":"cities","climate-change":"climate-change","comics":"comics","coronavirus":"coronavirus","creativity":"creativity","cryptocurrency":"cryptocurrency","culture":"culture","cybersecurity":"cybersecurity","data-science":"data-science","design":"design","digital-life":"digital-life","disability":"disability","economy":"economy","education":"education","equality":"equality","family":"family","feminism":"feminism","fiction":"fiction","film":"film","fitness":"fitness","food":"food","freelancing":"freelancing","future":"future","gadgets":"gadgets","gaming":"gaming","gun-control":"gun-control","health":"health","history":"history","humor":"humor","immigration":"immigration","ios-development":"ios-development","javascript":"javascript","justice":"justice","language":"language","leadership":"leadership","lgbtqia":"lgbtqia","lifestyle":"lifestyle","machine-learning":"machine-learning","makers":"makers","marketing":"marketing","math":"math","media":"media","mental-health":"mental-health","mindfulness":"mindfulness","money":"money","music":"music","neuroscience":"neuroscience","nonfiction":"nonfiction","outdoors":"outdoors","parenting":"parenting","pets":"pets","philosophy":"philosophy","photography":"photography","podcasts":"podcast","poetry":"poetry","politics":"politics","privacy":"privacy","product-management":"product-management","productivity":"productivity","programming":"programming","psychedelics":"psychedelics","psychology":"psychology","race":"race","relationships":"relationships","religion":"religion","remote-work":"remote-work","san-francisco":"san-francisco","science":"science","self":"self","self-driving-cars":"self-driving-cars","sexuality":"sexuality","social-media":"social-media","society":"society","software-engineering":"software-engineering","space":"space","spirituality":"spirituality","sports":"sports","startups":"startup","style":"style","technology":"technology","transportation":"transportation","travel":"travel","true-crime":"true-crime","tv":"tv","ux":"ux","venture-capital":"venture-capital","visual-design":"visual-design","work":"work","world":"world","writing":"writing"},"defaultImages":{"avatar":{"imageId":"1*dmbNkD5D-u45r44go_cf0g.png","height":150,"width":150},"orgLogo":{"imageId":"7*V1_7XP4snlmqrc_0Njontw.png","height":110,"width":500},"postLogo":{"imageId":"bd978bb536350a710e8efb012513429cabdc4c28700604261aeda246d0f980b7","height":810,"width":1440},"postPreviewImage":{"imageId":"1*hn4v1tCaJy7cWMyb0bpNpQ.png","height":386,"width":579}},"collectionStructuredData":{"8d6b8a439e32":{"name":"Elemental","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F980\u002F1*9ygdqoKprhwuTVKUM0DLPA@2x.png","width":980,"height":159}}},"3f6ecf56618":{"name":"Forge","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F596\u002F1*uULpIlImcO5TDuBZ6lm7Lg@2x.png","width":596,"height":183}}},"ae2a65f35510":{"name":"GEN","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F264\u002F1*RdVZMdvfV3YiZTw6mX7yWA.png","width":264,"height":140}}},"88d9857e584e":{"name":"LEVEL","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F540\u002F1*JqYMhNX6KNNb2UlqGqO2WQ.png","width":540,"height":108}}},"7b6769f2748b":{"name":"Marker","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fcdn-images-1.medium.com\u002Fmax\u002F383\u002F1*haCUs0wF6TgOOvfoY-jEoQ@2x.png","width":383,"height":92}}},"444d13b52878":{"name":"OneZero","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F540\u002F1*cw32fIqCbRWzwJaoQw6BUg.png","width":540,"height":123}}},"8ccfed20cbb2":{"name":"Zora","data":{"@type":"NewsMediaOrganization","ethicsPolicy":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Farticles\u002F360043290473","logo":{"@type":"ImageObject","url":"https:\u002F\u002Fmiro.medium.com\u002Fmax\u002F540\u002F1*tZUQqRcCCZDXjjiZ4bDvgQ.png","width":540,"height":106}}}},"embeddedPostIds":{"coronavirus":"cd3010f9d81f"},"sharedCdcMessaging":{"COVID_APPLICABLE_TAG_SLUGS":[],"COVID_APPLICABLE_TOPIC_NAMES":[],"COVID_APPLICABLE_TOPIC_NAMES_FOR_TOPIC_PAGE":[],"COVID_MESSAGES":{"tierA":{"text":"For more information on the novel coronavirus and Covid-19, visit cdc.gov.","markups":[{"start":66,"end":73,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]},"tierB":{"text":"Anyone can publish on Medium per our Policies, but we don’t fact-check every story. For more info about the coronavirus, see cdc.gov.","markups":[{"start":37,"end":45,"href":"https:\u002F\u002Fhelp.medium.com\u002Fhc\u002Fen-us\u002Fcategories\u002F201931128-Policies-Safety"},{"start":125,"end":132,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]},"paywall":{"text":"This article has been made free for everyone, thanks to Medium Members. For more information on the novel coronavirus and Covid-19, visit cdc.gov.","markups":[{"start":56,"end":70,"href":"https:\u002F\u002Fmedium.com\u002Fmembership"},{"start":138,"end":145,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]},"unbound":{"text":"This article is free for everyone, thanks to Medium Members. For more information on the novel coronavirus and Covid-19, visit cdc.gov.","markups":[{"start":45,"end":59,"href":"https:\u002F\u002Fmedium.com\u002Fmembership"},{"start":127,"end":134,"href":"https:\u002F\u002Fwww.cdc.gov\u002Fcoronavirus\u002F2019-nCoV"}]}},"COVID_BANNER_POST_ID_OVERRIDE_WHITELIST":["3b31a67bff4a"]},"sharedVoteMessaging":{"TAGS":["politics","election-2020","government","us-politics","election","2020-presidential-race","trump","donald-trump","democrats","republicans","congress","republican-party","democratic-party","biden","joe-biden","maga"],"TOPICS":["politics","election"],"MESSAGE":{"text":"Find out more about the U.S. election results here.","markups":[{"start":46,"end":50,"href":"https:\u002F\u002Fcookpolitical.com\u002F2020-national-popular-vote-tracker"}]},"EXCLUDE_POSTS":["397ef29e3ca5"]},"embedPostRules":[],"recircOptions":{"v1":{"limit":3},"v2":{"limit":8}},"braintreeClientKey":"production_zjkj96jm_m56f8fqpf7ngnrd4","braintree":{"enabled":true,"merchantId":"m56f8fqpf7ngnrd4","merchantAccountId":{"usd":"AMediumCorporation_instant","eur":"amediumcorporation_EUR","cad":"amediumcorporation_CAD"},"publicKey":"ds2nn34bg2z7j5gd","braintreeEnvironment":"production","dashboardUrl":"https:\u002F\u002Fwww.braintreegateway.com\u002Fmerchants","gracePeriodDurationInDays":14,"mediumMembershipPlanId":{"monthly":"ce105f8c57a3","monthlyV2":"e8a5e126-792b-4ee6-8fba-d574c1b02fc5","monthlyWithTrial":"d5ee3dbe3db8","monthlyPremium":"fa741a9b47a2","yearly":"a40ad4a43185","yearlyV2":"3815d7d6-b8ca-4224-9b8c-182f9047866e","yearlyStaff":"d74fb811198a","yearlyWithTrial":"b3bc7350e5c7","yearlyPremium":"e21bd2c12166","monthlyOneYearFree":"e6c0637a-2bad-4171-ab4f-3c268633d83c","monthly25PercentOffFirstYear":"235ecc62-0cdb-49ae-9378-726cd21c504b","monthly20PercentOffFirstYear":"ba518864-9c13-4a99-91ca-411bf0cac756","monthly15PercentOffFirstYear":"594c029b-9f89-43d5-88f8-8173af4e070e","monthly10PercentOffFirstYear":"c6c7bc9a-40f2-4b51-8126-e28511d5bdb0","monthlyForStudents":"629ebe51-da7d-41fd-8293-34cd2f2030a8","yearlyOneYearFree":"78ba7be9-0d9f-4ece-aa3e-b54b826f2bf1","yearly25PercentOffFirstYear":"2dbb010d-bb8f-4eeb-ad5c-a08509f42d34","yearly20PercentOffFirstYear":"47565488-435b-47f8-bf93-40d5fbe0ebc8","yearly15PercentOffFirstYear":"8259809b-0881-47d9-acf7-6c001c7f720f","yearly10PercentOffFirstYear":"9dd694fb-96e1-472c-8d9e-3c868d5c1506","yearlyForStudents":"e29345ef-ab1c-4234-95c5-70e50fe6bc23","monthlyCad":"p52orjkaceei","yearlyCad":"h4q9g2up9ktt"},"braintreeDiscountId":{"oneMonthFree":"MONTHS_FREE_01","threeMonthsFree":"MONTHS_FREE_03","sixMonthsFree":"MONTHS_FREE_06","fiftyPercentOffOneYear":"FIFTY_PERCENT_OFF_ONE_YEAR"},"3DSecureVersion":"2","defaultCurrency":"usd","providerPlanIdCurrency":{"4ycw":"usd","rz3b":"usd","3kqm":"usd","jzw6":"usd","c2q2":"usd","nnsw":"usd","q8qw":"usd","d9y6":"usd","fx7w":"cad","nwf2":"cad"}},"paypalClientId":"AXj1G4fotC2GE8KzWX9mSxCH1wmPE3nJglf4Z2ig_amnhvlMVX87otaq58niAg9iuLktVNF_1WCMnN7v","paypal":{"host":"https:\u002F\u002Fapi.paypal.com:443","clientMode":"production","serverMode":"live","webhookId":"4G466076A0294510S","monthlyPlan":{"planId":"P-9WR0658853113943TMU5FDQA","name":"Medium Membership (Monthly) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"yearlyPlan":{"planId":"P-7N8963881P8875835MU5JOPQ","name":"Medium Membership (Annual) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"oneYearGift":{"name":"Medium Membership (1 Year, Digital Gift Code)","description":"Unlimited access to the best and brightest stories on Medium. Gift codes can be redeemed at medium.com\u002Fredeem.","price":"50.00","currency":"USD","sku":"membership-gift-1-yr"},"oldMonthlyPlan":{"planId":"P-96U02458LM656772MJZUVH2Y","name":"Medium Membership (Monthly)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"oldYearlyPlan":{"planId":"P-59P80963JF186412JJZU3SMI","name":"Medium Membership (Annual)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"monthlyPlanWithTrial":{"planId":"P-66C21969LR178604GJPVKUKY","name":"Medium Membership (Monthly) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"yearlyPlanWithTrial":{"planId":"P-6XW32684EX226940VKCT2MFA","name":"Medium Membership (Annual) with setup fee","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"oldMonthlyPlanNoSetupFee":{"planId":"P-4N046520HR188054PCJC7LJI","name":"Medium Membership (Monthly)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed monthly."},"oldYearlyPlanNoSetupFee":{"planId":"P-7A4913502Y5181304CJEJMXQ","name":"Medium Membership (Annual)","description":"Unlimited access to the best and brightest stories on Medium. Membership billed annually."},"sdkUrl":"https:\u002F\u002Fwww.paypal.com\u002Fsdk\u002Fjs"},"stripePublishableKey":"pk_live_7FReX44VnNIInZwrIIx6ghjl","log":{"json":true,"level":"info"},"imageUploadMaxSizeMb":25,"staffPicks":{"title":"Staff Picks","catalogId":"c7bc6e1ee00f"}},"session":{"xsrf":""}}</script><script>window.__APOLLO_STATE__ = {"ROOT_QUERY":{"__typename":"Query","viewer":null,"collectionByDomainOrSlug({\"domainOrSlug\":\"airbnb-engineering\"})":{"__ref":"Collection:53c7c27702d5"},"postResult({\"id\":\"dc169230bd12\"})":{"__ref":"Post:dc169230bd12"}},"ImageMetadata:":{"__typename":"ImageMetadata","id":""},"Collection:53c7c27702d5":{"__typename":"Collection","id":"53c7c27702d5","favicon":{"__ref":"ImageMetadata:"},"customStyleSheet":null,"colorPalette":{"__typename":"ColorPalette","highlightSpectrum":{"__typename":"ColorSpectrum","backgroundColor":"#FFFFFFFF","colorPoints":[{"__typename":"ColorPoint","color":"#FFE4F7F8","point":0},{"__typename":"ColorPoint","color":"#FFDFF6F7","point":0.1},{"__typename":"ColorPoint","color":"#FFDAF6F6","point":0.2},{"__typename":"ColorPoint","color":"#FFD5F5F6","point":0.3},{"__typename":"ColorPoint","color":"#FFCFF4F5","point":0.4},{"__typename":"ColorPoint","color":"#FFC9F3F4","point":0.5},{"__typename":"ColorPoint","color":"#FFC3F2F4","point":0.6},{"__typename":"ColorPoint","color":"#FFBDF1F3","point":0.7},{"__typename":"ColorPoint","color":"#FFB7F0F3","point":0.8},{"__typename":"ColorPoint","color":"#FFB1F0F2","point":0.9},{"__typename":"ColorPoint","color":"#FFAAEFF1","point":1}]},"defaultBackgroundSpectrum":{"__typename":"ColorSpectrum","backgroundColor":"#FFFFFFFF","colorPoints":[{"__typename":"ColorPoint","color":"#FF30969A","point":0},{"__typename":"ColorPoint","color":"#FF338B8E","point":0.1},{"__typename":"ColorPoint","color":"#FF338083","point":0.2},{"__typename":"ColorPoint","color":"#FF337477","point":0.3},{"__typename":"ColorPoint","color":"#FF31696B","point":0.4},{"__typename":"ColorPoint","color":"#FF2F5D5F","point":0.5},{"__typename":"ColorPoint","color":"#FF2B5153","point":0.6},{"__typename":"ColorPoint","color":"#FF264546","point":0.7},{"__typename":"ColorPoint","color":"#FF203839","point":0.8},{"__typename":"ColorPoint","color":"#FF192B2C","point":0.9},{"__typename":"ColorPoint","color":"#FF101D1D","point":1}]},"tintBackgroundSpectrum":{"__typename":"ColorSpectrum","backgroundColor":"#FF007E82","colorPoints":[{"__typename":"ColorPoint","color":"#FF007E82","point":0},{"__typename":"ColorPoint","color":"#FF368D91","point":0.1},{"__typename":"ColorPoint","color":"#FF529C9F","point":0.2},{"__typename":"ColorPoint","color":"#FF6AAAAD","point":0.3},{"__typename":"ColorPoint","color":"#FF80B8BA","point":0.4},{"__typename":"ColorPoint","color":"#FF95C5C7","point":0.5},{"__typename":"ColorPoint","color":"#FFA9D2D4","point":0.6},{"__typename":"ColorPoint","color":"#FFBDDFE0","point":0.7},{"__typename":"ColorPoint","color":"#FFCFEBEC","point":0.8},{"__typename":"ColorPoint","color":"#FFE2F7F7","point":0.9},{"__typename":"ColorPoint","color":"#FFF4FFFF","point":1}]}},"domain":null,"slug":"airbnb-engineering","googleAnalyticsId":null,"editors":[{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:ebe93072cafd"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:715069fb9693"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:2c64fccbad80"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:f4c9b6905436"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:d06d84a4dee7"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:ae9de0d76057"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:8a8dba98ccda"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:ba68c6ee8dae"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:5315ce63140f"}},{"__typename":"CollectionMastheadUserItem","user":{"__ref":"User:23561a2a5df3"}}],"name":"The Airbnb Tech Blog","avatar":{"__ref":"ImageMetadata:1*MlNQKg-sieBGW5prWoe9HQ.jpeg"},"description":"Creative engineers and data scientists building a world where you can belong anywhere. http:\u002F\u002Fairbnb.io","subscriberCount":148726,"latestPostsConnection({\"paging\":{\"limit\":1}})":{"__typename":"PostConnection","posts":[{"__ref":"Post:c88aa2bb9399"}]},"viewerEdge":{"__ref":"CollectionViewerEdge:collectionId:53c7c27702d5-viewerId:lo_4d3df4fece5e"},"twitterUsername":"AirbnbEng","facebookPageId":null,"logo":{"__ref":"ImageMetadata:1*JZl-TXoSiG0VmYn3qWLdTA.png"}},"User:ebe93072cafd":{"__typename":"User","id":"ebe93072cafd"},"User:715069fb9693":{"__typename":"User","id":"715069fb9693"},"User:2c64fccbad80":{"__typename":"User","id":"2c64fccbad80"},"User:f4c9b6905436":{"__typename":"User","id":"f4c9b6905436"},"User:d06d84a4dee7":{"__typename":"User","id":"d06d84a4dee7"},"User:ae9de0d76057":{"__typename":"User","id":"ae9de0d76057"},"User:8a8dba98ccda":{"__typename":"User","id":"8a8dba98ccda"},"User:ba68c6ee8dae":{"__typename":"User","id":"ba68c6ee8dae"},"User:5315ce63140f":{"__typename":"User","id":"5315ce63140f"},"User:23561a2a5df3":{"__typename":"User","id":"23561a2a5df3"},"ImageMetadata:1*MlNQKg-sieBGW5prWoe9HQ.jpeg":{"__typename":"ImageMetadata","id":"1*MlNQKg-sieBGW5prWoe9HQ.jpeg"},"User:7cade6b6b883":{"__typename":"User","id":"7cade6b6b883","customDomainState":null,"hasSubdomain":false,"username":"alexsalama"},"Post:c88aa2bb9399":{"__typename":"Post","id":"c88aa2bb9399","firstPublishedAt":1732557741764,"creator":{"__ref":"User:7cade6b6b883"},"collection":{"__ref":"Collection:53c7c27702d5"},"isSeries":false,"mediumUrl":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Ffrom-data-to-insights-segmenting-airbnbs-supply-c88aa2bb9399","sequence":null,"uniqueSlug":"from-data-to-insights-segmenting-airbnbs-supply-c88aa2bb9399"},"LinkedAccounts:e52389684329":{"__typename":"LinkedAccounts","mastodon":null,"id":"e52389684329"},"UserViewerEdge:userId:e52389684329-viewerId:lo_4d3df4fece5e":{"__typename":"UserViewerEdge","id":"userId:e52389684329-viewerId:lo_4d3df4fece5e","isFollowing":false,"isUser":false,"isMuting":false},"NewsletterV3:86d74eeda6e3":{"__typename":"NewsletterV3","id":"86d74eeda6e3","type":"NEWSLETTER_TYPE_AUTHOR","slug":"e52389684329","name":"e52389684329","collection":null,"user":{"__ref":"User:e52389684329"}},"User:e52389684329":{"__typename":"User","id":"e52389684329","name":"Joe Lencioni","username":"lencioni","newsletterV3":{"__ref":"NewsletterV3:86d74eeda6e3"},"linkedAccounts":{"__ref":"LinkedAccounts:e52389684329"},"isSuspended":false,"imageId":"1*r4bT1s_VG5WFqtCX5M-2lA.jpeg","mediumMemberAt":0,"verifications":{"__typename":"VerifiedInfo","isBookAuthor":false},"socialStats":{"__typename":"SocialStats","followerCount":1864,"followingCount":240,"collectionFollowingCount":48},"customDomainState":{"__typename":"CustomDomainState","live":{"__typename":"CustomDomain","domain":"lencioni.medium.com"}},"hasSubdomain":true,"bio":"Web infrastructure at @airbnb. Making web since the 90s. Co-created happo.io. he\u002Fhim Minnesotan, liberal, dad. Follow @lencioni on Twitter.","isPartnerProgramEnrolled":false,"viewerEdge":{"__ref":"UserViewerEdge:userId:e52389684329-viewerId:lo_4d3df4fece5e"},"viewerIsUser":false,"postSubscribeMembershipUpsellShownAt":0,"membership":null,"allowNotes":true,"twitterScreenName":"lencioni"},"Topic:55f1c20aba7a":{"__typename":"Topic","slug":"software-engineering","id":"55f1c20aba7a","name":"Software Engineering"},"Paragraph:5a62db7e743d_0":{"__typename":"Paragraph","id":"5a62db7e743d_0","name":"14e6","type":"H3","href":null,"layout":null,"metadata":null,"text":"Airbnb’s Trip to Linaria","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":0,"end":24,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_1":{"__typename":"Paragraph","id":"5a62db7e743d_1","name":"0d0b","type":"H4","href":null,"layout":null,"metadata":null,"text":"Learn how Linaria, Airbnb’s newest choice for web styling, improved both developer experience and web performance","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:1*-qT4pQIPIsxHBZj22sQtag.jpeg":{"__typename":"ImageMetadata","id":"1*-qT4pQIPIsxHBZj22sQtag.jpeg","originalHeight":2670,"originalWidth":4000,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:5a62db7e743d_2":{"__typename":"Paragraph","id":"5a62db7e743d_2","name":"1b49","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:1*-qT4pQIPIsxHBZj22sQtag.jpeg"},"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_3":{"__typename":"Paragraph","id":"5a62db7e743d_3","name":"655f","type":"P","href":null,"layout":null,"metadata":null,"text":"CSS is a critical component of every web application, and many solutions have evolved for how styles are written by developers and delivered to visitors. In this post we’ll take you through Airbnb’s journey from Sass to CSS-in-JS and show you why we landed on Linaria, a zero-runtime CSS-in-JS library, and the impact it has had on the developer experience and performance of Airbnb’s web app.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":260,"end":301,"href":"https:\u002F\u002Fgithub.com\u002Fcallstack\u002Flinaria","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_4":{"__typename":"Paragraph","id":"5a62db7e743d_4","name":"77ce","type":"H3","href":null,"layout":null,"metadata":null,"text":"From Sass to CSS-in-JS","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_5":{"__typename":"Paragraph","id":"5a62db7e743d_5","name":"e1c6","type":"P","href":null,"layout":null,"metadata":null,"text":"In 2016, our web frontend was in a monolithic Ruby on Rails app using a combination of Sprockets, Browserify, and Sass. We had a Bootstrap-inspired internal toolkit for styling, but we weren’t using anything like CSS Modules or BEM.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":46,"end":59,"href":"https:\u002F\u002Frubyonrails.org\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":87,"end":96,"href":"https:\u002F\u002Fgithub.com\u002Frails\u002Fsprockets","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":98,"end":108,"href":"https:\u002F\u002Fbrowserify.org\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":114,"end":118,"href":"https:\u002F\u002Fsass-lang.com\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":129,"end":138,"href":"https:\u002F\u002Fgetbootstrap.com\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":213,"end":224,"href":"https:\u002F\u002Fgithub.com\u002Fcss-modules\u002Fcss-modules","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":228,"end":231,"href":"http:\u002F\u002Fgetbem.com\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_6":{"__typename":"Paragraph","id":"5a62db7e743d_6","name":"aafb","type":"P","href":null,"layout":null,"metadata":null,"text":"Production bugs were often caused by our styling — sometimes the correct stylesheet was missing from some pages and other times styles from different stylesheets conflicted unexpectedly.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"MediaResource:87a9281e173621a774aa89d0f59370a7":{"__typename":"MediaResource","id":"87a9281e173621a774aa89d0f59370a7","iframeSrc":"https:\u002F\u002Fcdn.embedly.com\u002Fwidgets\u002Fmedia.html?type=text%2Fhtml&key=a19fcc184b9711e1b4764040d3dc5c07&schema=twitter&url=https%3A\u002F\u002Ftwitter.com\u002Fthomasfuchs\u002Fstatus\u002F493790680397803521&image=https%3A\u002F\u002Fi.embed.ly\u002F1\u002Fimage%3Furl%3Dhttps%253A%252F%252Fabs.twimg.com%252Ferrors%252Flogo46x38.png%26key%3Da19fcc184b9711e1b4764040d3dc5c07","iframeHeight":281,"iframeWidth":500,"title":"Thomas \"🐈🔭🕹\" Fuchs on Twitter: \"Two CSS properties walk into a bar.A barstool in a completely different bar falls over. \u002F Twitter\""},"Paragraph:5a62db7e743d_7":{"__typename":"Paragraph","id":"5a62db7e743d_7","name":"9a4d","type":"IFRAME","href":null,"layout":"INSET_CENTER","metadata":null,"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":{"__typename":"Iframe","mediaResource":{"__ref":"MediaResource:87a9281e173621a774aa89d0f59370a7"}},"mixtapeMetadata":null},"Paragraph:5a62db7e743d_8":{"__typename":"Paragraph","id":"5a62db7e743d_8","name":"d300","type":"P","href":null,"layout":null,"metadata":null,"text":"Additionally, developers rarely removed styles once added since it was hard to know whether they were still needed. These issues compounded as our product surface area rapidly expanded.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":25,"end":114,"href":"https:\u002F\u002Fcss-tricks.com\u002Fhow-do-you-remove-unused-css-from-a-site\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_9":{"__typename":"Paragraph","id":"5a62db7e743d_9","name":"bbcf","type":"P","href":null,"layout":null,"metadata":null,"text":"As we began to build our Design System in React, we landed on CSS-in-JS as an exciting new option. At the time, CSS-in-JS was still in its infancy–only a few libraries existed and Styled Components had not been invented yet. We chose Aphrodite, but didn’t want to be directly coupled to Aphrodite’s implementation for two reasons: since CSS-in-JS was a nascent space we wanted to have the flexibility to switch implementations at a later date, and we also wanted something that would work for open source projects where people might not want Aphrodite. So we created an abstraction layer called react-with-styles, which gave us a higher-order component (HOC) to define themeable styles.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":25,"end":38,"href":"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=fHQ1WSx41CA","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":180,"end":197,"href":"https:\u002F\u002Fstyled-components.com\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":234,"end":243,"href":"https:\u002F\u002Fgithub.com\u002Fkhan\u002Faphrodite","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":595,"end":612,"href":"https:\u002F\u002Fgithub.com\u002Fairbnb\u002Freact-with-styles","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":630,"end":658,"href":"https:\u002F\u002Freactjs.org\u002Fdocs\u002Fhigher-order-components.html","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"MediaResource:0d5993a13c08a6ad1017623c4cbb4255":{"__typename":"MediaResource","id":"0d5993a13c08a6ad1017623c4cbb4255","iframeSrc":"","iframeHeight":0,"iframeWidth":0,"title":"react-with-styles Example"},"Paragraph:5a62db7e743d_10":{"__typename":"Paragraph","id":"5a62db7e743d_10","name":"3e53","type":"IFRAME","href":null,"layout":"INSET_CENTER","metadata":null,"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":{"__typename":"Iframe","mediaResource":{"__ref":"MediaResource:0d5993a13c08a6ad1017623c4cbb4255"}},"mixtapeMetadata":null},"Paragraph:5a62db7e743d_11":{"__typename":"Paragraph","id":"5a62db7e743d_11","name":"329e","type":"P","href":null,"layout":null,"metadata":null,"text":"This allowed components to be styled in the same file, making repo organization more convenient. More importantly, moving from a globally-aware styling system to a component-based styling system gave us guarantees around how styles would be applied and what files were needed to render every component correctly on every page. This enabled us to rely on Happo, our screenshot testing tool of choice, and as a result visual regressions plummeted (disclosure: I am the co-creator of Happo).","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":354,"end":398,"href":"https:\u002F\u002Fhappo.io\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":115,"end":325,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_12":{"__typename":"Paragraph","id":"5a62db7e743d_12","name":"2c14","type":"P","href":null,"layout":null,"metadata":null,"text":"Though react-with-styles has served us well for years, it comes with performance and developer experience tradeoffs. The styles and runtime libraries increase critical path JS bundle size, and applying styles at render-time comes with a CPU cost (10–20% of our component mount times). While we get the aforementioned guarantees about styles, actually writing styles in JavaScript objects feels awkward compared to regular CSS syntax. These tradeoffs led us to reconsider how we style the web at Airbnb.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":69,"end":80,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":85,"end":105,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_13":{"__typename":"Paragraph","id":"5a62db7e743d_13","name":"30b1","type":"H3","href":null,"layout":null,"metadata":null,"text":"Considering Our Options","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_14":{"__typename":"Paragraph","id":"5a62db7e743d_14","name":"7b23","type":"P","href":null,"layout":null,"metadata":null,"text":"To address the problems with react-with-styles, we formed a working group of engineers from various teams. We considered a number of directions, which fit into the following high-level categories:","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_15":{"__typename":"Paragraph","id":"5a62db7e743d_15","name":"adfa","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Static extraction of CSS from react-with-styles at build time","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_16":{"__typename":"Paragraph","id":"5a62db7e743d_16","name":"761f","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Write our own framework","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_17":{"__typename":"Paragraph","id":"5a62db7e743d_17","name":"f326","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Investigate and adopt an existing framework","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_18":{"__typename":"Paragraph","id":"5a62db7e743d_18","name":"decd","type":"P","href":null,"layout":null,"metadata":null,"text":"We decided against static extraction from react-with-styles at build time because it would require a lot of effort. Additionally, it would be home-grown and therefore lack benefits of a community. Finally, it does not address developer ergonomics issues.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":19,"end":36,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_19":{"__typename":"Paragraph","id":"5a62db7e743d_19","name":"3a5c","type":"P","href":null,"layout":null,"metadata":null,"text":"Similarly, writing our own framework would have had a high cost of initial implementation, maintenance, and support. Additionally, there were existing solutions for this problem that we wanted to leverage and contribute back to.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":11,"end":36,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*7Kwk-MuLZOIUhgnv":{"__typename":"ImageMetadata","id":"0*7Kwk-MuLZOIUhgnv","originalHeight":283,"originalWidth":500,"focusPercentX":null,"focusPercentY":null,"alt":"An xkcd comic titled “How Standards Proliferate: (see: A\u002FC chargers, character encodings, instant messaging, etc). Panel 1: Situation: There are 14 competing standards. Panel 2: “14?! Ridiculous! We need to develop one universal standard that covers everyone’s use cases.” “Yeah!” Panel 3: Soon: Situation: There are 15 competing standards."},"Paragraph:5a62db7e743d_20":{"__typename":"Paragraph","id":"5a62db7e743d_20","name":"46e0","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*7Kwk-MuLZOIUhgnv"},"text":"Comic from https:\u002F\u002Fxkcd.com\u002F927\u002F by Randall Munroe and is used under a CC-BY-NC 2.5 license.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":11,"end":32,"href":"https:\u002F\u002Fxkcd.com\u002F927\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_21":{"__typename":"Paragraph","id":"5a62db7e743d_21","name":"6666","type":"P","href":null,"layout":null,"metadata":null,"text":"After evaluating several existing frameworks against our requirements, we narrowed down candidates for building a proof of concept:","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":25,"end":44,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_22":{"__typename":"Paragraph","id":"5a62db7e743d_22","name":"0a23","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Emotion: CSS-in-JS, with a low runtime cost","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":0,"end":7,"href":"https:\u002F\u002Femotion.sh\u002Fdocs\u002Fintroduction","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_23":{"__typename":"Paragraph","id":"5a62db7e743d_23","name":"6872","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Linaria: zero-runtime CSS-in-JS (static CSS extraction)","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":0,"end":7,"href":"https:\u002F\u002Fgithub.com\u002Fcallstack\u002Flinaria","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_24":{"__typename":"Paragraph","id":"5a62db7e743d_24","name":"bb46","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Treat: near zero-runtime CSS-in-JS (static CSS extraction)","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":0,"end":5,"href":"https:\u002F\u002Fgithub.com\u002Fseek-oss\u002Ftreat","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_25":{"__typename":"Paragraph","id":"5a62db7e743d_25","name":"da82","type":"P","href":null,"layout":null,"metadata":null,"text":"The proof-of-concepting work was done in a new repo that implemented a server-rendered client-hydrated unstyled version of Airbnb’s logged in homepage. For each framework, this allowed us to:","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_26":{"__typename":"Paragraph","id":"5a62db7e743d_26","name":"9ee9","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Understand what changes might need to be made to our build system","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_27":{"__typename":"Paragraph","id":"5a62db7e743d_27","name":"f5b7","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Try out framework APIs and get a feel for developer ergonomics","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_28":{"__typename":"Paragraph","id":"5a62db7e743d_28","name":"d4fe","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Assess how each framework supports our web styling requirements","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_29":{"__typename":"Paragraph","id":"5a62db7e743d_29","name":"092a","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Gather performance metrics","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_30":{"__typename":"Paragraph","id":"5a62db7e743d_30","name":"5935","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Serve as a starting point for a migration plan","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_31":{"__typename":"Paragraph","id":"5a62db7e743d_31","name":"f6cd","type":"P","href":null,"layout":null,"metadata":null,"text":"Frameworks were evaluated against each other based on the following ranked list of criteria:","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_32":{"__typename":"Paragraph","id":"5a62db7e743d_32","name":"7204","type":"OLI","href":null,"layout":null,"metadata":null,"text":"Performance","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":0,"end":11,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_33":{"__typename":"Paragraph","id":"5a62db7e743d_33","name":"602e","type":"OLI","href":null,"layout":null,"metadata":null,"text":"Community (i.e. support and adoption)","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":0,"end":9,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_34":{"__typename":"Paragraph","id":"5a62db7e743d_34","name":"15c7","type":"OLI","href":null,"layout":null,"metadata":null,"text":"Developer experience","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":0,"end":20,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_35":{"__typename":"Paragraph","id":"5a62db7e743d_35","name":"8b61","type":"H3","href":null,"layout":null,"metadata":null,"text":"Performance Analysis","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_36":{"__typename":"Paragraph","id":"5a62db7e743d_36","name":"4e2e","type":"P","href":null,"layout":null,"metadata":null,"text":"Using SpeedCurve, local benchmarking, and the React \u003CProfiler \u002F\u003E, we ran performance benchmarking tests for each framework. All results were calculated as the median of 200 runs on a throttled MacBook Pro, and are statistically significantly different from control with a p-value of \u003C= 0.05.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":6,"end":16,"href":"https:\u002F\u002Fwww.speedcurve.com\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":46,"end":64,"href":"https:\u002F\u002Freactjs.org\u002Fdocs\u002Fprofiler.html","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_37":{"__typename":"Paragraph","id":"5a62db7e743d_37","name":"d82e","type":"P","href":null,"layout":null,"metadata":null,"text":"Informed by Airbnb’s Page Performance Score (similar to Lighthouse’s performance score), we focused on the following metrics to give us an idea of how each framework performed and would impact the user experience:","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":12,"end":43,"href":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fcreating-airbnbs-page-performance-score-5f664be0936","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":56,"end":86,"href":"https:\u002F\u002Fweb.dev\u002Fperformance-scoring\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_38":{"__typename":"Paragraph","id":"5a62db7e743d_38","name":"5d16","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Total blocking time (TBT)","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":0,"end":25,"href":"https:\u002F\u002Fweb.dev\u002Ftbt\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_39":{"__typename":"Paragraph","id":"5a62db7e743d_39","name":"2cbf","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Bundle size","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_40":{"__typename":"Paragraph","id":"5a62db7e743d_40","name":"1d63","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Update layout tree count and duration","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_41":{"__typename":"Paragraph","id":"5a62db7e743d_41","name":"d74b","type":"ULI","href":null,"layout":null,"metadata":null,"text":"Composite layers count and duration","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"MediaResource:8b77529c5df622792851c8c9884fb78f":{"__typename":"MediaResource","id":"8b77529c5df622792851c8c9884fb78f","iframeSrc":"","iframeHeight":0,"iframeWidth":0,"title":"Comparison of perf metrics of various libraries"},"Paragraph:5a62db7e743d_42":{"__typename":"Paragraph","id":"5a62db7e743d_42","name":"0ed5","type":"IFRAME","href":null,"layout":"INSET_CENTER","metadata":null,"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":{"__typename":"Iframe","mediaResource":{"__ref":"MediaResource:8b77529c5df622792851c8c9884fb78f"}},"mixtapeMetadata":null},"Paragraph:5a62db7e743d_43":{"__typename":"Paragraph","id":"5a62db7e743d_43","name":"cf54","type":"P","href":null,"layout":null,"metadata":null,"text":"It is clear that the frameworks are divided into two groups: runtime frameworks (react-with-styles, Emotion) and build-time frameworks (Linaria, Treat).","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":61,"end":79,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":113,"end":134,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_44":{"__typename":"Paragraph","id":"5a62db7e743d_44","name":"074d","type":"P","href":null,"layout":null,"metadata":null,"text":"Benchmarks of the server-rendered and client-hydrated version of our homepage showed Treat and Linaria performing 36% and 22% better than Emotion on Total Blocking Time, respectively. All frameworks performed significantly better than react-with-styles, ranging from a 32–56% improvement. (Note that these numbers should not be used to estimate expected improvements in production, as this is a very specific benchmark designed to test differences between frameworks, not expected savings in production.)","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":149,"end":168,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"EM","start":289,"end":504,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_45":{"__typename":"Paragraph","id":"5a62db7e743d_45","name":"62ed","type":"P","href":null,"layout":null,"metadata":null,"text":"Bundle size differences also fall into these two categories — with savings on the order of 80 KiB (~12%) for the Linaria\u002FTreat group.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":0,"end":11,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_46":{"__typename":"Paragraph","id":"5a62db7e743d_46","name":"15ba","type":"P","href":null,"layout":null,"metadata":null,"text":"The CSS metrics (update layout tree and composite layers) show that, on average, there is roughly one more layout tree update and layer composition event for react-with-styles\u002FEmotion. This is likely due to the insertion and hydration of stylesheets with JavaScript that is not necessary with a CSS extraction library like Linaria or Treat.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":17,"end":35,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":40,"end":56,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_47":{"__typename":"Paragraph","id":"5a62db7e743d_47","name":"eafb","type":"P","href":null,"layout":null,"metadata":null,"text":"This performance investigation shows that either Linaria or Treat would be promising options to adopt, and that all frameworks considered are a statistically significant improvement over react-with-styles with Aphrodite.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_48":{"__typename":"Paragraph","id":"5a62db7e743d_48","name":"41a8","type":"H3","href":null,"layout":null,"metadata":null,"text":"What We Liked About Linaria","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_49":{"__typename":"Paragraph","id":"5a62db7e743d_49","name":"0c96","type":"P","href":null,"layout":null,"metadata":null,"text":"The above performance improvements were largely thanks to Linaria extracting the styles from JS to static CSS files at build time, so there is no JS bundle or runtime CPU overhead — giving it a slight edge over the near-zero runtime Treat. Also, this brings caching benefits since these static CSS files may change at a different cadence than the JS files. Since the styles are extracted at build time, Linaria has the opportunity to automatically remove unused styles — this also opens the door to the possibility of deduplicating styles (i.e. Atomic CSS). Additionally, Linaria supports injecting the critical CSS for server-side rendering, which we had wanted to preserve from our react-with-styles integration.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":545,"end":555,"href":"https:\u002F\u002Fcss-tricks.com\u002Flets-define-exactly-atomic-css\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":10,"end":21,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_50":{"__typename":"Paragraph","id":"5a62db7e743d_50","name":"8fc0","type":"P","href":null,"layout":null,"metadata":null,"text":"Linaria also seemed to be a healthy project that saw a good amount of activity, community involvement, documentation, and adoption. Its good trajectory gave us confidence that it would continue to improve and that we would be able to contribute back.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":0,"end":43,"href":"https:\u002F\u002Fsnyk.io\u002Fadvisor\u002Fnpm-package\u002Flinaria","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":80,"end":89,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_51":{"__typename":"Paragraph","id":"5a62db7e743d_51","name":"f5f4","type":"P","href":null,"layout":null,"metadata":null,"text":"We found Linaria’s tagged template literal API that enables developers to use CSS syntax to be an attractive improvement over the JS object HOC API that we built for react-with-styles. Additionally, off-the-shelf integrations were available for stylelint, CSS autocompletion, and syntax highlighting, which enriched the developer experience.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":19,"end":42,"href":"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FTemplate_literals#tagged_templates","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":320,"end":340,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"ImageMetadata:0*hyXFKX-bB-ixvHsE":{"__typename":"ImageMetadata","id":"0*hyXFKX-bB-ixvHsE","originalHeight":655,"originalWidth":1600,"focusPercentX":null,"focusPercentY":null,"alt":null},"Paragraph:5a62db7e743d_52":{"__typename":"Paragraph","id":"5a62db7e743d_52","name":"096f","type":"IMG","href":null,"layout":"INSET_CENTER","metadata":{"__ref":"ImageMetadata:0*hyXFKX-bB-ixvHsE"},"text":"Off-the-shelf integrations for stylelint, CSS autocompletion, and syntax highlighting working with Linaria in action.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_53":{"__typename":"Paragraph","id":"5a62db7e743d_53","name":"0c17","type":"P","href":null,"layout":null,"metadata":null,"text":"We also found value in the similarities between Linaria and our existing solution. The co-location of styles within the component file was a big feature that tipped the scales in favor of Linaria over Treat for us, and the familiar API smoothed the transition for developers and gave us confidence that migration efforts could be eased with automation.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_54":{"__typename":"Paragraph","id":"5a62db7e743d_54","name":"e110","type":"H3","href":null,"layout":null,"metadata":null,"text":"Migration Strategy","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_55":{"__typename":"Paragraph","id":"5a62db7e743d_55","name":"32b2","type":"P","href":null,"layout":null,"metadata":null,"text":"To roll out this big change, we adopted an incremental migration strategy that is largely automated by codemods we’ve written. We are leaning heavily on our Happo screenshot tests to ensure that our components look the same after they are migrated. This allows sections of our codebase to be migrated by running a script and following up with any necessary tweaks, similar to the approach we took when adopting TypeScript.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":103,"end":111,"href":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fturbocharged-javascript-refactoring-with-codemods-b0cae8b326b9","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":157,"end":179,"href":"https:\u002F\u002Fhappo.io\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":376,"end":421,"href":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fts-migrate-a-tool-for-migrating-to-typescript-at-scale-cd23bfeb5cc","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_56":{"__typename":"Paragraph","id":"5a62db7e743d_56","name":"bb4f","type":"P","href":null,"layout":null,"metadata":null,"text":"The first phase of the migration was handled by the web styling working group and targeted converting a subset of components on a few select pages with varying performance characteristics. This phase was gated on A\u002FB tests which ensured that our initial understanding of the performance held up under the specifics of our app and assured us that there were no hidden problems.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_57":{"__typename":"Paragraph","id":"5a62db7e743d_57","name":"d71f","type":"P","href":null,"layout":null,"metadata":null,"text":"Once we were confident about the performance and correctness of our Linaria integration, we allowed teams to start using Linaria in new code. We also encouraged teams to migrate their existing code using our codemods. Although the migration has proceeded at a good pace organically, we plan to ensure that all code has moved off of react-with-styles so that we can eventually remove the runtime dependencies from the bundles entirely. This consistency will give us an additional performance boost and reduce the cost of decision fatigue.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":520,"end":536,"href":"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FDecision_fatigue","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_58":{"__typename":"Paragraph","id":"5a62db7e743d_58","name":"dd3b","type":"H3","href":null,"layout":null,"metadata":null,"text":"Contributing Back","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_59":{"__typename":"Paragraph","id":"5a62db7e743d_59","name":"21d1","type":"P","href":null,"layout":null,"metadata":null,"text":"Once we started using Linaria, we discovered that automatic style deduplication (i.e. Atomic CSS) would give us not just a performance boost, but also would fix some non-performance-related hiccups we ran into.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_60":{"__typename":"Paragraph","id":"5a62db7e743d_60","name":"ad78","type":"P","href":null,"layout":null,"metadata":null,"text":"The selectors that Linaria generates are all of the same specificity. Since CSS selectors of the same specificity depend on their declaration order, the order that the bundler builds these files becomes important. This is problematic when sharing styles between files, since we cannot predict or maintain the order of the styles as the shape of the dependency graph changes.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":57,"end":68,"href":"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FCSS\u002FSpecificity","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_61":{"__typename":"Paragraph","id":"5a62db7e743d_61","name":"f5c8","type":"P","href":null,"layout":null,"metadata":null,"text":"We initially approached this problem by creating a new tagged template literal for CSS fragments which allows for the styles to be interpolated into Linaria’s CSS tagged template literals. This works okay, but it is unintuitive, defeats tooling that expects styles to be defined in CSS tagged template literals, and leads to the styles being included several times in the CSS bundles (which is suboptimal for performance).","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":55,"end":78,"href":"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FJavaScript\u002FReference\u002FTemplate_literals#tagged_templates","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":237,"end":310,"href":"https:\u002F\u002Fgithub.com\u002Fprettier\u002Fprettier\u002Fblob\u002Fd13feed42b6478710bebbcd3225ab6f203a914c1\u002Fsrc\u002Flanguage-js\u002Fembed.js#L90-L121","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_62":{"__typename":"Paragraph","id":"5a62db7e743d_62","name":"8f7f","type":"P","href":null,"layout":null,"metadata":null,"text":"Josh Nelson, a member of our web styling working group, contributed Atomic CSS support back to Linaria and the Linaria community has been very supportive. The change adds a new @linaria\u002Fatomic package that when imported instead of @linaria\u002Fcore will generate Atomic CSS at build time. This means that if you write your code like this:","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":56,"end":102,"href":"https:\u002F\u002Fgithub.com\u002Fcallstack\u002Flinaria\u002Fpull\u002F867","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":177,"end":192,"href":"https:\u002F\u002Fnpmjs.com\u002F@linaria\u002Fatomic","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":231,"end":244,"href":"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@linaria\u002Fcore","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"MediaResource:3a3e079e4ec42de365e369ddcc9cfd77":{"__typename":"MediaResource","id":"3a3e079e4ec42de365e369ddcc9cfd77","iframeSrc":"","iframeHeight":0,"iframeWidth":0,"title":"linaria atomic example"},"Paragraph:5a62db7e743d_63":{"__typename":"Paragraph","id":"5a62db7e743d_63","name":"8ef0","type":"IFRAME","href":null,"layout":"INSET_CENTER","metadata":null,"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":{"__typename":"Iframe","mediaResource":{"__ref":"MediaResource:3a3e079e4ec42de365e369ddcc9cfd77"}},"mixtapeMetadata":null},"Paragraph:5a62db7e743d_64":{"__typename":"Paragraph","id":"5a62db7e743d_64","name":"eae7","type":"P","href":null,"layout":null,"metadata":null,"text":"Instead of generating output like this (without Atomic CSS):","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"MediaResource:520c2e335d3e36a2e93ad4d872342ea5":{"__typename":"MediaResource","id":"520c2e335d3e36a2e93ad4d872342ea5","iframeSrc":"","iframeHeight":0,"iframeWidth":0,"title":"linaria example output"},"Paragraph:5a62db7e743d_65":{"__typename":"Paragraph","id":"5a62db7e743d_65","name":"09ce","type":"IFRAME","href":null,"layout":"INSET_CENTER","metadata":null,"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":{"__typename":"Iframe","mediaResource":{"__ref":"MediaResource:520c2e335d3e36a2e93ad4d872342ea5"}},"mixtapeMetadata":null},"Paragraph:5a62db7e743d_66":{"__typename":"Paragraph","id":"5a62db7e743d_66","name":"2c93","type":"P","href":null,"layout":null,"metadata":null,"text":"The generated output will look something like this (with Atomic CSS):","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"MediaResource:f5126082ab3df8f6d84a5519635d0f96":{"__typename":"MediaResource","id":"f5126082ab3df8f6d84a5519635d0f96","iframeSrc":"","iframeHeight":0,"iframeWidth":0,"title":"linaria atomic example output"},"Paragraph:5a62db7e743d_67":{"__typename":"Paragraph","id":"5a62db7e743d_67","name":"4fe1","type":"IFRAME","href":null,"layout":"INSET_CENTER","metadata":null,"text":"","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":{"__typename":"Iframe","mediaResource":{"__ref":"MediaResource:f5126082ab3df8f6d84a5519635d0f96"}},"mixtapeMetadata":null},"Paragraph:5a62db7e743d_68":{"__typename":"Paragraph","id":"5a62db7e743d_68","name":"c27e","type":"P","href":null,"layout":null,"metadata":null,"text":"The order of appearance problem is solved by build time analysis that chains class names based on the order they are passed in to the cx function to increase specificity when necessary.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_69":{"__typename":"Paragraph","id":"5a62db7e743d_69","name":"e264","type":"H3","href":null,"layout":null,"metadata":null,"text":"Reception","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_70":{"__typename":"Paragraph","id":"5a62db7e743d_70","name":"b2a3","type":"P","href":null,"layout":null,"metadata":null,"text":"Our engineers have reacted positively to Linaria. Here are some quotes:","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_71":{"__typename":"Paragraph","id":"5a62db7e743d_71","name":"1587","type":"BQ","href":null,"layout":null,"metadata":null,"text":"“Linaria opens up a world where we can code like it’s 1999, in old school pure on CSS. It advises against bad patterns, but gives us the flexibility to build amazing experiences. We’re not fighting the platform anymore, we’re harnessing it and it feels incredibly powerful.” — Callie Riggins","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_72":{"__typename":"Paragraph","id":"5a62db7e743d_72","name":"2dad","type":"BQ","href":null,"layout":null,"metadata":null,"text":"“Compared to react-with-styles, I care more about what I’m creating now. Linaria is so good.” — Ian Demattei-Selby","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_73":{"__typename":"Paragraph","id":"5a62db7e743d_73","name":"0900","type":"BQ","href":null,"layout":null,"metadata":null,"text":"“I really liked being able to write CSS again. It gives you so much more control over what you can style in the component.” — Brie Bunge","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_74":{"__typename":"Paragraph","id":"5a62db7e743d_74","name":"7a37","type":"BQ","href":null,"layout":null,"metadata":null,"text":"“It’s great to be writing actual CSS again.” — Victor Lin","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_75":{"__typename":"Paragraph","id":"5a62db7e743d_75","name":"ad61","type":"P","href":null,"layout":null,"metadata":null,"text":"Thanks to its familiar CSS syntax, style extraction into static stylesheets, and application of styles using class names, Linaria increases product development speed and unlocks new styling capabilities not possible with react-with-styles and Aphrodite.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":130,"end":165,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":170,"end":252,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_76":{"__typename":"Paragraph","id":"5a62db7e743d_76","name":"44a5","type":"H3","href":null,"layout":null,"metadata":null,"text":"Performance Impact","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_77":{"__typename":"Paragraph","id":"5a62db7e743d_77","name":"1067","type":"P","href":null,"layout":null,"metadata":null,"text":"Though we are still at the beginning of our migration, we have run some A\u002FB tests that give us an encouraging look at the real world performance impact of switching to Linaria for a large group of visitors in the wild.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_78":{"__typename":"Paragraph","id":"5a62db7e743d_78","name":"456a","type":"P","href":null,"layout":null,"metadata":null,"text":"In one experiment, we converted about 10% of the components rendered on the airbnb.com homepage from react-with-styles to Linaria, and saw Homepage Page Performance Score improve by 0.26%. Time to First Contentful Paint (TTFCP) improved by 0.54% (mean of 790ms), while Total Blocking Time (TBT) also had a strong improvement of 1.6% (mean of 1200ms). To put this in perspective, hydrating the homepage with React takes around 200ms for most people, so improvements of this order of magnitude are significant. We believe these performance improvements with Linaria are attributable to no longer generating CSS styles at render-time, which improves render times on both server and client.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":148,"end":170,"href":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fcreating-airbnbs-page-performance-score-5f664be0936","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":189,"end":227,"href":"https:\u002F\u002Fweb.dev\u002Ffcp\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":269,"end":294,"href":"https:\u002F\u002Fweb.dev\u002Ftbt\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_79":{"__typename":"Paragraph","id":"5a62db7e743d_79","name":"8fcf","type":"P","href":null,"layout":null,"metadata":null,"text":"Assuming the performance improvements will scale linearly (which is a big assumption), converting the remaining 90% of the components might result in a 2.6% improvement to Page Performance Score, 5.4% improvement to Time to First Contentful Paint (TTFCP), and 16% improvement to Total Blocking Time (TBT).","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":134,"end":139,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_80":{"__typename":"Paragraph","id":"5a62db7e743d_80","name":"971a","type":"P","href":null,"layout":null,"metadata":null,"text":"Note that direct comparisons with other industry numbers are a little tricky here, given the different ways we define pages especially with regard to client routing.","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_81":{"__typename":"Paragraph","id":"5a62db7e743d_81","name":"8fd0","type":"H3","href":null,"layout":null,"metadata":null,"text":"What Does This Mean for react-with-styles?","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_82":{"__typename":"Paragraph","id":"5a62db7e743d_82","name":"449c","type":"P","href":null,"layout":null,"metadata":null,"text":"Given that we still have many components that still depend on react-with-styles and that it will take a while for us to complete our migration, we will put react-with-styles in maintenance mode until we approach the end of our migration. At that point, we intend to sunset react-with-styles and the related packages.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":144,"end":193,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":253,"end":290,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_83":{"__typename":"Paragraph","id":"5a62db7e743d_83","name":"feba","type":"P","href":null,"layout":null,"metadata":null,"text":"By removing an option from the marketplace we hope to help the community coalesce towards a common solution and invest in better frameworks. If you are looking for a new tool, we think Linaria is a great choice!","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_84":{"__typename":"Paragraph","id":"5a62db7e743d_84","name":"cea4","type":"H3","href":null,"layout":null,"metadata":null,"text":"Conclusion","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_85":{"__typename":"Paragraph","id":"5a62db7e743d_85","name":"98ef","type":"P","href":null,"layout":null,"metadata":null,"text":"Styling infrastructure is still an exciting space, rich with opportunities. At Airbnb, we’ve found big improvements to the developer experience by adopting a framework that allows regular CSS syntax to be used alongside our React component code. And by replacing a runtime styling library with one that compiles to static CSS files at build time, we are able to continue driving toward faster performance. Thanks to the Linaria community and our collaboration, we expect this library to continue to improve for many years.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"STRONG","start":123,"end":143,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":393,"end":404,"href":null,"anchorType":null,"userId":null,"linkMetadata":null},{"__typename":"Markup","type":"STRONG","start":428,"end":437,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_86":{"__typename":"Paragraph","id":"5a62db7e743d_86","name":"0d26","type":"P","href":null,"layout":null,"metadata":null,"text":"Interested in working at Airbnb? Check out these open roles:","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_87":{"__typename":"Paragraph","id":"5a62db7e743d_87","name":"4588","type":"P","href":null,"layout":null,"metadata":null,"text":"Frontend Infrastructure Engineer, Web Platform\nStaff Software Engineer, Data Governance \nStaff Software Engineer, Cloud Infrastructure \nStaff Database Engineer \nStaff Software Engineer — ML Ops Platform \nSenior\u002FStaff Software Engineer, Service Capabilities","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":0,"end":46,"href":"https:\u002F\u002Fgrnh.se\u002Febfa55151us","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":47,"end":88,"href":"https:\u002F\u002Fgrnh.se\u002Fb5afa9151us","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":89,"end":135,"href":"https:\u002F\u002Fgrnh.se\u002F92c32fed1us","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":136,"end":160,"href":"https:\u002F\u002Fgrnh.se\u002Fbbe55fe81us","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":161,"end":203,"href":"https:\u002F\u002Fgrnh.se\u002F21e5c2011us","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":204,"end":256,"href":"https:\u002F\u002Fgrnh.se\u002Fee114dfc1us","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_88":{"__typename":"Paragraph","id":"5a62db7e743d_88","name":"3e5b","type":"H3","href":null,"layout":null,"metadata":null,"text":"Acknowledgments","hasDropCap":null,"dropCapImage":null,"markups":[],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_89":{"__typename":"Paragraph","id":"5a62db7e743d_89","name":"2e09","type":"P","href":null,"layout":null,"metadata":null,"text":"We have a lot of appreciation for the folks at callstack and the Linaria community for building such a great tool and for collaborating with us to make it even better. Also for Khan Academy for giving us Aphrodite which served us well for many years. This has been a huge effort at Airbnb that would not have been possible without all the work put in by so many people at Airbnb, including Mars Jullian, Josh Nelson, Nora Tarano, Alan Wright, Jimmy Guo, Ian Demattei-Selby, Victor Lin, Nnenna John, Adrianne Soike, Garrett Berg, Andrew Huth, Austin Wood, Chris Sorenson, and Miles Johnson. Finally, thank you to Surashree Kulkarni for help editing this blog post. Thank you all!","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"A","start":47,"end":56,"href":"https:\u002F\u002Fwww.callstack.com\u002F","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":65,"end":82,"href":"https:\u002F\u002Fgithub.com\u002Fcallstack\u002Flinaria#contributors","anchorType":"LINK","userId":null,"linkMetadata":null},{"__typename":"Markup","type":"A","start":177,"end":189,"href":"https:\u002F\u002Fwww.khanacademy.org\u002F","anchorType":"LINK","userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"Paragraph:5a62db7e743d_90":{"__typename":"Paragraph","id":"5a62db7e743d_90","name":"d1bc","type":"P","href":null,"layout":null,"metadata":null,"text":"All product names, logos, and brands are property of their respective owners. All company, product and service names used in this website are for identification purposes only. Use of these names, logos, and brands does not imply endorsement.","hasDropCap":null,"dropCapImage":null,"markups":[{"__typename":"Markup","type":"EM","start":0,"end":241,"href":null,"anchorType":null,"userId":null,"linkMetadata":null}],"codeBlockMetadata":null,"iframe":null,"mixtapeMetadata":null},"CollectionViewerEdge:collectionId:53c7c27702d5-viewerId:lo_4d3df4fece5e":{"__typename":"CollectionViewerEdge","id":"collectionId:53c7c27702d5-viewerId:lo_4d3df4fece5e","isEditor":false,"isMuting":false},"ImageMetadata:1*JZl-TXoSiG0VmYn3qWLdTA.png":{"__typename":"ImageMetadata","id":"1*JZl-TXoSiG0VmYn3qWLdTA.png","originalWidth":280,"originalHeight":280},"PostViewerEdge:postId:dc169230bd12-viewerId:lo_4d3df4fece5e":{"__typename":"PostViewerEdge","shouldIndexPostForExternalSearch":true,"id":"postId:dc169230bd12-viewerId:lo_4d3df4fece5e"},"Tag:css":{"__typename":"Tag","id":"css","displayTitle":"CSS","normalizedTagSlug":"css"},"Tag:web-performance":{"__typename":"Tag","id":"web-performance","displayTitle":"Web Performance","normalizedTagSlug":"web-performance"},"Tag:css-in-js":{"__typename":"Tag","id":"css-in-js","displayTitle":"Css In Js","normalizedTagSlug":"css-in-js"},"Tag:atomic-css":{"__typename":"Tag","id":"atomic-css","displayTitle":"Atomic Css","normalizedTagSlug":"atomic-css"},"Tag:open-source":{"__typename":"Tag","id":"open-source","displayTitle":"Open Source","normalizedTagSlug":"open-source"},"Post:dc169230bd12":{"__typename":"Post","id":"dc169230bd12","collection":{"__ref":"Collection:53c7c27702d5"},"content({\"postMeteringOptions\":{}})":{"__typename":"PostContent","isLockedPreviewOnly":false,"bodyModel":{"__typename":"RichText","sections":[{"__typename":"Section","name":"a66f","startIndex":0,"textLayout":null,"imageLayout":null,"backgroundImage":null,"videoLayout":null,"backgroundVideo":null},{"__typename":"Section","name":"422d","startIndex":90,"textLayout":null,"imageLayout":null,"backgroundImage":null,"videoLayout":null,"backgroundVideo":null}],"paragraphs":[{"__ref":"Paragraph:5a62db7e743d_0"},{"__ref":"Paragraph:5a62db7e743d_1"},{"__ref":"Paragraph:5a62db7e743d_2"},{"__ref":"Paragraph:5a62db7e743d_3"},{"__ref":"Paragraph:5a62db7e743d_4"},{"__ref":"Paragraph:5a62db7e743d_5"},{"__ref":"Paragraph:5a62db7e743d_6"},{"__ref":"Paragraph:5a62db7e743d_7"},{"__ref":"Paragraph:5a62db7e743d_8"},{"__ref":"Paragraph:5a62db7e743d_9"},{"__ref":"Paragraph:5a62db7e743d_10"},{"__ref":"Paragraph:5a62db7e743d_11"},{"__ref":"Paragraph:5a62db7e743d_12"},{"__ref":"Paragraph:5a62db7e743d_13"},{"__ref":"Paragraph:5a62db7e743d_14"},{"__ref":"Paragraph:5a62db7e743d_15"},{"__ref":"Paragraph:5a62db7e743d_16"},{"__ref":"Paragraph:5a62db7e743d_17"},{"__ref":"Paragraph:5a62db7e743d_18"},{"__ref":"Paragraph:5a62db7e743d_19"},{"__ref":"Paragraph:5a62db7e743d_20"},{"__ref":"Paragraph:5a62db7e743d_21"},{"__ref":"Paragraph:5a62db7e743d_22"},{"__ref":"Paragraph:5a62db7e743d_23"},{"__ref":"Paragraph:5a62db7e743d_24"},{"__ref":"Paragraph:5a62db7e743d_25"},{"__ref":"Paragraph:5a62db7e743d_26"},{"__ref":"Paragraph:5a62db7e743d_27"},{"__ref":"Paragraph:5a62db7e743d_28"},{"__ref":"Paragraph:5a62db7e743d_29"},{"__ref":"Paragraph:5a62db7e743d_30"},{"__ref":"Paragraph:5a62db7e743d_31"},{"__ref":"Paragraph:5a62db7e743d_32"},{"__ref":"Paragraph:5a62db7e743d_33"},{"__ref":"Paragraph:5a62db7e743d_34"},{"__ref":"Paragraph:5a62db7e743d_35"},{"__ref":"Paragraph:5a62db7e743d_36"},{"__ref":"Paragraph:5a62db7e743d_37"},{"__ref":"Paragraph:5a62db7e743d_38"},{"__ref":"Paragraph:5a62db7e743d_39"},{"__ref":"Paragraph:5a62db7e743d_40"},{"__ref":"Paragraph:5a62db7e743d_41"},{"__ref":"Paragraph:5a62db7e743d_42"},{"__ref":"Paragraph:5a62db7e743d_43"},{"__ref":"Paragraph:5a62db7e743d_44"},{"__ref":"Paragraph:5a62db7e743d_45"},{"__ref":"Paragraph:5a62db7e743d_46"},{"__ref":"Paragraph:5a62db7e743d_47"},{"__ref":"Paragraph:5a62db7e743d_48"},{"__ref":"Paragraph:5a62db7e743d_49"},{"__ref":"Paragraph:5a62db7e743d_50"},{"__ref":"Paragraph:5a62db7e743d_51"},{"__ref":"Paragraph:5a62db7e743d_52"},{"__ref":"Paragraph:5a62db7e743d_53"},{"__ref":"Paragraph:5a62db7e743d_54"},{"__ref":"Paragraph:5a62db7e743d_55"},{"__ref":"Paragraph:5a62db7e743d_56"},{"__ref":"Paragraph:5a62db7e743d_57"},{"__ref":"Paragraph:5a62db7e743d_58"},{"__ref":"Paragraph:5a62db7e743d_59"},{"__ref":"Paragraph:5a62db7e743d_60"},{"__ref":"Paragraph:5a62db7e743d_61"},{"__ref":"Paragraph:5a62db7e743d_62"},{"__ref":"Paragraph:5a62db7e743d_63"},{"__ref":"Paragraph:5a62db7e743d_64"},{"__ref":"Paragraph:5a62db7e743d_65"},{"__ref":"Paragraph:5a62db7e743d_66"},{"__ref":"Paragraph:5a62db7e743d_67"},{"__ref":"Paragraph:5a62db7e743d_68"},{"__ref":"Paragraph:5a62db7e743d_69"},{"__ref":"Paragraph:5a62db7e743d_70"},{"__ref":"Paragraph:5a62db7e743d_71"},{"__ref":"Paragraph:5a62db7e743d_72"},{"__ref":"Paragraph:5a62db7e743d_73"},{"__ref":"Paragraph:5a62db7e743d_74"},{"__ref":"Paragraph:5a62db7e743d_75"},{"__ref":"Paragraph:5a62db7e743d_76"},{"__ref":"Paragraph:5a62db7e743d_77"},{"__ref":"Paragraph:5a62db7e743d_78"},{"__ref":"Paragraph:5a62db7e743d_79"},{"__ref":"Paragraph:5a62db7e743d_80"},{"__ref":"Paragraph:5a62db7e743d_81"},{"__ref":"Paragraph:5a62db7e743d_82"},{"__ref":"Paragraph:5a62db7e743d_83"},{"__ref":"Paragraph:5a62db7e743d_84"},{"__ref":"Paragraph:5a62db7e743d_85"},{"__ref":"Paragraph:5a62db7e743d_86"},{"__ref":"Paragraph:5a62db7e743d_87"},{"__ref":"Paragraph:5a62db7e743d_88"},{"__ref":"Paragraph:5a62db7e743d_89"},{"__ref":"Paragraph:5a62db7e743d_90"}]},"validatedShareKey":"","shareKeyCreator":null},"creator":{"__ref":"User:e52389684329"},"inResponseToEntityType":null,"isLocked":false,"isMarkedPaywallOnly":false,"lockedSource":"LOCKED_POST_SOURCE_NONE","mediumUrl":"https:\u002F\u002Fmedium.com\u002Fairbnb-engineering\u002Fairbnbs-trip-to-linaria-dc169230bd12","primaryTopic":{"__ref":"Topic:55f1c20aba7a"},"topics":[{"__typename":"Topic","slug":"software-engineering"},{"__typename":"Topic","slug":"javascript"},{"__typename":"Topic","slug":"programming"}],"isPublished":true,"latestPublishedVersion":"5a62db7e743d","visibility":"PUBLIC","postResponses":{"__typename":"PostResponses","count":6},"clapCount":512,"allowResponses":true,"isLimitedState":false,"title":"Airbnb’s Trip to Linaria","isSeries":false,"sequence":null,"uniqueSlug":"airbnbs-trip-to-linaria-dc169230bd12","socialTitle":"","socialDek":"","canonicalUrl":"","metaDescription":"","latestPublishedAt":1655401308753,"readingTime":10.300943396226415,"previewContent":{"__typename":"PreviewContent","subtitle":"Learn how Linaria, Airbnb’s newest choice for web styling, improved both developer experience and web performance"},"previewImage":{"__ref":"ImageMetadata:1*-qT4pQIPIsxHBZj22sQtag.jpeg"},"isShortform":false,"seoTitle":"Airbnb's Trip to Linaria","firstPublishedAt":1655401308753,"updatedAt":1655401470541,"shortformType":"SHORTFORM_TYPE_LINK","seoDescription":"How Linaria, Airbnb's newest choice for web styling, improved both developer experience and web performance","viewerEdge":{"__ref":"PostViewerEdge:postId:dc169230bd12-viewerId:lo_4d3df4fece5e"},"isSuspended":false,"license":"ALL_RIGHTS_RESERVED","tags":[{"__ref":"Tag:css"},{"__ref":"Tag:web-performance"},{"__ref":"Tag:css-in-js"},{"__ref":"Tag:atomic-css"},{"__ref":"Tag:open-source"}],"isNewsletter":false,"statusForCollection":"APPROVED","pendingCollection":null,"detectedLanguage":"en","wordCount":2584,"layerCake":3,"responsesLocked":false}}</script><script>window.__MIDDLEWARE_STATE__={"session":{"xsrf":""},"cache":{"cacheStatus":"HIT"}}</script><script src="https://cdn-client.medium.com/lite/static/js/manifest.aa9242f7.js"></script><script src="https://cdn-client.medium.com/lite/static/js/9865.1496d74a.js"></script><script src="https://cdn-client.medium.com/lite/static/js/main.e556b4ac.js"></script><script src="https://cdn-client.medium.com/lite/static/js/instrumentation.d9108df7.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/reporting.ff22a7a5.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/9120.5df29668.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5049.d1ead72d.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/4810.6318add7.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/6618.db187378.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2707.b0942613.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/9977.5b3eb23a.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8599.1ab63137.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5250.9f9e01d2.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5787.e66a3a4d.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2648.26563adf.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8393.826a25fb.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/3104.c3413b66.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/3735.afb7e926.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/5642.8ad8a900.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/6546.cd03f950.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/6834.08de95de.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/7346.72622eb9.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2420.2a5e2d95.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/839.ca7937c2.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/7975.d195c6f1.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2106.21ff89d3.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/7394.094844de.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/2961.00a48598.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/8204.c4082863.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/4391.59acaed3.chunk.js"></script> <script src="https://cdn-client.medium.com/lite/static/js/PostPage.MainContent.1387c5dc.chunk.js"></script><script>window.main();</script><script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'8e94c747fce79cbf',t:'MTczMjczODQwMy4wMDAwMDA='};var a=document.createElement('script');a.nonce='';a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body></html>