[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"sanity-yH3CxKrj_JrzxlAhkZDytemzx6yqh5crThX2Ob1Jefw":3,"sanity-bbrQlqRyKJaHXhJ7_polhsvesXwaVt3tIokIehzxoTc":607},{"data":4,"sourceMap":-1},{"latestPodcast":5,"latestReleases":14,"post":39,"recent":582},[6],{"_id":7,"publishedAt":8,"slug":9,"sponsored":12,"title":13},"d81860b7-7b72-4ba5-8ad5-3b77fd9a8e9b","2026-07-14T07:40:00.000Z",{"_type":10,"current":11},"slug","your-ai-is-only-as-responsible-as-you-are",null,"Your AI is only as responsible as you are",[15,21,27,33],{"_id":16,"publishedAt":17,"slug":18,"title":20},"eb5b66eb-9410-4329-83bb-22bbff39402a","2026-04-28T13:00:00.000Z",{"_type":10,"current":19},"turn-scattered-knowledge-into-trusted-intelligence","Turning scattered knowledge into trusted intelligence: Stack Internal 2026.3",{"_id":22,"publishedAt":23,"slug":24,"title":26},"369c2401-b62e-4a37-8ff8-bf603023ecad","2026-03-02T15:03:00.988Z",{"_type":10,"current":25},"what-s-new-at-stack-overflow-march-2026","What’s new at Stack Overflow: March 2026",{"_id":28,"publishedAt":29,"slug":30,"title":32},"5e9053a4-07ea-447c-91ea-29e0b6228537","2026-02-02T15:00:00.000Z",{"_type":10,"current":31},"what-s-new-at-stack-overflow-february-2026","What’s new at Stack Overflow: February 2026",{"_id":34,"publishedAt":35,"slug":36,"title":38},"a1b538eb-a8a6-46d0-80a1-ac70ec9bb935","2026-01-05T10:00:00.000-05:00",{"_type":10,"current":37},"what-s-new-at-stack-overflow-january-2026","What’s new at Stack Overflow: January 2026",{"_createdAt":40,"_id":41,"_rev":42,"_type":43,"_updatedAt":44,"author":45,"body":63,"comments":552,"dateUrl":553,"excerpt":554,"image":555,"legacyBody":558,"product":12,"publishedAt":561,"slug":562,"sponsored":12,"tags":564,"title":581,"visible":552},"2023-05-25T09:39:18Z","wp-post-18139","vvGEPqE7oenQZ7USMHRJxR","blogPost","2023-10-25T13:28:38Z",[46],{"_createdAt":47,"_id":48,"_rev":49,"_type":50,"_updatedAt":51,"avatar":52,"employee":57,"name":58,"role":59,"slug":60,"website":62},"2023-05-23T16:27:18Z","wp-author-274","1XHUBZ981q5C1ATiUYqY5H","blogAuthor","2023-10-25T13:29:29Z",{"_type":53,"asset":54},"image",{"_ref":55,"_type":56},"image-dda4e3fd5d11ea5a09a64ed62cb4f58301950810-1024x1024-jpg","reference","former","Aaron Shekey","Staff Product Designer, Design Systems",{"current":61},"ashekey","https:\u002F\u002Fwww.aaronshekey.com\u002F",[64,75,95,99,107,112,129,133,141,150,169,177,185,203,206,214,222,225,241,249,257,265,273,277,280,296,299,322,330,333,341,357,360,368,371,379,387,403,411,419,422,441,450,466,474,478,486,489,505,508,544],{"_key":65,"_type":66,"children":67,"markDefs":73,"style":74},"916677d6a336","block",[68],{"_key":69,"_type":70,"marks":71,"text":72},"916677d6a3360","span",[],"Quite often in our product, we’ll have celebratory popovers or modals. Congrats. You did the thing! Good job! You got the feature! Hooray!",[],"normal",{"_key":76,"_type":66,"children":77,"markDefs":91,"style":74},"0198d079d81b",[78,82,87],{"_key":79,"_type":70,"marks":80,"text":81},"0198d079d81b0",[],"Over on our design system ",{"_key":83,"_type":70,"marks":84,"text":86},"0198d079d81b1",[85],"a42dc2f79c0d","Stacks",{"_key":88,"_type":70,"marks":89,"text":90},"0198d079d81b2",[],", we recently shipped a reusable, portable way to display celebratory confetti.",[92],{"_key":85,"_type":93,"href":94,"reference":12},"link","https:\u002F\u002Fstackoverflow.design\u002F",{"_key":96,"_type":97,"markDefs":12,"url":98},"75639b86f091","embed","https:\u002F\u002Fcodepen.io\u002Faaronshekey\u002Fembed\u002FabJygGW",{"_key":100,"_type":66,"children":101,"markDefs":106,"style":74},"a65de1895f1d",[102],{"_key":103,"_type":70,"marks":104,"text":105},"a65de1895f1d0",[],"The first time we needed to show some confetti, we simply included a statically rendered SVG of confetti in the background, did our best to position it out of the way of the text, and moved on with our lives. It looked like this:",[],{"_key":108,"_type":53,"alt":12,"asset":109,"caption":111,"markDefs":12},"d2f54a36697b",{"_ref":110,"_type":56},"image-b33ac7467beef1962c976406ec7e2e3f0916fa36-1200x503-png","",{"_key":113,"_type":66,"children":114,"markDefs":128,"style":74},"4fc60643483b",[115,119,124],{"_key":116,"_type":70,"marks":117,"text":118},"4fc60643483b0",[],"Just mere months later, we found this same approach taken 12 times throughout our product. Each iteration was slightly different. Soon we had other variations like ",{"_key":120,"_type":70,"marks":121,"text":123},"4fc60643483b1",[122],"code","confetti-bold.svg",{"_key":125,"_type":70,"marks":126,"text":127},"4fc60643483b2",[],".",[],{"_key":130,"_type":53,"alt":12,"asset":131,"caption":111,"markDefs":12},"f7f5db6ae1a9",{"_ref":132,"_type":56},"image-1942e875baf395ed809dfa7cb52bbff6de67f338-730x630-png",{"_key":134,"_type":66,"children":135,"markDefs":140,"style":74},"7fed46ba2649",[136],{"_key":137,"_type":70,"marks":138,"text":139},"7fed46ba26490",[],"We ought to be consistent in our approach to confetti that’s reusable, portable, and perhaps most importantly, documented. Time to formalize!",[],{"_key":142,"_type":66,"children":143,"markDefs":148,"style":149},"4f1d4b38bb41",[144],{"_key":145,"_type":70,"marks":146,"text":147},"4f1d4b38bb410",[],"Prior art",[],"h2",{"_key":151,"_type":66,"children":152,"markDefs":166,"style":74},"81d4bc193665",[153,157,162],{"_key":154,"_type":70,"marks":155,"text":156},"81d4bc1936650",[],"As many Stack Overflow users know, the best way to get started is to ",{"_key":158,"_type":70,"marks":159,"text":161},"81d4bc1936651",[160],"24fb0be4545e","build off a good example",{"_key":163,"_type":70,"marks":164,"text":165},"81d4bc1936652",[],". Thankfully, there are lots of examples of confetti in products across the internet. Apps like Bamboo use it for anniversaries and birthdays. Carta uses confetti to celebrate exercising options.",[167],{"_key":160,"_type":93,"href":168,"reference":12},"https:\u002F\u002Fstackoverflow.blog\u002F2021\u002F04\u002F19\u002Fhow-often-do-people-actually-copy-and-paste-from-stack-overflow-now-we-know\u002F",{"_key":170,"_type":66,"children":171,"markDefs":176,"style":74},"d66a03fdff22",[172],{"_key":173,"_type":70,"marks":174,"text":175},"d66a03fdff220",[],"Some are rendering things in JavaScript, others as animated gifs. There are some that are rendering entire WebGL scenes in Three.JS.",[],{"_key":178,"_type":66,"children":179,"markDefs":184,"style":74},"b94dc2cf91fe",[180],{"_key":181,"_type":70,"marks":182,"text":183},"b94dc2cf91fe0",[],"For Stack Overflow, we’d need something as portable as possible and running as close to the native HTML & CSS as we can get. We didn’t want to introduce any dependencies here. We also don’t want to have to initialize some JS every time we want to show these. Relying on extra dependencies disqualified the approaches we saw across the web.",[],{"_key":186,"_type":66,"children":187,"markDefs":200,"style":74},"950403778661",[188,192,197],{"_key":189,"_type":70,"marks":190,"text":191},"9504037786610",[],"When digging around for solutions to common problems, oftentimes I’ll start at Codepen. This led me to ",{"_key":193,"_type":70,"marks":194,"text":196},"9504037786611",[195],"17579c8f5ccd","Andy O'Brien's Pen",{"_key":198,"_type":70,"marks":199,"text":127},"9504037786612",[],[201],{"_key":195,"_type":93,"href":202,"reference":12},"https:\u002F\u002Fcodepen.io\u002Fandyobrien\u002Fpen\u002FWYrxMe",{"_key":204,"_type":97,"markDefs":12,"url":205},"f763e315d884","https:\u002F\u002Fcodepen.io\u002Fandyobrien\u002Fembed\u002FWYrxMe",{"_key":207,"_type":66,"children":208,"markDefs":213,"style":74},"3ab91e619803",[209],{"_key":210,"_type":70,"marks":211,"text":212},"3ab91e6198030",[],"This approach is simple and elegant, and the animation loops! It uses Sass-generated CSS to animate individual DOM elements. It also looked very close to our designer Vivian Zhang’s latest iteration on confetti aesthetics.",[],{"_key":215,"_type":66,"children":216,"markDefs":221,"style":74},"c2d2f4b28065",[217],{"_key":218,"_type":70,"marks":219,"text":220},"c2d2f4b280650",[],"I forked the Codepen to start understanding the approach. I tweaked the colors and started messing with timing variables. Once I understood the approach, I finalized colors, and placed the confetti element within one of our modals.",[],{"_key":223,"_type":97,"markDefs":12,"url":224},"d66800ae677a","https:\u002F\u002Fcodepen.io\u002Faaronshekey\u002Fembed\u002FqBRZaPr",{"_key":226,"_type":66,"children":227,"markDefs":240,"style":74},"a3223003706b",[228,232,236],{"_key":229,"_type":70,"marks":230,"text":231},"a3223003706b0",[],"But this approach has some problems. In our various contexts, we don't quite have componentization at the scale we want it. This means our engineers would have to copy and paste a baker's dozen ",{"_key":233,"_type":70,"marks":234,"text":235},"a3223003706b1",[122],"confetti-piece",{"_key":237,"_type":70,"marks":238,"text":239},"a3223003706b2",[]," divs and make sure to manage the z-index and pointer events of the resulting confetti. This approach also uses absolute positioning and flexbox to distribute the confetti pieces throughout, meaning if you wanted to use it on a wide container, it’d stretch instead of tiling.",[],{"_key":242,"_type":66,"children":243,"markDefs":248,"style":74},"1b499f863357",[244],{"_key":245,"_type":70,"marks":246,"text":247},"1b499f8633570",[],"We sure liked the aesthetic though.",[],{"_key":250,"_type":66,"children":251,"markDefs":256,"style":74},"5e0a6aa6254e",[252],{"_key":253,"_type":70,"marks":254,"text":255},"5e0a6aa6254e0",[],"I bet instead of delivering as DOM elements, we could put all this inside an SVG and deliver as a background image, giving us way greater control over positioning, sizing, and repeating.",[],{"_key":258,"_type":66,"children":259,"markDefs":264,"style":149},"0eebd8ac956f",[260],{"_key":261,"_type":70,"marks":262,"text":263},"0eebd8ac956f0",[],"SVG Authoring",[],{"_key":266,"_type":66,"children":267,"markDefs":272,"style":74},"880cfcf0e72f",[268],{"_key":269,"_type":70,"marks":270,"text":271},"880cfcf0e72f0",[],"Ok, so SVG as a background image then? Let's give it a shot. First, I’d have to author an SVG element to house the confetti pieces. This is just a matter of distributing some rectangles on a canvas and picking some sizes we like. This is just replacing our DOM that we explored in previous Codepens for portability. I used Figma to draw this out as a time-saver, but this can all be written by hand. Here’s the final output:",[],{"_key":274,"_type":53,"alt":12,"asset":275,"caption":111,"markDefs":12},"ab33ca97adf3",{"_ref":276,"_type":56},"image-86d508e615fb0617d0ba4f0d391ccbb294bae35d-1200x180-png",{"_key":278,"_type":122,"code":279,"markDefs":12},"0c2eca36f849","\u003Csvg width=\"600\" height=\"90\" viewBox=\"0 0 600 90\" fill=\"none\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\">\n    \u003Crect x=\"42\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"84\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"126\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"168\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"210\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"252\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"294\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"336\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"378\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"420\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"462\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"504\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"546\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n\u003C\u002Fsvg>",{"_key":281,"_type":66,"children":282,"markDefs":295,"style":74},"ddf57d5fbc63",[283,287,291],{"_key":284,"_type":70,"marks":285,"text":286},"ddf57d5fbc630",[],"Now that I’ve got the SVG element, I can embed CSS into it and the browser will do its thing. Andy’s original approach was to color, rotate, and position various confetti elements using CSS’s ",{"_key":288,"_type":70,"marks":289,"text":290},"ddf57d5fbc631",[122],"nth-child",{"_key":292,"_type":70,"marks":293,"text":294},"ddf57d5fbc632",[]," selector. At first, my SVG was structured as such:",[],{"_key":297,"_type":122,"code":298,"markDefs":12},"afa47370dc0b","\u003Csvg>\n    \u003Cstyle type=\"text\u002Fcss\">...\u003C\u002Fstyle>\n    \u003Crect \u002F>\n\u003C\u002Fsvg>",{"_key":300,"_type":66,"children":301,"markDefs":321,"style":74},"0e05fdf97a33",[302,306,309,313,317],{"_key":303,"_type":70,"marks":304,"text":305},"0e05fdf97a330",[],"Oh! But now the CSS ",{"_key":307,"_type":70,"marks":308,"text":290},"0e05fdf97a331",[122],{"_key":310,"_type":70,"marks":311,"text":312},"0e05fdf97a332",[]," selectors are all off by one because the CSS is counting the ",{"_key":314,"_type":70,"marks":315,"text":316},"0e05fdf97a333",[122],"style",{"_key":318,"_type":70,"marks":319,"text":320},"0e05fdf97a334",[]," element as a child. I guess we'll move that to the bottom.",[],{"_key":323,"_type":66,"children":324,"markDefs":329,"style":74},"378ecb398b87",[325],{"_key":326,"_type":70,"marks":327,"text":328},"378ecb398b870",[],"Also, the Sass functions aren’t going to work within our SVG, so we’ll have to compile as CSS and paste it into our SVG. Codepen can handle the compilation for us, and I can copy and paste. This is getting a little weird! 😛",[],{"_key":331,"_type":122,"code":332,"markDefs":12},"641f36947658","\u003Csvg width=\"600\" height=\"90\" viewBox=\"0 0 600 90\" fill=\"none\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\">\n    \u003Crect x=\"42\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"84\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"126\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"168\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"210\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"252\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"294\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"336\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"378\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"420\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"462\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"504\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"546\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n\n    \u003Cstyle type=\"text\u002Fcss\">\n        rect {\n            opacity: 0;\n        }\n        rect:nth-child(1) {\n            transform: rotate(-145deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 88ms;\n            animation-duration: 631ms;\n        }\n        rect:nth-child(2) {\n            transform: rotate(164deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 442ms;\n        }\n        rect:nth-child(3) {\n            transform: rotate(4deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 92ms;\n            animation-duration: 662ms;\n        }\n        rect:nth-child(4) {\n            transform: rotate(-175deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 17ms;\n            animation-duration: 593ms;\n        }\n        rect:nth-child(5) {\n            transform: rotate(-97deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 122ms;\n            animation-duration: 476ms;\n        }\n        rect:nth-child(6) {\n            transform: rotate(57deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 271ms;\n            animation-duration: 381ms;\n        }\n        rect:nth-child(7) {\n            transform: rotate(-46deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 619ms;\n        }\n        rect:nth-child(8) {\n            transform: rotate(-65deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 85ms;\n            animation-duration: 668ms;\n        }\n        rect:nth-child(9) {\n            transform: rotate(13deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 128ms;\n            animation-duration: 377ms;\n        }\n        rect:nth-child(10) {\n            transform: rotate(176deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 311ms;\n            animation-duration: 508ms;\n        }\n        rect:nth-child(11) {\n            transform: rotate(108deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 108ms;\n            animation-duration: 595ms;\n        }\n        rect:nth-child(12) {\n            transform: rotate(62deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 105ms;\n            animation-duration: 375ms;\n        }\n        rect:nth-child(13) {\n            transform: rotate(16deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 149ms;\n            animation-duration: 491ms;\n        }\n        rect:nth-child(odd) {\n            fill: #65BB5C;\n        }\n        rect:nth-child(even) {\n            z-index: 1;\n            fill: #33AAFF;\n        }\n        rect:nth-child(4n) {\n            animation-duration: 1400ms;\n            fill: #F23B14;\n        }\n        rect:nth-child(3n) {\n            animation-duration: 1750ms;\n            animation-delay: 700ms;\n        }\n        rect:nth-child(4n-7) {\n            fill: #2A2F6A;\n        }\n        rect:nth-child(6n) {\n            fill: #FBBA23;\n        }\n\n        @keyframes blast {\n            from {\n                opacity: 0;\n            }\n            20% {\n                opacity: 1;\n            }\n            to {\n                transform: translateY(90px);\n            }\n        }\n    \u003C\u002Fstyle>\n\u003C\u002Fsvg>",{"_key":334,"_type":66,"children":335,"markDefs":340,"style":74},"013bda58e86e",[336],{"_key":337,"_type":70,"marks":338,"text":339},"013bda58e86e0",[],"Ok, wild! So if you save this as an SVG and open it in your browser, you’ll now see some animated confetti, but something is wrong about the positioning of our confetti pieces. When these were DOM elements, they just worked. Something must be different about SVG. If you guessed that SVG has different transform origins, you were correct. In the DOM, if you rotate something with CSS, it just rotates by default at the center of the element. In SVG the default origin is 0,0, meaning the very top left of our canvas 🤦‍♂️",[],{"_key":342,"_type":66,"children":343,"markDefs":356,"style":74},"ee7fa9aae0fc",[344,348,352],{"_key":345,"_type":70,"marks":346,"text":347},"ee7fa9aae0fc0",[],"I solved this by measuring the distances in Figma and hardcoding some transform origins, e.g. ",{"_key":349,"_type":70,"marks":350,"text":351},"ee7fa9aae0fc1",[122],"transform-origin: 45px 5px;",{"_key":353,"_type":70,"marks":354,"text":355},"ee7fa9aae0fc2",[]," These origins aren’t the perfect center of the rectangles, but they’re close enough.",[],{"_key":358,"_type":122,"code":359,"markDefs":12},"81e0aaea7f14","\u003Csvg width=\"600\" height=\"90\" viewBox=\"0 0 600 90\" fill=\"none\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\">\n    \u003Crect x=\"42\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"84\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"126\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"168\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"210\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"252\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"294\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"336\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"378\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"420\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"462\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n    \u003Crect x=\"504\" y=\"0\" width=\"5\" height=\"13\"\u002F>\n    \u003Crect x=\"546\" y=\"0\" width=\"6\" height=\"10\"\u002F>\n\n    \u003Cstyle type=\"text\u002Fcss\">\n        rect {\n            opacity: 0;\n        }\n        rect:nth-child(1) {\n            transform-origin: 45px 5px;\n            transform: rotate(-145deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 88ms;\n            animation-duration: 631ms;\n        }\n        rect:nth-child(2) {\n            transform-origin: 87px 5px;\n            transform: rotate(164deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 442ms;\n        }\n        rect:nth-child(3) {\n            transform-origin: 128px 6px;\n            transform: rotate(4deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 92ms;\n            animation-duration: 662ms;\n        }\n        rect:nth-child(4) {\n            transform-origin: 170px 6px;\n            transform: rotate(-175deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 17ms;\n            animation-duration: 593ms;\n        }\n        rect:nth-child(5) {\n            transform-origin: 213px 5px;\n            transform: rotate(-97deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 122ms;\n            animation-duration: 476ms;\n        }\n        rect:nth-child(6) {\n            transform-origin: 255px 6px;\n            transform: rotate(57deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 271ms;\n            animation-duration: 381ms;\n        }\n        rect:nth-child(7) {\n            transform-origin: 297px 5px;\n            transform: rotate(-46deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 619ms;\n        }\n        rect:nth-child(8) {\n            transform-origin: 338px 6px;\n            transform: rotate(-65deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 85ms;\n            animation-duration: 668ms;\n        }\n        rect:nth-child(9) {\n            transform-origin: 380px 6px;\n            transform: rotate(13deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 128ms;\n            animation-duration: 377ms;\n        }\n        rect:nth-child(10) {\n            transform-origin: 423px 5px;\n            transform: rotate(176deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 311ms;\n            animation-duration: 508ms;\n        }\n        rect:nth-child(11) {\n            transform-origin: 465px 5px;\n            transform: rotate(108deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 108ms;\n            animation-duration: 595ms;\n        }\n        rect:nth-child(12) {\n            transform-origin: 506px 6px;\n            transform: rotate(62deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 105ms;\n            animation-duration: 375ms;\n        }\n        rect:nth-child(13) {\n            transform-origin: 549px 5px;\n            transform: rotate(16deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 149ms;\n            animation-duration: 491ms;\n        }\n        rect:nth-child(odd) {\n            fill: #65BB5C;\n        }\n        rect:nth-child(even) {\n            z-index: 1;\n            fill: #33AAFF;\n        }\n        rect:nth-child(4n) {\n            animation-duration: 1400ms;\n            fill: #F23B14;\n        }\n        rect:nth-child(3n) {\n            animation-duration: 1750ms;\n            animation-delay: 700ms;\n        }\n        rect:nth-child(4n-7) {\n            fill: #2A2F6A;\n        }\n        rect:nth-child(6n) {\n            fill: #FBBA23;\n        }\n\n        @keyframes blast {\n            from {\n                opacity: 0;\n            }\n            20% {\n                opacity: 1;\n            }\n            to {\n                transform: translateY(90px);\n            }\n        }\n    \u003C\u002Fstyle>\n\u003C\u002Fsvg>\n",{"_key":361,"_type":66,"children":362,"markDefs":367,"style":74},"5339c7b23d32",[363],{"_key":364,"_type":70,"marks":365,"text":366},"5339c7b23d320",[],"Just one last bit of finesse. Because the origins are slightly different in SVG, I’m noticing that at the bottom, I’ve got some confetti pieces getting cut off at the end of their animation. We can solve this by jogging our pieces up and off the canvas.",[],{"_key":369,"_type":122,"code":370,"markDefs":12},"0094a0698fa1","\u003Crect x=\"42\" y=\"-10\" width=\"6\" height=\"10\"\u002F>\n\u003Crect x=\"84\" y=\"-10\" width=\"6\" height=\"10\"\u002F>\n\u003Crect x=\"126\" y=\"-13\" width=\"5\" height=\"13\"\u002F>\n\u003Crect x=\"168\" y=\"-13\" width=\"5\" height=\"13\"\u002F>\n\u003Crect x=\"210\" y=\"-10\" width=\"6\" height=\"10\"\u002F>\n\u003Crect x=\"252\" y=\"-13\" width=\"5\" height=\"13\"\u002F>\n\u003Crect x=\"294\" y=\"-10\" width=\"6\" height=\"10\"\u002F>\n\u003Crect x=\"336\" y=\"-13\" width=\"5\" height=\"13\"\u002F>\n\u003Crect x=\"378\" y=\"-13\" width=\"5\" height=\"13\"\u002F>\n\u003Crect x=\"420\" y=\"-10\" width=\"6\" height=\"10\"\u002F>\n\u003Crect x=\"462\" y=\"-10\" width=\"6\" height=\"10\"\u002F>\n\u003Crect x=\"504\" y=\"-13\" width=\"5\" height=\"13\"\u002F>\n\u003Crect x=\"546\" y=\"-10\" width=\"6\" height=\"10\"\u002F>",{"_key":372,"_type":66,"children":373,"markDefs":378,"style":149},"89597048c5b7",[374],{"_key":375,"_type":70,"marks":376,"text":377},"89597048c5b70",[],"Delivery",[],{"_key":380,"_type":66,"children":381,"markDefs":386,"style":74},"539c2a22a13b",[382],{"_key":383,"_type":70,"marks":384,"text":385},"539c2a22a13b0",[],"Great! We’ve got a single SVG file that now handles all the animation, and we now place it as a background image on any element we want. We like our animation timing, colors, and sizing too.",[],{"_key":388,"_type":66,"children":389,"markDefs":402,"style":74},"37137ed9228f",[390,394,398],{"_key":391,"_type":70,"marks":392,"text":393},"37137ed9228f0",[],"We could stop right here and make sure that each project has this ",{"_key":395,"_type":70,"marks":396,"text":397},"37137ed9228f1",[122],".svg",{"_key":399,"_type":70,"marks":400,"text":401},"37137ed9228f2",[]," file somewhere on the file system...",[],{"_key":404,"_type":66,"children":405,"markDefs":410,"style":74},"29a774a03e3d",[406],{"_key":407,"_type":70,"marks":408,"text":409},"29a774a03e3d0",[],"OR we could further encapsulate by encoding this entire SVG (with CSS) in our design system’s CSS file. CSS in SVG in CSS? Why not? 🤯",[],{"_key":412,"_type":66,"children":413,"markDefs":418,"style":74},"5fd36e68dbfb",[414],{"_key":415,"_type":70,"marks":416,"text":417},"5fd36e68dbfb0",[],"This is as simple as encoding the SVG as a background image like so:",[],{"_key":420,"_type":122,"code":421,"markDefs":12},"d64cba04a4d4",".bg-confetti-animated {\n    background-repeat: repeat-x;\n    background-position: top -10px center;\n    background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='600' height='90' viewBox='0 0 600 90' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect x='42' y='-10' width='6' height='10'\u002F%3E%3Crect x='84' y='-10' width='6' height='10'\u002F%3E%3Crect x='126' y='-13' width='5' height='13'\u002F%3E%3Crect x='168' y='-13' width='5' height='13'\u002F%3E%3Crect x='210' y='-10' width='6' height='10'\u002F%3E%3Crect x='252' y='-13' width='5' height='13'\u002F%3E%3Crect x='294' y='-10' width='6' height='10'\u002F%3E%3Crect x='336' y='-13' width='5' height='13'\u002F%3E%3Crect x='378' y='-13' width='5' height='13'\u002F%3E%3Crect x='420' y='-10' width='6' height='10'\u002F%3E%3Crect x='462' y='-10' width='6' height='10'\u002F%3E%3Crect x='504' y='-13' width='5' height='13'\u002F%3E%3Crect x='546' y='-10' width='6' height='10'\u002F%3E%3Cstyle type='text\u002Fcss'%3E rect %7B opacity: 0; %7D rect:nth-child(1) %7B transform-origin: 45px 5px; transform: rotate(-145deg); animation: blast 700ms infinite ease-out; animation-delay: 88ms; animation-duration: 631ms; %7D rect:nth-child(2) %7B transform-origin: 87px 5px; transform: rotate(164deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 442ms; %7D rect:nth-child(3) %7B transform-origin: 128px 6px; transform: rotate(4deg); animation: blast 700ms infinite ease-out; animation-delay: 92ms; animation-duration: 662ms; %7D rect:nth-child(4) %7B transform-origin: 170px 6px; transform: rotate(-175deg); animation: blast 700ms infinite ease-out; animation-delay: 17ms; animation-duration: 593ms; %7D rect:nth-child(5) %7B transform-origin: 213px 5px; transform: rotate(-97deg); animation: blast 700ms infinite ease-out; animation-delay: 122ms; animation-duration: 476ms; %7D rect:nth-child(6) %7B transform-origin: 255px 6px; transform: rotate(57deg); animation: blast 700ms infinite ease-out; animation-delay: 271ms; animation-duration: 381ms; %7D rect:nth-child(7) %7B transform-origin: 297px 5px; transform: rotate(-46deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 619ms; %7D rect:nth-child(8) %7B transform-origin: 338px 6px; transform: rotate(-65deg); animation: blast 700ms infinite ease-out; animation-delay: 85ms; animation-duration: 668ms; %7D rect:nth-child(9) %7B transform-origin: 380px 6px; transform: rotate(13deg); animation: blast 700ms infinite ease-out; animation-delay: 128ms; animation-duration: 377ms; %7D rect:nth-child(10) %7B transform-origin: 423px 5px; transform: rotate(176deg); animation: blast 700ms infinite ease-out; animation-delay: 311ms; animation-duration: 508ms; %7D rect:nth-child(11) %7B transform-origin: 465px 5px; transform: rotate(108deg); animation: blast 700ms infinite ease-out; animation-delay: 108ms; animation-duration: 595ms; %7D rect:nth-child(12) %7B transform-origin: 506px 6px; transform: rotate(62deg); animation: blast 700ms infinite ease-out; animation-delay: 105ms; animation-duration: 375ms; %7D rect:nth-child(13) %7B transform-origin: 549px 5px; transform: rotate(16deg); animation: blast 700ms infinite ease-out; animation-delay: 149ms; animation-duration: 491ms; %7D rect:nth-child(odd) %7B fill: %2365BB5C; %7D rect:nth-child(even) %7B z-index: 1; fill: %2333AAFF; %7D rect:nth-child(4n) %7B animation-duration: 1400ms; fill: %23F23B14; %7D rect:nth-child(3n) %7B animation-duration: 1750ms; animation-delay: 700ms; %7D rect:nth-child(4n-7) %7B fill: %232A2F6A; %7D rect:nth-child(6n) %7B fill: %23FBBA23; %7D @keyframes blast %7B from %7B opacity: 0; %7D 20%25 %7B opacity: 1; %7D to %7B transform: translateY(90px); %7D %7D %3C\u002Fstyle%3E%3C\u002Fsvg%3E%0A\");\n}",{"_key":423,"_type":66,"children":424,"markDefs":438,"style":74},"0a3040826d9a",[425,429,434],{"_key":426,"_type":70,"marks":427,"text":428},"0a3040826d9a0",[],"I use ",{"_key":430,"_type":70,"marks":431,"text":433},"0a3040826d9a1",[432],"f53be25d47fe","yoksel's tool",{"_key":435,"_type":70,"marks":436,"text":437},"0a3040826d9a2",[]," whenever I have to encode something like this.",[439],{"_key":432,"_type":93,"href":440,"reference":12},"https:\u002F\u002Fyoksel.github.io\u002Furl-encoder\u002F",{"_key":442,"_type":66,"children":443,"markDefs":448,"style":449},"912b6161bf94",[444],{"_key":445,"_type":70,"marks":446,"text":447},"912b6161bf940",[],"Supporting reduced motion",[],"h3",{"_key":451,"_type":66,"children":452,"markDefs":465,"style":74},"c8e0deb0b0f6",[453,457,461],{"_key":454,"_type":70,"marks":455,"text":456},"c8e0deb0b0f60",[],"Some folks have a hard time with animation. Others simply prefer not seeing it at all. Thankfully, our browsers offer a media query for this ",{"_key":458,"_type":70,"marks":459,"text":460},"c8e0deb0b0f61",[122],"@media (prefers-reduced-motion)",{"_key":462,"_type":70,"marks":463,"text":464},"c8e0deb0b0f62",[],". Let’s use it to show a statically-rendered bit of confetti, which is actually the original organic ad-hoc approach we took.",[],{"_key":467,"_type":66,"children":468,"markDefs":473,"style":74},"8bb51edf9c01",[469],{"_key":470,"_type":70,"marks":471,"text":472},"8bb51edf9c010",[],"Vivian was kind enough to draw up a static version of the confetti in Figma.",[],{"_key":475,"_type":53,"alt":12,"asset":476,"caption":111,"markDefs":12},"f66aeafeef75",{"_ref":477,"_type":56},"image-f7b87a0211c431428b3c765ddf2624d88d975eb4-1148x120-png",{"_key":479,"_type":66,"children":480,"markDefs":485,"style":74},"f7c825f2f65b",[481],{"_key":482,"_type":70,"marks":483,"text":484},"f7c825f2f65b0",[],"Now it’s just a matter of embedding the static version behind that media query:",[],{"_key":487,"_type":122,"code":488,"markDefs":12},"04893097d1f0",".bg-confetti-animated {\n    background-repeat: repeat-x;\n    background-position: top -10px center;\n    background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='600' height='90' viewBox='0 0 600 90' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect x='42' y='-10' width='6' height='10'\u002F%3E%3Crect x='84' y='-10' width='6' height='10'\u002F%3E%3Crect x='126' y='-13' width='5' height='13'\u002F%3E%3Crect x='168' y='-13' width='5' height='13'\u002F%3E%3Crect x='210' y='-10' width='6' height='10'\u002F%3E%3Crect x='252' y='-13' width='5' height='13'\u002F%3E%3Crect x='294' y='-10' width='6' height='10'\u002F%3E%3Crect x='336' y='-13' width='5' height='13'\u002F%3E%3Crect x='378' y='-13' width='5' height='13'\u002F%3E%3Crect x='420' y='-10' width='6' height='10'\u002F%3E%3Crect x='462' y='-10' width='6' height='10'\u002F%3E%3Crect x='504' y='-13' width='5' height='13'\u002F%3E%3Crect x='546' y='-10' width='6' height='10'\u002F%3E%3Cstyle type='text\u002Fcss'%3E rect %7B opacity: 0; %7D rect:nth-child(1) %7B transform-origin: 45px 5px; transform: rotate(-145deg); animation: blast 700ms infinite ease-out; animation-delay: 88ms; animation-duration: 631ms; %7D rect:nth-child(2) %7B transform-origin: 87px 5px; transform: rotate(164deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 442ms; %7D rect:nth-child(3) %7B transform-origin: 128px 6px; transform: rotate(4deg); animation: blast 700ms infinite ease-out; animation-delay: 92ms; animation-duration: 662ms; %7D rect:nth-child(4) %7B transform-origin: 170px 6px; transform: rotate(-175deg); animation: blast 700ms infinite ease-out; animation-delay: 17ms; animation-duration: 593ms; %7D rect:nth-child(5) %7B transform-origin: 213px 5px; transform: rotate(-97deg); animation: blast 700ms infinite ease-out; animation-delay: 122ms; animation-duration: 476ms; %7D rect:nth-child(6) %7B transform-origin: 255px 6px; transform: rotate(57deg); animation: blast 700ms infinite ease-out; animation-delay: 271ms; animation-duration: 381ms; %7D rect:nth-child(7) %7B transform-origin: 297px 5px; transform: rotate(-46deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 619ms; %7D rect:nth-child(8) %7B transform-origin: 338px 6px; transform: rotate(-65deg); animation: blast 700ms infinite ease-out; animation-delay: 85ms; animation-duration: 668ms; %7D rect:nth-child(9) %7B transform-origin: 380px 6px; transform: rotate(13deg); animation: blast 700ms infinite ease-out; animation-delay: 128ms; animation-duration: 377ms; %7D rect:nth-child(10) %7B transform-origin: 423px 5px; transform: rotate(176deg); animation: blast 700ms infinite ease-out; animation-delay: 311ms; animation-duration: 508ms; %7D rect:nth-child(11) %7B transform-origin: 465px 5px; transform: rotate(108deg); animation: blast 700ms infinite ease-out; animation-delay: 108ms; animation-duration: 595ms; %7D rect:nth-child(12) %7B transform-origin: 506px 6px; transform: rotate(62deg); animation: blast 700ms infinite ease-out; animation-delay: 105ms; animation-duration: 375ms; %7D rect:nth-child(13) %7B transform-origin: 549px 5px; transform: rotate(16deg); animation: blast 700ms infinite ease-out; animation-delay: 149ms; animation-duration: 491ms; %7D rect:nth-child(odd) %7B fill: %2365BB5C; %7D rect:nth-child(even) %7B z-index: 1; fill: %2333AAFF; %7D rect:nth-child(4n) %7B animation-duration: 1400ms; fill: %23F23B14; %7D rect:nth-child(3n) %7B animation-duration: 1750ms; animation-delay: 700ms; %7D rect:nth-child(4n-7) %7B fill: %232A2F6A; %7D rect:nth-child(6n) %7B fill: %23FBBA23; %7D @keyframes blast %7B from %7B opacity: 0; %7D 20%25 %7B opacity: 1; %7D to %7B transform: translateY(90px); %7D %7D %3C\u002Fstyle%3E%3C\u002Fsvg%3E%0A\");\n\n    @media (prefers-reduced-motion) {\n        background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='574' height='60' viewBox='0 0 574 60' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect opacity='0.8' x='27.1224' y='20.0458' width='5' height='13' transform='rotate(-139 27.1224 20.0458)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='118.478' y='7.00201' width='5' height='13' transform='rotate(-38.8114 118.478 7.00201)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='504.616' y='25.4479' width='5' height='13' transform='rotate(-60.2734 504.616 25.4479)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='538.983' y='45.555' width='5' height='13' transform='rotate(16.7826 538.983 45.555)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.3' x='470.322' y='2.63625' width='5' height='13' transform='rotate(11.295 470.322 2.63625)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='190.295' y='4.58138' width='5' height='13' transform='rotate(27.5954 190.295 4.58138)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='234.303' y='16.3233' width='5' height='13' transform='rotate(-41.8233 234.303 16.3233)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='369.702' y='40.9875' width='5' height='13' transform='rotate(-56.419 369.702 40.9875)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='402.121' y='31.0848' width='5' height='13' transform='rotate(-17.9234 402.121 31.0848)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='200.316' y='31.9328' width='5' height='13' transform='rotate(-15.8896 200.316 31.9328)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.6' x='69.6745' y='23.4725' width='6' height='10' transform='rotate(70.0266 69.6745 23.4725)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='291.945' y='7.16931' width='6' height='10' transform='rotate(30.4258 291.945 7.16931)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='33.7754' y='38.2208' width='6' height='10' transform='rotate(38.6056 33.7754 38.2208)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='109.752' y='31.1743' width='6' height='10' transform='rotate(28.5296 109.752 31.1743)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='278.081' y='37.8695' width='6' height='10' transform='rotate(-26.5651 278.081 37.8695)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='416.294' y='11.5573' width='6' height='10' transform='rotate(-22.8498 416.294 11.5573)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='354.667' y='9.32341' width='6' height='10' transform='rotate(17.7506 354.667 9.32341)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.8' x='532.404' y='16.6372' width='6' height='10' transform='rotate(-75.3432 532.404 16.6372)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.6' x='460.463' y='39.3557' width='6' height='10' transform='rotate(45.4982 460.463 39.3557)' fill='%2365BB5C'\u002F%3E%3C\u002Fsvg%3E\");\n    }\n}",{"_key":490,"_type":66,"children":491,"markDefs":504,"style":74},"7ae3e02f246a",[492,496,500],{"_key":493,"_type":70,"marks":494,"text":495},"7ae3e02f246a0",[],"We can also provide this as a separate class with ",{"_key":497,"_type":70,"marks":498,"text":499},"7ae3e02f246a1",[122],".bg-confetti-static",{"_key":501,"_type":70,"marks":502,"text":503},"7ae3e02f246a2",[],":",[],{"_key":506,"_type":122,"code":507,"markDefs":12},"7a1b35a0a87f",".bg-confetti-static {\n    background-repeat: repeat-x;\n    background-position: top -10px center;\n    background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='574' height='60' viewBox='0 0 574 60' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect opacity='0.8' x='27.1224' y='20.0458' width='5' height='13' transform='rotate(-139 27.1224 20.0458)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='118.478' y='7.00201' width='5' height='13' transform='rotate(-38.8114 118.478 7.00201)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='504.616' y='25.4479' width='5' height='13' transform='rotate(-60.2734 504.616 25.4479)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='538.983' y='45.555' width='5' height='13' transform='rotate(16.7826 538.983 45.555)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.3' x='470.322' y='2.63625' width='5' height='13' transform='rotate(11.295 470.322 2.63625)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='190.295' y='4.58138' width='5' height='13' transform='rotate(27.5954 190.295 4.58138)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='234.303' y='16.3233' width='5' height='13' transform='rotate(-41.8233 234.303 16.3233)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='369.702' y='40.9875' width='5' height='13' transform='rotate(-56.419 369.702 40.9875)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='402.121' y='31.0848' width='5' height='13' transform='rotate(-17.9234 402.121 31.0848)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='200.316' y='31.9328' width='5' height='13' transform='rotate(-15.8896 200.316 31.9328)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.6' x='69.6745' y='23.4725' width='6' height='10' transform='rotate(70.0266 69.6745 23.4725)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='291.945' y='7.16931' width='6' height='10' transform='rotate(30.4258 291.945 7.16931)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='33.7754' y='38.2208' width='6' height='10' transform='rotate(38.6056 33.7754 38.2208)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='109.752' y='31.1743' width='6' height='10' transform='rotate(28.5296 109.752 31.1743)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='278.081' y='37.8695' width='6' height='10' transform='rotate(-26.5651 278.081 37.8695)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='416.294' y='11.5573' width='6' height='10' transform='rotate(-22.8498 416.294 11.5573)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='354.667' y='9.32341' width='6' height='10' transform='rotate(17.7506 354.667 9.32341)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.8' x='532.404' y='16.6372' width='6' height='10' transform='rotate(-75.3432 532.404 16.6372)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.6' x='460.463' y='39.3557' width='6' height='10' transform='rotate(45.4982 460.463 39.3557)' fill='%2365BB5C'\u002F%3E%3C\u002Fsvg%3E\");\n}",{"_key":509,"_type":66,"children":510,"markDefs":539,"style":74},"c73356872280",[511,515,519,523,527,531,536],{"_key":512,"_type":70,"marks":513,"text":514},"c733568722800",[],"That wraps it up! Now our engineers and designers have a single, portable class of ",{"_key":516,"_type":70,"marks":517,"text":518},"c733568722801",[122],".bg-confetti-animated",{"_key":520,"_type":70,"marks":521,"text":522},"c733568722802",[]," that they can add to any block level element. You can see the further documentation on our design system, ",{"_key":524,"_type":70,"marks":525,"text":86},"c733568722803",[526],"a41eb9ca0f1a",{"_key":528,"_type":70,"marks":529,"text":530},"c733568722804",[],", and how we extended it to ",{"_key":532,"_type":70,"marks":533,"text":535},"c733568722805",[534],"24264038bfc7","modal styling",{"_key":537,"_type":70,"marks":538,"text":127},"c733568722806",[],[540,542],{"_key":526,"_type":93,"href":541,"reference":12},"https:\u002F\u002Fstackoverflow.design\u002Fproduct\u002Fbase\u002Fbackgrounds\u002F#confetti",{"_key":534,"_type":93,"href":543,"reference":12},"https:\u002F\u002Fstackoverflow.design\u002Fproduct\u002Fcomponents\u002Fmodals\u002F#celebratory",{"_key":545,"_type":66,"children":546,"markDefs":551,"style":74},"c01edb5764d2",[547],{"_key":548,"_type":70,"marks":549,"text":550},"c01edb5764d20",[],"There you have it. CSS in SVG in CSS confetti. 🎉 No additional dependencies, and it’s all just bundled in our CSS.",[],true,"2021\u002F05\u002F31","Stack Overflow celebrates site accomplishments with confetti in multiple places. That means it's time to formalize it in our design system. ",{"_type":53,"asset":556},{"_ref":557,"_type":56},"image-45ce5ecf6d26452b917575163097d3d8596e21a5-2400x1260-png",{"code":559,"language":560},"\u003C!-- wp:paragraph -->\n\u003Cp>Quite often in our product, we’ll have celebratory popovers or modals. Congrats. You did the thing! Good job! You got the feature! Hooray!\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Over on our design system \u003Ca href=\"https:\u002F\u002Fstackoverflow.design\u002F\">Stacks\u003C\u002Fa>, we recently shipped a reusable, portable way to display celebratory confetti.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:embed {\"url\":\"https:\u002F\u002Fcodepen.io\u002Faaronshekey\u002Fpen\u002FabJygGW\",\"type\":\"rich\",\"providerNameSlug\":\"codepen\",\"className\":\"\"} -->\n\u003Cfigure class=\"wp-block-embed is-type-rich is-provider-codepen wp-block-embed-codepen\">\u003Cdiv class=\"wp-block-embed__wrapper\">\nhttps:\u002F\u002Fcodepen.io\u002Faaronshekey\u002Fpen\u002FabJygGW\n\u003C\u002Fdiv>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:embed -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>The first time we needed to show some confetti, we simply included a statically rendered SVG of confetti in the background, did our best to position it out of the way of the text, and moved on with our lives. It looked like this:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image {\"id\":18140,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} -->\n\u003Cfigure class=\"wp-block-image size-large\">\u003Cimg src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2021\u002F05\u002Fconfetti-old-1200x503.png\" alt=\"\" class=\"wp-image-18140\"\u002F>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Just mere months later, we found this same approach taken 12 times throughout our product. Each iteration was slightly different. Soon we had other variations like \u003Ccode>confetti-bold.svg\u003C\u002Fcode>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image {\"id\":18141,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} -->\n\u003Cfigure class=\"wp-block-image size-large\">\u003Cimg src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2021\u002F05\u002Fgithub-730x630.png\" alt=\"\" class=\"wp-image-18141\"\u002F>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>We ought to be consistent in our approach to confetti that’s reusable, portable, and perhaps most importantly, documented. Time to formalize!\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2 id=\"h-prior-art\">Prior art\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>As many Stack Overflow users know, the best way to get started is to \u003Ca href=\"https:\u002F\u002Fstackoverflow.blog\u002F2021\u002F04\u002F19\u002Fhow-often-do-people-actually-copy-and-paste-from-stack-overflow-now-we-know\u002F\">build off a good example\u003C\u002Fa>. Thankfully, there are lots of examples of confetti in products across the internet. Apps like Bamboo use it for anniversaries and birthdays. Carta uses confetti to celebrate exercising options.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:video {\"id\":18147} -->\n\u003Cfigure class=\"wp-block-video\">\u003Cvideo controls src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2021\u002F05\u002FCarta.mp4\">\u003C\u002Fvideo>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:video -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Some are rendering things in JavaScript, others as animated gifs. There are some that are rendering entire WebGL scenes in Three.JS.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:video {\"id\":18143} -->\n\u003Cfigure class=\"wp-block-video\">\u003Cvideo controls src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2021\u002F05\u002Fthreejs.mp4\">\u003C\u002Fvideo>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:video -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>For Stack Overflow, we’d need something as portable as possible and running as close to the native HTML &amp; CSS as we can get. We didn’t want to introduce any dependencies here. We also don’t want to have to initialize some JS every time we want to show these. Relying on extra dependencies disqualified the approaches we saw across the web.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>When digging around for solutions to common problems, oftentimes I’ll start at Codepen. This led me to \u003Ca href=\"https:\u002F\u002Fcodepen.io\u002Fandyobrien\u002Fpen\u002FWYrxMe\">Andy O'Brien's Pen\u003C\u002Fa>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:embed {\"url\":\"https:\u002F\u002Fcodepen.io\u002Fandyobrien\u002Fpen\u002FWYrxMe\",\"type\":\"rich\",\"providerNameSlug\":\"codepen\",\"className\":\"\"} -->\n\u003Cfigure class=\"wp-block-embed is-type-rich is-provider-codepen wp-block-embed-codepen\">\u003Cdiv class=\"wp-block-embed__wrapper\">\nhttps:\u002F\u002Fcodepen.io\u002Fandyobrien\u002Fpen\u002FWYrxMe\n\u003C\u002Fdiv>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:embed -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This approach is simple and elegant, and the animation loops! It uses Sass-generated CSS to animate individual DOM elements. It also looked very close to our designer Vivian Zhang’s latest iteration on confetti aesthetics.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I forked the Codepen to start understanding the approach. I tweaked the colors and started messing with timing variables. Once I understood the approach, I finalized colors, and placed the confetti element within one of our modals.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:embed {\"url\":\"https:\u002F\u002Fcodepen.io\u002Faaronshekey\u002Fpen\u002FqBRZaPr?editors=1100\",\"type\":\"rich\",\"providerNameSlug\":\"codepen\",\"className\":\"\"} -->\n\u003Cfigure class=\"wp-block-embed is-type-rich is-provider-codepen wp-block-embed-codepen\">\u003Cdiv class=\"wp-block-embed__wrapper\">\nhttps:\u002F\u002Fcodepen.io\u002Faaronshekey\u002Fpen\u002FqBRZaPr?editors=1100\n\u003C\u002Fdiv>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:embed -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>But this approach has some problems. In our various contexts, we don't quite have componentization at the scale we want it. This means our engineers would have to copy and paste a baker's dozen \u003Ccode>confetti-piece\u003C\u002Fcode> divs and make sure to manage the z-index and pointer events of the resulting confetti. This approach also uses absolute positioning and flexbox to distribute the confetti pieces throughout, meaning if you wanted to use it on a wide container, it’d stretch instead of tiling.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>We sure liked the aesthetic though.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I bet instead of delivering as DOM elements, we could put all this inside an SVG and deliver as a background image, giving us way greater control over positioning, sizing, and repeating.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading -->\n\u003Ch2 id=\"h-svg-authoring\">SVG Authoring\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Ok, so SVG as a background image then? Let's give it a shot. First, I’d have to author an SVG element to house the confetti pieces. This is just a matter of distributing some rectangles on a canvas and picking some sizes we like. This is just replacing our DOM that we explored in previous Codepens for portability. I used Figma to draw this out as a time-saver, but this can all be written by hand. Here’s the final output:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image {\"id\":18144,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} -->\n\u003Cfigure class=\"wp-block-image size-large\">\u003Cimg src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2021\u002F05\u002Fbasic-svg.png\" alt=\"\" class=\"wp-image-18144\"\u002F>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&lt;svg width=\"600\" height=\"90\" viewBox=\"0 0 600 90\" fill=\"none\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\"&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"42\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"84\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"126\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"168\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"210\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"252\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"294\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"336\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"378\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"420\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"462\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"504\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n&nbsp;&nbsp;&nbsp;&nbsp;&lt;rect x=\"546\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;\u002Fsvg&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Now that I’ve got the SVG element, I can embed CSS into it and the browser will do its thing. Andy’s original approach was to color, rotate, and position various confetti elements using CSS’s \u003Ccode>nth-child\u003C\u002Fcode> selector. At first, my SVG was structured as such:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&lt;svg&gt;\n    &lt;style type=\"text\u002Fcss\"&gt;...&lt;\u002Fstyle&gt;\n    &lt;rect \u002F&gt;\n&lt;\u002Fsvg&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Oh! But now the CSS \u003Ccode>nth-child\u003C\u002Fcode> selectors are all off by one because the CSS is counting the \u003Ccode>style\u003C\u002Fcode> element as a child. I guess we'll move that to the bottom.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Also, the Sass functions aren’t going to work within our SVG, so we’ll have to compile as CSS and paste it into our SVG. Codepen can handle the compilation for us, and I can copy and paste. This is getting a little weird! 😛\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&lt;svg width=\"600\" height=\"90\" viewBox=\"0 0 600 90\" fill=\"none\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\"&gt;\n    &lt;rect x=\"42\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"84\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"126\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"168\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"210\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"252\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"294\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"336\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"378\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"420\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"462\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"504\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"546\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n\n    &lt;style type=\"text\u002Fcss\"&gt;\n        rect {\n            opacity: 0;\n        }\n        rect:nth-child(1) {\n            transform: rotate(-145deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 88ms;\n            animation-duration: 631ms;\n        }\n        rect:nth-child(2) {\n            transform: rotate(164deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 442ms;\n        }\n        rect:nth-child(3) {\n            transform: rotate(4deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 92ms;\n            animation-duration: 662ms;\n        }\n        rect:nth-child(4) {\n            transform: rotate(-175deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 17ms;\n            animation-duration: 593ms;\n        }\n        rect:nth-child(5) {\n            transform: rotate(-97deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 122ms;\n            animation-duration: 476ms;\n        }\n        rect:nth-child(6) {\n            transform: rotate(57deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 271ms;\n            animation-duration: 381ms;\n        }\n        rect:nth-child(7) {\n            transform: rotate(-46deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 619ms;\n        }\n        rect:nth-child(8) {\n            transform: rotate(-65deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 85ms;\n            animation-duration: 668ms;\n        }\n        rect:nth-child(9) {\n            transform: rotate(13deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 128ms;\n            animation-duration: 377ms;\n        }\n        rect:nth-child(10) {\n            transform: rotate(176deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 311ms;\n            animation-duration: 508ms;\n        }\n        rect:nth-child(11) {\n            transform: rotate(108deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 108ms;\n            animation-duration: 595ms;\n        }\n        rect:nth-child(12) {\n            transform: rotate(62deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 105ms;\n            animation-duration: 375ms;\n        }\n        rect:nth-child(13) {\n            transform: rotate(16deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 149ms;\n            animation-duration: 491ms;\n        }\n        rect:nth-child(odd) {\n            fill: #65BB5C;\n        }\n        rect:nth-child(even) {\n            z-index: 1;\n            fill: #33AAFF;\n        }\n        rect:nth-child(4n) {\n            animation-duration: 1400ms;\n            fill: #F23B14;\n        }\n        rect:nth-child(3n) {\n            animation-duration: 1750ms;\n            animation-delay: 700ms;\n        }\n        rect:nth-child(4n-7) {\n            fill: #2A2F6A;\n        }\n        rect:nth-child(6n) {\n            fill: #FBBA23;\n        }\n\n        @keyframes blast {\n            from {\n                opacity: 0;\n            }\n            20% {\n                opacity: 1;\n            }\n            to {\n                transform: translateY(90px);\n            }\n        }\n    &lt;\u002Fstyle&gt;\n&lt;\u002Fsvg&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Ok, wild! So if you save this as an SVG and open it in your browser, you’ll now see some animated confetti, but something is wrong about the positioning of our confetti pieces. When these were DOM elements, they just worked. Something must be different about SVG. If you guessed that SVG has different transform origins, you were correct. In the DOM, if you rotate something with CSS, it just rotates by default at the center of the element. In SVG the default origin is 0,0, meaning the very top left of our canvas 🤦‍♂️\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I solved this by measuring the distances in Figma and hardcoding some transform origins, e.g. \u003Ccode>transform-origin: 45px 5px;\u003C\u002Fcode> These origins aren’t the perfect center of the rectangles, but they’re close enough.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&lt;svg width=\"600\" height=\"90\" viewBox=\"0 0 600 90\" fill=\"none\" xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\"&gt;\n    &lt;rect x=\"42\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"84\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"126\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"168\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"210\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"252\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"294\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"336\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"378\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"420\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"462\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n    &lt;rect x=\"504\" y=\"0\" width=\"5\" height=\"13\"\u002F&gt;\n    &lt;rect x=\"546\" y=\"0\" width=\"6\" height=\"10\"\u002F&gt;\n\n    &lt;style type=\"text\u002Fcss\"&gt;\n        rect {\n            opacity: 0;\n        }\n        rect:nth-child(1) {\n            transform-origin: 45px 5px;\n            transform: rotate(-145deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 88ms;\n            animation-duration: 631ms;\n        }\n        rect:nth-child(2) {\n            transform-origin: 87px 5px;\n            transform: rotate(164deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 442ms;\n        }\n        rect:nth-child(3) {\n            transform-origin: 128px 6px;\n            transform: rotate(4deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 92ms;\n            animation-duration: 662ms;\n        }\n        rect:nth-child(4) {\n            transform-origin: 170px 6px;\n            transform: rotate(-175deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 17ms;\n            animation-duration: 593ms;\n        }\n        rect:nth-child(5) {\n            transform-origin: 213px 5px;\n            transform: rotate(-97deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 122ms;\n            animation-duration: 476ms;\n        }\n        rect:nth-child(6) {\n            transform-origin: 255px 6px;\n            transform: rotate(57deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 271ms;\n            animation-duration: 381ms;\n        }\n        rect:nth-child(7) {\n            transform-origin: 297px 5px;\n            transform: rotate(-46deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 131ms;\n            animation-duration: 619ms;\n        }\n        rect:nth-child(8) {\n            transform-origin: 338px 6px;\n            transform: rotate(-65deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 85ms;\n            animation-duration: 668ms;\n        }\n        rect:nth-child(9) {\n            transform-origin: 380px 6px;\n            transform: rotate(13deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 128ms;\n            animation-duration: 377ms;\n        }\n        rect:nth-child(10) {\n            transform-origin: 423px 5px;\n            transform: rotate(176deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 311ms;\n            animation-duration: 508ms;\n        }\n        rect:nth-child(11) {\n            transform-origin: 465px 5px;\n            transform: rotate(108deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 108ms;\n            animation-duration: 595ms;\n        }\n        rect:nth-child(12) {\n            transform-origin: 506px 6px;\n            transform: rotate(62deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 105ms;\n            animation-duration: 375ms;\n        }\n        rect:nth-child(13) {\n            transform-origin: 549px 5px;\n            transform: rotate(16deg);\n            animation: blast 700ms infinite ease-out;\n            animation-delay: 149ms;\n            animation-duration: 491ms;\n        }\n        rect:nth-child(odd) {\n            fill: #65BB5C;\n        }\n        rect:nth-child(even) {\n            z-index: 1;\n            fill: #33AAFF;\n        }\n        rect:nth-child(4n) {\n            animation-duration: 1400ms;\n            fill: #F23B14;\n        }\n        rect:nth-child(3n) {\n            animation-duration: 1750ms;\n            animation-delay: 700ms;\n        }\n        rect:nth-child(4n-7) {\n            fill: #2A2F6A;\n        }\n        rect:nth-child(6n) {\n            fill: #FBBA23;\n        }\n\n        @keyframes blast {\n            from {\n                opacity: 0;\n            }\n            20% {\n                opacity: 1;\n            }\n            to {\n                transform: translateY(90px);\n            }\n        }\n    &lt;\u002Fstyle&gt;\n&lt;\u002Fsvg&gt;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Just one last bit of finesse. Because the origins are slightly different in SVG, I’m noticing that at the bottom, I’ve got some confetti pieces getting cut off at the end of their animation. We can solve this by jogging our pieces up and off the canvas.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>&lt;rect x=\"42\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;rect x=\"84\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;rect x=\"126\" y=\"-13\" width=\"5\" height=\"13\"\u002F&gt;\n&lt;rect x=\"168\" y=\"-13\" width=\"5\" height=\"13\"\u002F&gt;\n&lt;rect x=\"210\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;rect x=\"252\" y=\"-13\" width=\"5\" height=\"13\"\u002F&gt;\n&lt;rect x=\"294\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;rect x=\"336\" y=\"-13\" width=\"5\" height=\"13\"\u002F&gt;\n&lt;rect x=\"378\" y=\"-13\" width=\"5\" height=\"13\"\u002F&gt;\n&lt;rect x=\"420\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;rect x=\"462\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\n&lt;rect x=\"504\" y=\"-13\" width=\"5\" height=\"13\"\u002F&gt;\n&lt;rect x=\"546\" y=\"-10\" width=\"6\" height=\"10\"\u002F&gt;\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:heading -->\n\u003Ch2 id=\"h-delivery\">Delivery\u003C\u002Fh2>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Great! We’ve got a single SVG file that now handles all the animation, and we now place it as a background image on any element we want. We like our animation timing, colors, and sizing too.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>We could stop right here and make sure that each project has this \u003Ccode>.svg\u003C\u002Fcode> file somewhere on the file system...\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>OR we could further encapsulate by encoding this entire SVG (with CSS) in our design system’s CSS file. CSS in SVG in CSS? Why not? 🤯\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>This is as simple as encoding the SVG as a background image like so:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>.bg-confetti-animated {\n    background-repeat: repeat-x;\n    background-position: top -10px center;\n    background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='600' height='90' viewBox='0 0 600 90' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect x='42' y='-10' width='6' height='10'\u002F%3E%3Crect x='84' y='-10' width='6' height='10'\u002F%3E%3Crect x='126' y='-13' width='5' height='13'\u002F%3E%3Crect x='168' y='-13' width='5' height='13'\u002F%3E%3Crect x='210' y='-10' width='6' height='10'\u002F%3E%3Crect x='252' y='-13' width='5' height='13'\u002F%3E%3Crect x='294' y='-10' width='6' height='10'\u002F%3E%3Crect x='336' y='-13' width='5' height='13'\u002F%3E%3Crect x='378' y='-13' width='5' height='13'\u002F%3E%3Crect x='420' y='-10' width='6' height='10'\u002F%3E%3Crect x='462' y='-10' width='6' height='10'\u002F%3E%3Crect x='504' y='-13' width='5' height='13'\u002F%3E%3Crect x='546' y='-10' width='6' height='10'\u002F%3E%3Cstyle type='text\u002Fcss'%3E rect %7B opacity: 0; %7D rect:nth-child(1) %7B transform-origin: 45px 5px; transform: rotate(-145deg); animation: blast 700ms infinite ease-out; animation-delay: 88ms; animation-duration: 631ms; %7D rect:nth-child(2) %7B transform-origin: 87px 5px; transform: rotate(164deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 442ms; %7D rect:nth-child(3) %7B transform-origin: 128px 6px; transform: rotate(4deg); animation: blast 700ms infinite ease-out; animation-delay: 92ms; animation-duration: 662ms; %7D rect:nth-child(4) %7B transform-origin: 170px 6px; transform: rotate(-175deg); animation: blast 700ms infinite ease-out; animation-delay: 17ms; animation-duration: 593ms; %7D rect:nth-child(5) %7B transform-origin: 213px 5px; transform: rotate(-97deg); animation: blast 700ms infinite ease-out; animation-delay: 122ms; animation-duration: 476ms; %7D rect:nth-child(6) %7B transform-origin: 255px 6px; transform: rotate(57deg); animation: blast 700ms infinite ease-out; animation-delay: 271ms; animation-duration: 381ms; %7D rect:nth-child(7) %7B transform-origin: 297px 5px; transform: rotate(-46deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 619ms; %7D rect:nth-child(8) %7B transform-origin: 338px 6px; transform: rotate(-65deg); animation: blast 700ms infinite ease-out; animation-delay: 85ms; animation-duration: 668ms; %7D rect:nth-child(9) %7B transform-origin: 380px 6px; transform: rotate(13deg); animation: blast 700ms infinite ease-out; animation-delay: 128ms; animation-duration: 377ms; %7D rect:nth-child(10) %7B transform-origin: 423px 5px; transform: rotate(176deg); animation: blast 700ms infinite ease-out; animation-delay: 311ms; animation-duration: 508ms; %7D rect:nth-child(11) %7B transform-origin: 465px 5px; transform: rotate(108deg); animation: blast 700ms infinite ease-out; animation-delay: 108ms; animation-duration: 595ms; %7D rect:nth-child(12) %7B transform-origin: 506px 6px; transform: rotate(62deg); animation: blast 700ms infinite ease-out; animation-delay: 105ms; animation-duration: 375ms; %7D rect:nth-child(13) %7B transform-origin: 549px 5px; transform: rotate(16deg); animation: blast 700ms infinite ease-out; animation-delay: 149ms; animation-duration: 491ms; %7D rect:nth-child(odd) %7B fill: %2365BB5C; %7D rect:nth-child(even) %7B z-index: 1; fill: %2333AAFF; %7D rect:nth-child(4n) %7B animation-duration: 1400ms; fill: %23F23B14; %7D rect:nth-child(3n) %7B animation-duration: 1750ms; animation-delay: 700ms; %7D rect:nth-child(4n-7) %7B fill: %232A2F6A; %7D rect:nth-child(6n) %7B fill: %23FBBA23; %7D @keyframes blast %7B from %7B opacity: 0; %7D 20%25 %7B opacity: 1; %7D to %7B transform: translateY(90px); %7D %7D %3C\u002Fstyle%3E%3C\u002Fsvg%3E%0A\");\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>I use \u003Ca href=\"https:\u002F\u002Fyoksel.github.io\u002Furl-encoder\u002F\">yoksel's tool\u003C\u002Fa> whenever I have to encode something like this.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:heading {\"level\":3} -->\n\u003Ch3 id=\"h-supporting-reduced-motion\">Supporting reduced motion\u003C\u002Fh3>\n\u003C!-- \u002Fwp:heading -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Some folks have a hard time with animation. Others simply prefer not seeing it at all. Thankfully, our browsers offer a media query for this \u003Ccode>@media (prefers-reduced-motion)\u003C\u002Fcode>. Let’s use it to show a statically-rendered bit of confetti, which is actually the original organic ad-hoc approach we took.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Vivian was kind enough to draw up a static version of the confetti in Figma.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:image {\"id\":18145,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} -->\n\u003Cfigure class=\"wp-block-image size-large\">\u003Cimg src=\"https:\u002F\u002Fstackoverflow.blog\u002Fwp-content\u002Fuploads\u002F2021\u002F05\u002Fconfetti-static.png\" alt=\"\" class=\"wp-image-18145\"\u002F>\u003C\u002Ffigure>\n\u003C!-- \u002Fwp:image -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>Now it’s just a matter of embedding the static version behind that media query:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>.bg-confetti-animated {\n    background-repeat: repeat-x;\n    background-position: top -10px center;\n    background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='600' height='90' viewBox='0 0 600 90' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect x='42' y='-10' width='6' height='10'\u002F%3E%3Crect x='84' y='-10' width='6' height='10'\u002F%3E%3Crect x='126' y='-13' width='5' height='13'\u002F%3E%3Crect x='168' y='-13' width='5' height='13'\u002F%3E%3Crect x='210' y='-10' width='6' height='10'\u002F%3E%3Crect x='252' y='-13' width='5' height='13'\u002F%3E%3Crect x='294' y='-10' width='6' height='10'\u002F%3E%3Crect x='336' y='-13' width='5' height='13'\u002F%3E%3Crect x='378' y='-13' width='5' height='13'\u002F%3E%3Crect x='420' y='-10' width='6' height='10'\u002F%3E%3Crect x='462' y='-10' width='6' height='10'\u002F%3E%3Crect x='504' y='-13' width='5' height='13'\u002F%3E%3Crect x='546' y='-10' width='6' height='10'\u002F%3E%3Cstyle type='text\u002Fcss'%3E rect %7B opacity: 0; %7D rect:nth-child(1) %7B transform-origin: 45px 5px; transform: rotate(-145deg); animation: blast 700ms infinite ease-out; animation-delay: 88ms; animation-duration: 631ms; %7D rect:nth-child(2) %7B transform-origin: 87px 5px; transform: rotate(164deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 442ms; %7D rect:nth-child(3) %7B transform-origin: 128px 6px; transform: rotate(4deg); animation: blast 700ms infinite ease-out; animation-delay: 92ms; animation-duration: 662ms; %7D rect:nth-child(4) %7B transform-origin: 170px 6px; transform: rotate(-175deg); animation: blast 700ms infinite ease-out; animation-delay: 17ms; animation-duration: 593ms; %7D rect:nth-child(5) %7B transform-origin: 213px 5px; transform: rotate(-97deg); animation: blast 700ms infinite ease-out; animation-delay: 122ms; animation-duration: 476ms; %7D rect:nth-child(6) %7B transform-origin: 255px 6px; transform: rotate(57deg); animation: blast 700ms infinite ease-out; animation-delay: 271ms; animation-duration: 381ms; %7D rect:nth-child(7) %7B transform-origin: 297px 5px; transform: rotate(-46deg); animation: blast 700ms infinite ease-out; animation-delay: 131ms; animation-duration: 619ms; %7D rect:nth-child(8) %7B transform-origin: 338px 6px; transform: rotate(-65deg); animation: blast 700ms infinite ease-out; animation-delay: 85ms; animation-duration: 668ms; %7D rect:nth-child(9) %7B transform-origin: 380px 6px; transform: rotate(13deg); animation: blast 700ms infinite ease-out; animation-delay: 128ms; animation-duration: 377ms; %7D rect:nth-child(10) %7B transform-origin: 423px 5px; transform: rotate(176deg); animation: blast 700ms infinite ease-out; animation-delay: 311ms; animation-duration: 508ms; %7D rect:nth-child(11) %7B transform-origin: 465px 5px; transform: rotate(108deg); animation: blast 700ms infinite ease-out; animation-delay: 108ms; animation-duration: 595ms; %7D rect:nth-child(12) %7B transform-origin: 506px 6px; transform: rotate(62deg); animation: blast 700ms infinite ease-out; animation-delay: 105ms; animation-duration: 375ms; %7D rect:nth-child(13) %7B transform-origin: 549px 5px; transform: rotate(16deg); animation: blast 700ms infinite ease-out; animation-delay: 149ms; animation-duration: 491ms; %7D rect:nth-child(odd) %7B fill: %2365BB5C; %7D rect:nth-child(even) %7B z-index: 1; fill: %2333AAFF; %7D rect:nth-child(4n) %7B animation-duration: 1400ms; fill: %23F23B14; %7D rect:nth-child(3n) %7B animation-duration: 1750ms; animation-delay: 700ms; %7D rect:nth-child(4n-7) %7B fill: %232A2F6A; %7D rect:nth-child(6n) %7B fill: %23FBBA23; %7D @keyframes blast %7B from %7B opacity: 0; %7D 20%25 %7B opacity: 1; %7D to %7B transform: translateY(90px); %7D %7D %3C\u002Fstyle%3E%3C\u002Fsvg%3E%0A\");\n\n    @media (prefers-reduced-motion) {\n        background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='574' height='60' viewBox='0 0 574 60' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect opacity='0.8' x='27.1224' y='20.0458' width='5' height='13' transform='rotate(-139 27.1224 20.0458)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='118.478' y='7.00201' width='5' height='13' transform='rotate(-38.8114 118.478 7.00201)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='504.616' y='25.4479' width='5' height='13' transform='rotate(-60.2734 504.616 25.4479)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='538.983' y='45.555' width='5' height='13' transform='rotate(16.7826 538.983 45.555)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.3' x='470.322' y='2.63625' width='5' height='13' transform='rotate(11.295 470.322 2.63625)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='190.295' y='4.58138' width='5' height='13' transform='rotate(27.5954 190.295 4.58138)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='234.303' y='16.3233' width='5' height='13' transform='rotate(-41.8233 234.303 16.3233)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='369.702' y='40.9875' width='5' height='13' transform='rotate(-56.419 369.702 40.9875)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='402.121' y='31.0848' width='5' height='13' transform='rotate(-17.9234 402.121 31.0848)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='200.316' y='31.9328' width='5' height='13' transform='rotate(-15.8896 200.316 31.9328)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.6' x='69.6745' y='23.4725' width='6' height='10' transform='rotate(70.0266 69.6745 23.4725)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='291.945' y='7.16931' width='6' height='10' transform='rotate(30.4258 291.945 7.16931)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='33.7754' y='38.2208' width='6' height='10' transform='rotate(38.6056 33.7754 38.2208)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='109.752' y='31.1743' width='6' height='10' transform='rotate(28.5296 109.752 31.1743)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='278.081' y='37.8695' width='6' height='10' transform='rotate(-26.5651 278.081 37.8695)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='416.294' y='11.5573' width='6' height='10' transform='rotate(-22.8498 416.294 11.5573)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='354.667' y='9.32341' width='6' height='10' transform='rotate(17.7506 354.667 9.32341)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.8' x='532.404' y='16.6372' width='6' height='10' transform='rotate(-75.3432 532.404 16.6372)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.6' x='460.463' y='39.3557' width='6' height='10' transform='rotate(45.4982 460.463 39.3557)' fill='%2365BB5C'\u002F%3E%3C\u002Fsvg%3E\");\n    }\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>We can also provide this as a separate class with \u003Ccode>.bg-confetti-static\u003C\u002Fcode>:\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:code -->\n\u003Cpre class=\"wp-block-code\">\u003Ccode>.bg-confetti-static {\n    background-repeat: repeat-x;\n    background-position: top -10px center;\n    background-image: url(\"data:image\u002Fsvg+xml,%3Csvg width='574' height='60' viewBox='0 0 574 60' fill='none' xmlns='http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg'%3E%3Crect opacity='0.8' x='27.1224' y='20.0458' width='5' height='13' transform='rotate(-139 27.1224 20.0458)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='118.478' y='7.00201' width='5' height='13' transform='rotate(-38.8114 118.478 7.00201)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='504.616' y='25.4479' width='5' height='13' transform='rotate(-60.2734 504.616 25.4479)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='538.983' y='45.555' width='5' height='13' transform='rotate(16.7826 538.983 45.555)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.3' x='470.322' y='2.63625' width='5' height='13' transform='rotate(11.295 470.322 2.63625)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='190.295' y='4.58138' width='5' height='13' transform='rotate(27.5954 190.295 4.58138)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='234.303' y='16.3233' width='5' height='13' transform='rotate(-41.8233 234.303 16.3233)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='369.702' y='40.9875' width='5' height='13' transform='rotate(-56.419 369.702 40.9875)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='402.121' y='31.0848' width='5' height='13' transform='rotate(-17.9234 402.121 31.0848)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.6' x='200.316' y='31.9328' width='5' height='13' transform='rotate(-15.8896 200.316 31.9328)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.6' x='69.6745' y='23.4725' width='6' height='10' transform='rotate(70.0266 69.6745 23.4725)' fill='%2365BB5C'\u002F%3E%3Crect opacity='0.6' x='291.945' y='7.16931' width='6' height='10' transform='rotate(30.4258 291.945 7.16931)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='33.7754' y='38.2208' width='6' height='10' transform='rotate(38.6056 33.7754 38.2208)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.8' x='109.752' y='31.1743' width='6' height='10' transform='rotate(28.5296 109.752 31.1743)' fill='%2333AAFF'\u002F%3E%3Crect opacity='0.3' x='278.081' y='37.8695' width='6' height='10' transform='rotate(-26.5651 278.081 37.8695)' fill='%23F23B14'\u002F%3E%3Crect opacity='0.8' x='416.294' y='11.5573' width='6' height='10' transform='rotate(-22.8498 416.294 11.5573)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.3' x='354.667' y='9.32341' width='6' height='10' transform='rotate(17.7506 354.667 9.32341)' fill='%232A2F6A'\u002F%3E%3Crect opacity='0.8' x='532.404' y='16.6372' width='6' height='10' transform='rotate(-75.3432 532.404 16.6372)' fill='%23FBBA23'\u002F%3E%3Crect opacity='0.6' x='460.463' y='39.3557' width='6' height='10' transform='rotate(45.4982 460.463 39.3557)' fill='%2365BB5C'\u002F%3E%3C\u002Fsvg%3E\");\n}\u003C\u002Fcode>\u003C\u002Fpre>\n\u003C!-- \u002Fwp:code -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>That wraps it up! Now our engineers and designers have a single, portable class of \u003Ccode>.bg-confetti-animated\u003C\u002Fcode> that they can add to any block level element. You can see the further documentation on our design system, \u003Ca href=\"https:\u002F\u002Fstackoverflow.design\u002Fproduct\u002Fbase\u002Fbackgrounds\u002F#confetti\">Stacks\u003C\u002Fa>, and how we extended it to \u003Ca href=\"https:\u002F\u002Fstackoverflow.design\u002Fproduct\u002Fcomponents\u002Fmodals\u002F#celebratory\">modal styling\u003C\u002Fa>.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->\n\n\u003C!-- wp:paragraph -->\n\u003Cp>There you have it. CSS in SVG in CSS confetti. 🎉 No additional dependencies, and it’s all just bundled in our CSS.\u003C\u002Fp>\n\u003C!-- \u002Fwp:paragraph -->","html","2021-05-31T14:00:00.000Z",{"current":563},"shipping-confetti-to-stack-overflows-design-system",[565,572,577],{"_createdAt":566,"_id":567,"_rev":568,"_type":569,"_updatedAt":566,"slug":570,"title":571},"2023-05-23T16:43:21Z","wp-tagcat-css","9HpbCsT2tq0xwozQfkc4ih","blogTag",{"current":571},"css",{"_createdAt":566,"_id":573,"_rev":568,"_type":569,"_updatedAt":566,"slug":574,"title":576},"wp-tagcat-engineering",{"current":575},"engineering","Engineering",{"_createdAt":566,"_id":578,"_rev":568,"_type":569,"_updatedAt":566,"slug":579,"title":580},"wp-tagcat-stacks",{"current":580},"stacks","CSS in SVG in CSS: Shipping confetti to Stack Overflow’s design system",[583,589,595,601],{"_id":584,"publishedAt":585,"slug":586,"sponsored":12,"title":588},"76c9771b-34e6-4d98-8641-ecefc711f0ef","2026-07-06T15:23:34.559Z",{"_type":10,"current":587},"when-the-sensor-starts-thinking-snortml-agentic-ai-and-the-evolving-architecture-of-intrusion-detection","When the sensor starts thinking: SnortML, agentic AI, and the evolving architecture of intrusion detection",{"_id":590,"publishedAt":591,"slug":592,"sponsored":12,"title":594},"28e560af-f0aa-4d46-bd90-f435ad604aa7","2026-06-26T14:00:27.102Z",{"_type":10,"current":593},"paging-charity-how-can-engineering-leaders-avoid-becoming-bond-villains","Paging Charity! How can engineering leaders avoid becoming Bond villains?",{"_id":596,"publishedAt":597,"slug":598,"sponsored":12,"title":600},"4b22c2a3-3779-4966-93eb-5230391dbdce","2026-06-23T14:08:58.595Z",{"_type":10,"current":599},"your-ai-shipped-a-backend-that-boots-that-is-the-whole-problem","Your AI shipped a backend that boots. That is the whole problem.",{"_id":602,"publishedAt":603,"slug":604,"sponsored":12,"title":606},"5cf362e1-fe7b-45af-b69c-914731c6a052","2026-06-23T14:00:00.000Z",{"_type":10,"current":605},"the-2026-developer-survey-is-now-open-for-human-developers-only","The 2026 Developer Survey is now open (for human developers only)!",{"data":608,"sourceMap":-1},{"count":609,"lastTimestamp":610},6,"2023-05-25T09:47:33Z"]