issue<\/a>.<\/p>\nAdding in Animation<\/h4>\n Since the standard mask-composite<\/code> only works in Firefox for now and Firefox doesn’t yet support conic-gradient()<\/code> natively, we cannot put CSS variables inside the repeating-conic-gradient()<\/code> (because Firefox still falls back on the polyfill for it and the polyfill doesn’t support CSS variable usage). But we can put them inside the repeating-radial-gradient()<\/code> and even if we cannot animate them with CSS keyframe animations, we can do so with JavaScript!<\/p>\nBecause we’re now putting CSS variables inside the repeating-radial-gradient()<\/code>, but not inside the repeating-conic-gradient()<\/code> (as we want better browser support and Firefox doesn’t support conic gradients natively, so it falls back on the polyfill, which doesn’t support CSS variable usage), we cannot use the same $stop-list<\/code> for both gradient layers of our mask<\/code> anymore.<\/p>\nBut if we have to rewrite our mask<\/code> without a common $stop-list<\/code> anyway, we can take this opportunity to use different stop positions for the two gradients:<\/p>\n\/\/ for conic gradient\r\n$nc: 20;\r\n$pc: 100%\/$nc;\r\n\/\/ for radial gradient\r\n$nr: 10;\r\n$pr: 100%\/$nr;<\/code><\/pre>\nThe CSS variable we animate is an alpha --a<\/code> one, just like for the first animation in the rays case. We also introduce the --c0<\/code> and --c1<\/code> variables because here we cannot have multiple positions per stop and we want to avoid repetition as much as possible:<\/p>\n$lyr1: repeating-conic-gradient(#000 0% .5*$pc, transparent 0% $pc);\r\n$lyr0: repeating-radial-gradient(closest-side, \r\n var(--c0), var(--c0) .5*$pr, \r\n var(--c1) 0, var(--c1) $pr);\r\n\r\nbody {\r\n --a: 0;\r\n \/* layout, backgrounds and other irrelevant stuff *\/\r\n}\r\n\r\n.xor {\r\n \/* same as before *\/\r\n --c0: #{rgba(#000, var(--a))};\r\n --c1: #{rgba(#000, calc(1 - var(--a)))};\r\n -webkit-mask: $lyr1, $lyr0;\r\n -webkit-mask-composite: xor;\r\n mask: $lyr1 exclude, $lyr0\r\n}<\/code><\/pre>\nThe alpha variable --a<\/code> is the one we animate back and forth (from 0<\/code> to 1<\/code> and then back to 0<\/code> again) with a little bit of vanilla JavaScript. We start by setting a total number of frames NF<\/code> the animation happens over, a current frame index f<\/code> and a current animation direction dir<\/code>:<\/p>\nconst NF = 50;\r\n\r\nlet f = 0, dir = 1;<\/code><\/pre>\nWithin an update()<\/code> function, we update the current frame index f<\/code> and then we set the current progress value (f\/NF<\/code>) to the current alpha --a<\/code>. If f<\/code> has reached either 0<\/code> of NF<\/code>, we change the direction. Then the update()<\/code> function gets called again on the next refresh.<\/p>\n(function update() {\r\n f += dir;\r\n \r\n document.body.style.setProperty('--a', (f\/NF).toFixed(2));\r\n\t \r\n if(!(f%NF)) dir *= -1;\r\n \r\n requestAnimationFrame(update)\r\n})();<\/code><\/pre>\nAnd that’s all for the JavaScript! We now have an animated result:<\/p>\nRipple alpha animation, linear<\/code> (live demo<\/a>, Firefox 53+ with standard mask-composite<\/code> and Chrome 1.0+\/ Safari 4.0+ with non-standard -webkit-mask-composite<\/code>).<\/figcaption><\/figure>\nThis is a linear animation, the alpha value --a<\/code> being set to the progress f\/NF<\/code>. But we can change the timing function to something else, as explained in an earlier article I wrote on emulating CSS timing functions<\/a> with JavaScript.<\/p>\nFor example, if we want an ease-in<\/code> kind of timing function, we set the alpha value to easeIn(f\/NF)<\/code> instead of just f\/NF<\/code>, where we have that easeIn()<\/code> is:<\/p>\nfunction easeIn(k, e = 1.675) {\r\n return Math.pow(k, e)\r\n}<\/code><\/pre>\nThe result when using an ease-in<\/code> timing function can be seen in this Pen<\/a> (Firefox 53+ with standard mask-composite<\/code> and Chrome 1.0+\/ Safari 4.0+ with non-standard -webkit-mask-composite<\/code>). If you’re interested in how we got this function, it’s all explained in a lot of detail in the previously linked article on timing functions.<\/p>\nThe exact same approach works for easeOut()<\/code> or easeInOut()<\/code>:<\/p>\nfunction easeOut(k, e = 1.675) {\r\n return 1 - Math.pow(1 - k, e)\r\n};\r\n\r\nfunction easeInOut(k) {\r\n return .5*(Math.sin((k - .5)*Math.PI) + 1)\r\n}<\/code><\/pre>\n