{"id":1252,"date":"2024-03-15T08:36:46","date_gmt":"2024-03-15T14:36:46","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=1252"},"modified":"2024-11-01T09:24:15","modified_gmt":"2024-11-01T14:24:15","slug":"creating-wavy-circles-with-fancy-animations","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/creating-wavy-circles-with-fancy-animations\/","title":{"rendered":"Creating Wavy Circles with Fancy Animations in CSS"},"content":{"rendered":"\n<p>In <a href=\"https:\/\/frontendmasters.com\/blog\/creating-flower-shapes-using-css-mask-trigonometric-functions\/\">a previous article<\/a>, we created flower-like shapes using modern CSS (mask, trigonometric functions, etc). This article is a follow-up where we will create a similar shape and also introduce some fancy animations.<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/creating-flower-shapes-using-css-mask-trigonometric-functions\/\">Creating Flower Shapes using CSS Mask &amp; Trigonometric Functions<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/creating-wavy-circles-with-fancy-animations\/\">Creating Wavy Circles with Fancy Animations in CSS<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n\n\n\n<p>Here is a demo of what we are building. Hover the image to see the animation<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_abxZaXm\" src=\"\/\/codepen.io\/anon\/embed\/abxZaXm?height=450&amp;theme-id=47434&amp;slug-hash=abxZaXm&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed abxZaXm\" title=\"CodePen Embed abxZaXm\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Cool right? If you check the HTML tab you won\u2019t see a lengthy code structure. A single image element is all that we will be using to build that complex-looking effect. Don\u2019t look at the CSS for now and let\u2019s build this together.<\/p>\n\n\n\n<p>You can also take a look at&nbsp;<a href=\"https:\/\/css-generators.com\/wavy-circle\/\">my online generator<\/a>&nbsp;where you can easily generate the CSS code for those wavy circles.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating The Shape<\/h2>\n\n\n\n<p>It\u2019s highly recommended that you read <a href=\"https:\/\/frontendmasters.com\/blog\/creating-flower-shapes-using-css-mask-trigonometric-functions\/\">the previous article<\/a> because I will be building on top of it. I will be reusing many tricks and the starting point of this article will be the last demo of the previous one.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_JjVPjWZ\" src=\"\/\/codepen.io\/anon\/embed\/JjVPjWZ?height=500&amp;theme-id=47434&amp;slug-hash=JjVPjWZ&amp;default-tab=result\" height=\"500\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed JjVPjWZ\" title=\"CodePen Embed JjVPjWZ\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>And here is a figure to remind you the mask composition used to create the shape.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"486\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/image-1.png?resize=1001%2C486&#038;ssl=1\" alt=\"\" class=\"wp-image-4291\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/image-1.png?w=1001&amp;ssl=1 1001w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/image-1.png?resize=300%2C146&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/image-1.png?resize=768%2C373&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>As you can see, a set of small circles is used in the \u201csubtract\u201d composition to create the inner curves, and another set of small circles is used in the \u201cadd\u201d composition to create the outer curves. The idea is to move those circles in opposite directions to create and control our wavy circle.<\/p>\n\n\n\n<p>Here is another figure to illustrate the trick<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"833\" height=\"307\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197153808_image.png?resize=833%2C307&#038;ssl=1\" alt=\"the differentd colored circles make the blob shape, and as they move around the blob changes shape.\" class=\"wp-image-1267\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197153808_image.png?w=833&amp;ssl=1 833w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197153808_image.png?resize=300%2C111&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197153808_image.png?resize=768%2C283&amp;ssl=1 768w\" sizes=\"auto, (max-width: 833px) 100vw, 833px\" \/><\/figure>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>The [1] above illustrates the initial shape where all the small circles are aligned in a way to create a bigger circle while touching each other. The red circles are the excluded ones and the blue circles are the added ones.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>In [2] above we make the blue circles closer to the center while moving the red ones in the opposite direction. The result is weird because the circles no longer touch each other but if we increase their radius, we get a perfect result.<\/p>\n<\/div>\n<\/div>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"652\" height=\"335\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197483173_image.png?resize=652%2C335&#038;ssl=1\" alt=\"\" class=\"wp-image-1268\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197483173_image.png?w=652&amp;ssl=1 652w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710197483173_image.png?resize=300%2C154&amp;ssl=1 300w\" sizes=\"auto, (max-width: 652px) 100vw, 652px\" \/><\/figure>\n\n\n\n<p>The idea is to move the circles and at the same time adjust their radius so they are always touching each other. Here is an interactive demo to better understand the movement of the circles. Use the slider to control the position of the circles.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_abxNaLZ\/968ca9653b44e930a05c3d68de72db79\" src=\"\/\/codepen.io\/anon\/embed\/abxNaLZ\/968ca9653b44e930a05c3d68de72db79?height=500&amp;theme-id=47434&amp;slug-hash=abxNaLZ\/968ca9653b44e930a05c3d68de72db79&amp;default-tab=result\" height=\"500\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed abxNaLZ\/968ca9653b44e930a05c3d68de72db79\" title=\"CodePen Embed abxNaLZ\/968ca9653b44e930a05c3d68de72db79\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Let\u2019s write some code<\/h2>\n\n\n\n<p>Now that we have the geometry of shape in place, let\u2019s translate this into code. It wasn\u2019t an easy task at all. Finding the right formulas and translating everything into a CSS code was a bit tricky.<\/p>\n\n\n\n<p>The first challenge is to find <em>one<\/em> variable that allows me to control the position of the small circles and at the same time their radius. I could have used multiple variables but having only one variable will make the shape easy to control as we only have to update one value and everything else will follow.<\/p>\n\n\n\n<p>Initially, I thought about using a length variable which is logical since the radius can be expressed as a length and to move the circles I need a distance which is also a length. I wasn\u2019t able to follow that root because finding the formulas and expressing them using CSS was almost impossible. Instead of a length I had to rely on an angle variable. It may sound wrong but it was indeed the right way to do it as I was able to find most of the formulas and write them using CSS.<\/p>\n\n\n\n<p>Here is a figure to illustrate the angle I am referring to.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"912\" height=\"386\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710242390280_image.png?resize=912%2C386&#038;ssl=1\" alt=\"update to the angle between circles.\" class=\"wp-image-1269\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710242390280_image.png?w=912&amp;ssl=1 912w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710242390280_image.png?resize=300%2C127&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/s_81A818ED8330D45649102DD720DE2F83969DFD937D67C1333C0D9895E8850757_1710242390280_image.png?resize=768%2C325&amp;ssl=1 768w\" sizes=\"auto, (max-width: 912px) 100vw, 912px\" \/><\/figure>\n\n\n\n<p>Let\u2019s take two adjacent circles and draw a line between their center (illustrated in white). The [1] shows the initial shape where all the circles are perfectly aligned around the big circle. This will be the initial state so let\u2019s consider we have an angle equal to <code>0deg<\/code>. When we move the circles and get the shape in [2] the line will rotate a little and the angle of rotation will be our variable.<\/p>\n\n\n\n<p>Don&#8217;t worry, I won\u2019t start a boring geometry course. I just wanted to highlight the variable you need to adjust so you can visualize why it\u2019s an angle and the angle of what. By the way, in the last interactive demo, you are adjusting that angle using the range slider.<\/p>\n\n\n\n<p>Here is the full demo where you can play with the different values to control the shape.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_BaEzLyJ\/8521788da90176cf53bbcec0dba53266\" src=\"\/\/codepen.io\/anon\/embed\/BaEzLyJ\/8521788da90176cf53bbcec0dba53266?height=450&amp;theme-id=47434&amp;slug-hash=BaEzLyJ\/8521788da90176cf53bbcec0dba53266&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed BaEzLyJ\/8521788da90176cf53bbcec0dba53266\" title=\"CodePen Embed BaEzLyJ\/8521788da90176cf53bbcec0dba53266\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>If you want to dig into the math, check&nbsp;<a href=\"https:\/\/math.stackexchange.com\/questions\/4956515\/find-the-radius-of-adjacent-small-circles-moving-around-a-bigger-circle\">this question on StackExchange Mathematics<\/a>. I struggled with some of the formulas so I had to ask some math gurus.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing The Image Element<\/h2>\n\n\n\n<p>Let\u2019s now consider an <code>&lt;img&gt;<\/code> element instead of a <code>&lt;div&gt;<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_MWRejwx\/0f3533e37633bb40c9a2f890c30d8fd4\" src=\"\/\/codepen.io\/anon\/embed\/MWRejwx\/0f3533e37633bb40c9a2f890c30d8fd4?height=450&amp;theme-id=47434&amp;slug-hash=MWRejwx\/0f3533e37633bb40c9a2f890c30d8fd4&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed MWRejwx\/0f3533e37633bb40c9a2f890c30d8fd4\" title=\"CodePen Embed MWRejwx\/0f3533e37633bb40c9a2f890c30d8fd4\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>It works fine but our goal is to have the image <em>within<\/em> the shape like the first example. To do this, we add some padding (or border) to leave space for the background and also add <code>border-radius<\/code> to round the image.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_mdgErVw\/ea757d7bb5eae9c381635ff4445e0733\" src=\"\/\/codepen.io\/anon\/embed\/mdgErVw\/ea757d7bb5eae9c381635ff4445e0733?height=450&amp;theme-id=47434&amp;slug-hash=mdgErVw\/ea757d7bb5eae9c381635ff4445e0733&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed mdgErVw\/ea757d7bb5eae9c381635ff4445e0733\" title=\"CodePen Embed mdgErVw\/ea757d7bb5eae9c381635ff4445e0733\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Now it\u2019s perfect! I am using a padding value equal to <code>.4*var(--r)<\/code> but there is no particular logic behind it. It\u2019s what gives me something that looks good to me. Feel free to update it if you want to increase or decrease the space around the image.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Adding The Animation<\/h2>\n\n\n\n<p>Let\u2019s move to the interesting part which is the animation. We will first adjust the shape on hover and this is the easiest part because we already did the hard job by finding one variable to control the shape. All we have to do is to update that variable on hover.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">img<\/span> {\n  <span class=\"hljs-attribute\">--a<\/span>: <span class=\"hljs-number\">28deg<\/span>;\n}\n<span class=\"hljs-selector-tag\">img<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">--a<\/span>: <span class=\"hljs-number\">10deg<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The above will simply change the shape but will not give us a smooth animation it is because by default we cannot animate CSS variables (custom properties). To do this we need to <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/@property\">register them using <code>@property.<\/code><\/a><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@property<\/span> --a {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">angle<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">true<\/span>;\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 0<span class=\"hljs-selector-tag\">deg<\/span>;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then add a transition like below<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">img<\/span> {\n  <span class=\"hljs-attribute\">transition<\/span>: --a .<span class=\"hljs-number\">3s<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now we have a perfect hover effect!<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_ZEZOBYW\/1c1eb112082a53b777f3d63436ffcf8c\" src=\"\/\/codepen.io\/anon\/embed\/ZEZOBYW\/1c1eb112082a53b777f3d63436ffcf8c?height=450&amp;theme-id=47434&amp;slug-hash=ZEZOBYW\/1c1eb112082a53b777f3d63436ffcf8c&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed ZEZOBYW\/1c1eb112082a53b777f3d63436ffcf8c\" title=\"CodePen Embed ZEZOBYW\/1c1eb112082a53b777f3d63436ffcf8c\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>Let\u2019s tackle the rotation. It\u2019s clear that we cannot rotate the whole element as the image needs to remain straight and only the shape needs to rotate. To do this, we will introduce a new angle variable and use it within the formulas that define the position of the circles.<\/p>\n\n\n\n<p>If you look at the Sass loop that generates the code of the circles, you will notice that the increment <code>$i<\/code> is used to define an angle, and this angle is used to correctly place each circle. If we update that angle, we update the position. The idea is to update the angle of all the circles with the same value so they all move the same way to simulate a rotation.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_VwNjmOR\/9b18390a4eb6f66dd69d6ce0e4b69367\" src=\"\/\/codepen.io\/anon\/embed\/VwNjmOR\/9b18390a4eb6f66dd69d6ce0e4b69367?height=450&amp;theme-id=47434&amp;slug-hash=VwNjmOR\/9b18390a4eb6f66dd69d6ce0e4b69367&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed VwNjmOR\/9b18390a4eb6f66dd69d6ce0e4b69367\" title=\"CodePen Embed VwNjmOR\/9b18390a4eb6f66dd69d6ce0e4b69367\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>In the demo above, you will see I am registering a new variable and applying an animation to it<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@property<\/span> --o {\n  <span class=\"hljs-selector-tag\">syntax<\/span>: \"&lt;<span class=\"hljs-selector-tag\">angle<\/span>&gt;\";\n  <span class=\"hljs-selector-tag\">inherits<\/span>: <span class=\"hljs-selector-tag\">true<\/span>;\n  <span class=\"hljs-selector-tag\">initial-value<\/span>: 0<span class=\"hljs-selector-tag\">deg<\/span>;\n}\n<span class=\"hljs-selector-tag\">img<\/span> {\n  <span class=\"hljs-attribute\">animation<\/span>: rotate <span class=\"hljs-number\">20s<\/span> infinite linear;\n}\n<span class=\"hljs-keyword\">@keyframes<\/span> rotate {\n  <span class=\"hljs-selector-tag\">to<\/span> { <span class=\"hljs-attribute\">--o<\/span>: <span class=\"hljs-number\">360deg<\/span>; }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then I am using that variable within the Sass loop to update the angle of the circles. Instead of <code>360deg*#{$i\/$n}<\/code>, we use <code>360deg*#{$i\/$n} + var(--o)<\/code> and instead of <code>(360deg*#{$i} + 180deg)\/#{$n}<\/code> we use <code>(360deg*#{$i} + 180deg)\/#{$n} + var(--o)<\/code>.<\/p>\n\n\n\n<p>The final touch is to increase the speed of the rotation on hover. For this, I am going to introduce <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-composition\">the <code>animation-composition<\/code> property<\/a>. It&#8217;s a pretty new propery so you may have not heard about it, but it\u2019s a powerful property that I invite you to explore. Plus the browser support is pretty good.<\/p>\n\n\n\n<p>I will update the code of the animation like below:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">img<\/span> {\n  <span class=\"hljs-attribute\">animation<\/span>: \n    rotate <span class=\"hljs-number\">20s<\/span> infinite linear,\n    rotate <span class=\"hljs-number\">20s<\/span> infinite linear paused;\n  <span class=\"hljs-attribute\">animation-composition<\/span>: add\n}\n<span class=\"hljs-selector-tag\">img<\/span><span class=\"hljs-selector-pseudo\">:hover<\/span> {\n  <span class=\"hljs-attribute\">animation-play-state<\/span>: running;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>I am applying the same animation twice while making the second one <code>paused<\/code>. On hover, both animations are <code>running<\/code>. Let\u2019s have a look at the definition of <code>animation-composition: add<\/code><\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>The <code>animation-composition<\/code> <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\">CSS<\/a> property specifies the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Glossary\/Composite_operation\">composite operation<\/a> to use when multiple animations affect the same property simultaneously.<\/p>\n<\/blockquote>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p><code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-composition#add\">add<\/a><\/code><br>The effect value builds on the underlying value of the property. This operation produces an additive effect.<\/p>\n<\/blockquote>\n\n\n\n<p>We are using the same animation so we are affecting the same property (the variable <code>--o<\/code>) and the use of <code>add<\/code> will create an additive effect. It means that <strong>the element will rotate faster when both animations are <code>running<\/code><\/strong>.<\/p>\n\n\n\n<p>Try it!<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_WNWxZYw\/6ae0a0f3914d35872cdf16efed5128bb\" src=\"\/\/codepen.io\/anon\/embed\/WNWxZYw\/6ae0a0f3914d35872cdf16efed5128bb?height=450&amp;theme-id=47434&amp;slug-hash=WNWxZYw\/6ae0a0f3914d35872cdf16efed5128bb&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed WNWxZYw\/6ae0a0f3914d35872cdf16efed5128bb\" title=\"CodePen Embed WNWxZYw\/6ae0a0f3914d35872cdf16efed5128bb\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p>The concept of <code>animation-composition<\/code> is not easy to grasp at first glance, but imagine that you <strong>add an animation on the top of another one<\/strong>. The first animation is rotating the element then we add another animation that will also rotate the element. If you rotate an element that is already rotating then you get a faster rotation. We can also <a href=\"https:\/\/css-tip.com\/slow-down-rotation\/\">decrease the rotation speed<\/a> using the same technique. This time, the second animation needs to apply an opposite rotation using the <code>reverse<\/code> keywords.<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_yLrJzwb\/3b1a87d01b929ef8fdfaaf057f381770\" src=\"\/\/codepen.io\/anon\/embed\/yLrJzwb\/3b1a87d01b929ef8fdfaaf057f381770?height=450&amp;theme-id=47434&amp;slug-hash=yLrJzwb\/3b1a87d01b929ef8fdfaaf057f381770&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed yLrJzwb\/3b1a87d01b929ef8fdfaaf057f381770\" title=\"CodePen Embed yLrJzwb\/3b1a87d01b929ef8fdfaaf057f381770\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>We are done! We created a complex-looking effect using only CSS and a single HTML element. It was a good opportunity to explore modern CSS features such as mask, trigonometric functions, <code>@property<\/code>, etc<\/p>\n\n\n\n<p>You are probably thinking it\u2019s a bit too much, right? What\u2019s the point of introducing all this complexity for a fancy effect that you will probably never use? The goal is not really to build the effect and use it but to push the limit of CSS and explore new features. In the end, you have a bunch of CSS tricks that you can use elsewhere.<\/p>\n\n\n\n<p>We learned how to use <code>mask-composite<\/code>. We learned how to animate CSS variables using <code>@property<\/code>. We played with gradients. We discovered the <code>animation-composition<\/code> property. etc. One day, you will for sure need to use those CSS tricks!<\/p>\n\n\n<div class=\"box article-series\">\n  <header>\n    <h3 class=\"article-series-header\">Article Series<\/h3>\n  <\/header>\n  <div class=\"box-content\">\n            <ol>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/creating-flower-shapes-using-css-mask-trigonometric-functions\/\">Creating Flower Shapes using CSS Mask &amp; Trigonometric Functions<\/a>\n            <\/li>\n                      <li>\n              <a href=\"https:\/\/frontendmasters.com\/blog\/creating-wavy-circles-with-fancy-animations\/\">Creating Wavy Circles with Fancy Animations in CSS<\/a>\n            <\/li>\n                  <\/ol>\n        <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>In a previous article, we created flower-like shapes using modern CSS (mask, trigonometric functions, etc). This article is a follow-up where we will create a similar shape and also introduce some fancy animations. Here is a demo of what we are building. Hover the image to see the animation Cool right? If you check the [&hellip;]<\/p>\n","protected":false},"author":12,"featured_media":1257,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[134,100,7,89],"class_list":["post-1252","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-property","tag-animation","tag-css","tag-mask"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/03\/wavy-thumb.jpg?fit=1000%2C500&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1252","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/12"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=1252"}],"version-history":[{"count":11,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1252\/revisions"}],"predecessor-version":[{"id":4316,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/1252\/revisions\/4316"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/1257"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=1252"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=1252"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=1252"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}