{"id":63,"date":"2025-05-14T13:00:00","date_gmt":"2025-05-14T13:00:00","guid":{"rendered":"https:\/\/jibblemuffzoodle.com\/?p=63"},"modified":"2025-05-20T14:45:19","modified_gmt":"2025-05-20T14:45:19","slug":"smashing-animations-part-2-how-css-masking-can-add-an-extra-dimension","status":"publish","type":"post","link":"https:\/\/jibblemuffzoodle.com\/index.php\/2025\/05\/14\/smashing-animations-part-2-how-css-masking-can-add-an-extra-dimension\/","title":{"rendered":"Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension"},"content":{"rendered":"

Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension<\/title><\/p>\n<article>\n<header>\n<h1>Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension<\/h1>\n<address>Andy Clarke<\/address>\n<p> 2025-05-14T13:00:00+00:00<br \/>\n 2025-05-20T14:32:36+00:00<br \/>\n <\/header>\n<p>Despite keyframes and scroll-driven events, CSS animations have remained relatively rudimentary. As I wrote in <a href=\"https:\/\/www.smashingmagazine.com\/2025\/05\/smashing-animations-part-1-classic-cartoons-inspire-css\/\">Part 1<\/a>, they remind me of the 1960s <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hanna-Barbera\">Hanna-Barbera<\/a> animated series I grew up watching on TV. Shows like Dastardly and Muttley in <em>Their Flying Machines<\/em>, <em>Scooby-Doo<\/em>, <em>The Perils of Penelope Pitstop<\/em>, <em>Wacky Races<\/em>, and, of course, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Yogi_Bear\">Yogi Bear<\/a>.<\/p>\n<figure class=\"\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/1-yogi-bear-show.jpg\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"640\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/1-yogi-bear-show.jpg\" alt=\"The Yogi Bear Show poster\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/1-yogi-bear-show.jpg\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Mike loves \u201990s animation — especially <a href=\"https:\/\/en.wikipedia.org\/wiki\/DuckTales_(1987_TV_series)\">Disney\u2019s <em>Duck Tales<\/em><\/a>. So, that is the aesthetic applied throughout the design.<\/p>\n<figure class=\"\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/2-yogi-bear-design-andy-clarke.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"550\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/2-yogi-bear-design-andy-clarke.png\" alt=\"Design by Andy Clarke\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Design by <a href=\"https:\/\/stuffandnonsense.co.uk\/\">Andy Clarke, Stuff & Nonsense<\/a>. Mike Worth\u2019s website will launch in June 2025, but you can see <a href=\"https:\/\/codepen.io\/collection\/YwMKPb\">examples from this article on CodePen<\/a>. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/2-yogi-bear-design-andy-clarke.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I used animations throughout and have recently added an extra dimension to them using <strong>masking<\/strong>. So, to explain how this era of animation relates to masking in CSS, I\u2019ve chosen an episode of <em>The Yogi Bear Show<\/em>, \u201cDisguise and Gals,\u201d first broadcast in May 1961. In this story, two bank robbers, disguised as little old ladies, hide their loot in a \u201cpic-a-nic\u201d basket in Yogi and Boo-Boo\u2019s cave!<\/p>\n<p>What could <em>possibly<\/em> go wrong?<\/p>\n<figure class=\"\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/3-yogi-bear-disguise-gals.jpg\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"640\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/3-yogi-bear-disguise-gals.jpg\" alt=\"The Yogi Bear Show, \u201cDisguise and Gals\u201d episode\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/3-yogi-bear-disguise-gals.jpg\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<div data-audience=\"non-subscriber\" data-remove=\"true\" class=\"feature-panel-container\">\n<aside class=\"feature-panel\">\n<div class=\"feature-panel-left-col\">\n<div class=\"feature-panel-description\">\n<p>Meet <strong><a data-instant href=\"https:\/\/www.smashingconf.com\/online-workshops\/\">Smashing Workshops<\/a><\/strong> on <strong>front-end, design & UX<\/strong>, with practical takeaways, live sessions, <strong>video recordings<\/strong> and a friendly Q&A. With Brad Frost, St\u00e9ph Walter and <a href=\"https:\/\/smashingconf.com\/online-workshops\/workshops\">so many others<\/a>.<\/p>\n<p><a data-instant href=\"smashing-workshops\" class=\"btn btn--green btn--large\">Jump to the workshops \u21ac<\/a><\/div>\n<\/div>\n<div class=\"feature-panel-right-col\"><a data-instant href=\"smashing-workshops\" class=\"feature-panel-image-link\"><\/p>\n<div class=\"feature-panel-image\">\n<img loading=\"lazy\" class=\"feature-panel-image-img\" src=\"\/images\/smashing-cat\/cat-scubadiving-panel.svg\" alt=\"Feature Panel\" width=\"257\" height=\"355\" \/><\/p>\n<\/div>\n<p><\/a>\n<\/div>\n<\/aside>\n<\/div>\n<h2 id=\"what-s-a-mask\">What\u2019s A Mask?<\/h2>\n<p>One simple masking example comes at the end of \u201cDisguise and Gals\u201d and countless other cartoons. Here, an animated vignette gradually hides more of Yogi\u2019s face. The content behind the mask isn\u2019t erased; it\u2019s hidden.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/4-yogi-bear-masking-example.jpg\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"198\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/4-yogi-bear-masking-example.jpg\" alt=\"A masking example of Yogi\u2019s face\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/4-yogi-bear-masking-example.jpg\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>In CSS, <strong>masking controls visibility using a bitmap, vector, or gradient mask image<\/strong>. When a mask\u2019s filled pixels cover an element, its content will be visible. When they are transparent, it will be hidden, which makes sense. Filled pixels can be any colour, but I always make mine hot pink so that it\u2019s clear to me which areas will be visible.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/5-yogi-bear-andy-clarke-recreation.jpg\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"264\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/5-yogi-bear-andy-clarke-recreation.jpg\" alt=\"The Yogi Bear\u2019s masking example by Andy Clarke\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. Author\u2019s recreation. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/5-yogi-bear-andy-clarke-recreation.jpg\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>A <code>clip-path<\/code> functions similarly to a <code>mask<\/code> but uses paths to create hard-edged clipping areas. If you want to be picky, masks and clipping paths are technically different, but the goal for using them is usually the same. So, for this article, I\u2019ll refer to them as two entrances to the same cave and call using either \u201cmasking.\u201d<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/6-yogi-bear-show.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"148\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/6-yogi-bear-show.png\" alt=\"A robber rushes the picnic basket into Yogi\u2019s cave\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/6-yogi-bear-show.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>In this sequence from \u201cDisguise and Gals,\u201d one of the robbers rushes the picnic basket containing their loot into Yogi\u2019s cave. Masking defines the visible area, creating the illusion that the robber is entering the cave.<\/p>\n<blockquote><p>How do I choose when to use <code>clip path<\/code> and when to choose <code>mask<\/code>?<\/p><\/blockquote>\n<p>I\u2019ll explain my reasons in each example.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/7-yogi-bear-show.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"219\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/7-yogi-bear-show.png\" alt=\"Masking defines the visible area of the cave\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n The Yogi Bear Show, copyright Warner Bros. Entertainment Inc. Author\u2019s recreation. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/7-yogi-bear-show.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>When Mike Worth and I discussed working together, we knew we would neither have the budget nor the time to create a short animated cartoon for his website. However, we were keen to explore how animations could bring to life what would\u2019ve otherwise been static images.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/8-mike-worth-website.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"549\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/8-mike-worth-website.png\" alt=\"Illustration by Andy Clarke for Mike Worth\u2019s website\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n Mike Worth\u2019s website will launch in June 2025, but you can see examples from this article on CodePen. (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/8-mike-worth-website.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<h2 id=\"masking-using-a-clipping-path\">Masking Using A Clipping Path<\/h2>\n<p>On Mike\u2019s biography page, his character also enters a cave. The SVG illustration I created contains two groups, one for the background and the other for the orangutan in the foreground:<\/p>\n<pre><code class=\"language-html\"><figure>\n <svg viewBox=\"0 0 1400 960\" id=\"cave\">\n <g class=\"background\">\u2026<\/g>\n <g class=\"foreground\">\u2026<\/g>\n <\/svg>\n<\/figure>\n<\/code><\/pre>\n<p>I defined a keyframe animation that moves the character from <code>2000px<\/code> on the right to its natural position in the center of the frame by altering its <code>translate<\/code> value:<\/p>\n<pre><code class=\"language-css\">@keyframes foreground {\n 0% { \n opacity: .75; \n translate: 2000px 0;\n }\n 60% { \n opacity: 1;\n translate: 0 0;\n }\n 80% {\n opacity: 1; \n translate: 50px 0;\n }\n 100% {\n opacity: 1;\n translate: 0 0;\n }\n}\n<\/code><\/pre>\n<p>Then, I applied that animation to the foreground group:<\/p>\n<pre><code class=\"language-css\">.foreground {\n opacity: 0;\n animation: foreground 5s 2s ease-in-out infinite;\n}\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"VYYgYRQ\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s about page (without clip-path) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/VYYgYRQ) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/VYYgYRQ\">Mike Worth\u2019s about page (without clip-path) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>While the <code>50px<\/code> bounce does add a touch of realism to his movement, I wasn\u2019t happy with how the character\u2019s entrance started at the edge of the viewport.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/9-masking-using-clipping-path.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"549\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/9-masking-using-clipping-path.png\" alt=\"Character standing at the edge of the illustartion made with masking using a clipping path\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/9-masking-using-clipping-path.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I wanted him to become visible at the edge of the illustration instead. As the edges of the cave walls are hard, I chose a <code>clip-path<\/code>.<\/p>\n<p>There are several ways to define a <code>clip-path<\/code> in CSS. I could use a primitive shape like a rectangle, where each of the first four values specifies its corner positions. The <code>round<\/code> keyword and the value that follows define any rounded corners:<\/p>\n<pre><code class=\"language-css\">clip-path: rect(0px 150px 150px 0px round 5px);\n<\/code><\/pre>\n<p>Or <code>xywh<\/code> (x, y, width, height) values, which I find easier to read:<\/p>\n<pre><code class=\"language-css\">clip-path: xywh(0 0 150px 150px round 5px);\n<\/code><\/pre>\n<p>I could use a <code>circle<\/code>:<\/p>\n<pre><code class=\"language-css\">clip-path: circle(60px at center);\n<\/code><\/pre>\n<p>Or an <code>ellipse<\/code>:<\/p>\n<pre><code class=\"language-css\">clip-path: ellipse(50% 40% at 50% 50%);\n<\/code><\/pre>\n<p>I could use a <code>polygon<\/code> shape:<\/p>\n<pre><code class=\"language-css\">clip-path: polygon(...);\n<\/code><\/pre>\n<p>Or even the points from a path I created in a graphics app like Sketch:<\/p>\n<pre><code class=\"language-css\">clip-path: path(\"M ...\");\n<\/code><\/pre>\n<p>Finally — and my choice for this example — I might use a mask that I defined using paths from an SVG file:<\/p>\n<pre><code class=\"language-css\">clip-path: url(#mask-cave);\n<\/code><\/pre>\n<p>To make the character visible from the edge of the illustration, I added a second SVG. To prevent a browser from displaying it, set both its dimensions to zero:<\/p>\n<pre><code class=\"language-html\"><figure>\n <svg viewBox=\"0 0 1400 960\" id=\"cave\">...<\/svg>\n <svg height=\"0\" width=\"0\" id=\"mask\">...<\/svg>\n<\/figure>\n<\/code><\/pre>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/10-svg-clippath.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"549\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/10-svg-clippath.png\" alt=\"A single SVG clipPath\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/10-svg-clippath.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>This contains a single SVG <code>clipPath<\/code>. By placing this inside the <code>defs<\/code> element, this path isn\u2019t rendered, but it will be available to create my CSS <code>clip-path<\/code>:<\/p>\n<pre><code class=\"language-svg\"><svg height=\"0\" width=\"0\" id=\"mask\">\n <defs>\n <clipPath id=\"mask-cave\">...<\/clipPath>\n <\/defs>\n<\/svg>\n<\/code><\/pre>\n<p>I applied the <code>clipPath<\/code> URL to my illustration, and now Mike\u2019s mascot only becomes visible when he enters the cave:<\/p>\n<pre><code class=\"language-css\">#cave {\n clip-path: url(#mask-cave);\n}\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"oggmgKp\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s about page (with clip-path) (without clip-path) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/oggmgKp) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/oggmgKp\">Mike Worth\u2019s about page (with clip-path) (without clip-path) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<blockquote><p><strong>Tip<\/strong>: Implement that code, and you\u2019ll notice there\u2019s a problem when resizing a browser window. While my cave illustration is flexible, the <code>clipPath<\/code> remains a fixed width.<\/p>\n<p>To make <code>clipPath<\/code> responsive, add <code>clipPathUnits=\"objectBoundingBox\"<\/code> to the opening tag, then apply two <code>scale<\/code> values to the <code>transform<\/code> property. To calculate these values, divide <code>1<\/code> first by the SVG\u2019s <code>width<\/code> and then by its <code>height<\/code>. My SVG\u2019s width is <code>1400px<\/code>, which produces the first <code>scale<\/code> value, <code>0.0007142857143<\/code>.<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-svg\"><clipPath id=\"mask-cave\"\n clipPathUnits=\"objectBoundingBox\"\n transform=\"scale(0.0007142857143, 0.001041666667)\">\n ...\n<\/clipPath>\n<\/code><\/pre>\n<\/div>\n<\/blockquote>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"clipping-irregular-shapes\">Clipping Irregular Shapes<\/h2>\n<p>I often need to change or alter illustrations — perhaps by overlaying colours or applying blending modes — but I want to retain their overall shape.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/11-altered-illustrations.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"181\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/11-altered-illustrations.png\" alt=\"Altered illustrations with overlaying colours\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/11-altered-illustrations.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>While a <code>clipPath<\/code> will give me the result I\u2019m looking for, the complexity and size of these paths can sometimes negatively affect performance. That\u2019s when I choose a CSS <code>mask<\/code> as its properties have been baseline and highly usable since 2023.<\/p>\n<p>The <code>mask<\/code> property is a shorthand and can include values for <code>mask-clip<\/code>, <code>mask-mode<\/code>, <code>mask-origin<\/code>, <code>mask-position<\/code>, <code>mask-repeat<\/code>, <code>mask-size<\/code>, and <code>mask-type<\/code>. I find it\u2019s best to learn these properties individually to grasp the concept of masks more easily.<\/p>\n<p>Masks control visibility using bitmap, vector, or gradient mask images. Again, when a mask\u2019s filled pixels cover an element, its content will be visible. When they\u2018re transparent, the content will be hidden. And when parts of a mask are semi-transparent, some of the content will show through. I can use a bitmap format that includes an alpha channel, such as PNG or WebP:<\/p>\n<pre><code class=\"language-css\">mask-image: url(mask.webp);\n<\/code><\/pre>\n<p>I could apply a mask using a vector graphic:<\/p>\n<pre><code class=\"language-css\">mask-image: url(mask.svg);\n<\/code><\/pre>\n<p>Or generate an image using a conical, linear, or radial gradient:<\/p>\n<pre><code class=\"language-css\">mask-image: linear-gradient(#000, transparent); \n<\/code><\/pre>\n<p>\u2026or:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">mask-image: radial-gradient(circle, #ff104c 0%, transparent 100%);\n<\/code><\/pre>\n<\/div>\n<p>I might apply more than one mask to an element and mix several image types using what should be a familiar syntax:<\/p>\n<pre><code class=\"language-css\">mask-image:\n image(url(mask.webp)),\n linear-gradient(#000, transparent);\n<\/code><\/pre>\n<p><code>mask<\/code> shares the same syntax as CSS backgrounds, which makes remembering its properties much easier. To apply a <code>background-image<\/code>, add its URL value:<\/p>\n<pre><code class=\"language-css\">background-image: url(\"background.webp\");\n<\/code><\/pre>\n<p>To apply a mask, swap the <code>background-image<\/code> property for <code>mask-image<\/code>:<\/p>\n<pre><code class=\"language-css\">mask-image: url(\"mask.webp\");\n<\/code><\/pre>\n<p>The <code>mask<\/code> property also shares the same browser styles as CSS backgrounds, so by default, a mask will repeat horizontally and vertically unless I specify otherwise:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">\/* Options: repeat, repeat-x, repeat-y, round, space, no-repeat *\/\nmask-repeat: no-repeat;\n<\/code><\/pre>\n<\/div>\n<p>It will be placed at the top-left corner unless I alter its position:<\/p>\n<pre><code class=\"language-css\">\/* Options: Keywords, units, percentages *\/\nmask-position: center;\n<\/code><\/pre>\n<p>Plus, I can specify <code>mask-size<\/code> in the same way as <code>background-size<\/code>:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">\/* Options: Keywords (auto, contain, cover), units, percentages *\/\nmask-size: cover;\n<\/code><\/pre>\n<\/div>\n<p>Finally, I can define where a mask starts:<\/p>\n<pre><code class=\"language-css\">mask-origin: content-box;\nmask-origin: padding-box;\nmask-origin: border-box;\n<\/code><\/pre>\n<h2 id=\"using-a-mask-image\">Using A Mask Image<\/h2>\n<p>Mike\u2019s FAQs page includes an animated illustration of his hero standing at a crossroads. My goal was to separate the shape from its content, allowing me to change the illustration throughout the hero\u2019s journey. So, I created a scalable <code>mask-image<\/code> which defines the visible area and applied it to the figure element:<\/p>\n<pre><code class=\"language-css\">figure {\n mask-image: url(mask.svg);\n}\n<\/code><\/pre>\n<p>To ensure the mask matched the illustration\u2019s dimensions, I also set the <code>mask-size<\/code> to always <code>cover<\/code> its content:<\/p>\n<pre><code class=\"language-css\">figure {\n mask-size: cover;\n}\n<\/code><\/pre>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/12-mask-image.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"181\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/12-mask-image.png\" alt=\"Mike Worth\u2019s FAQs (mask-image)\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/12-mask-image.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"VYYgLed\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s FAQs (mask-image) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/VYYgLed) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/VYYgLed\">Mike Worth\u2019s FAQs (mask-image) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>Although \u201cX\u201c never, ever marks the spot, Mike Worth\u2019s review page illustration sees his orangutan mascot studying his treasure map. I wanted to focus someone\u2019s attention on the center part of the image by using an elliptical shape.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/13-mike-worth-review-page-illustration.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"549\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/13-mike-worth-review-page-illustration.png\" alt=\"A gorilla dressed as an explorer studies a treasure map at a desk with an elliptical shape effect\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/13-mike-worth-review-page-illustration.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<pre><code class=\"language-css\">figure {\n clip-path: ellipse(45% 35% at 50% 50%);\n}\n<\/code><\/pre>\n<p>However, the hard edges of a clip <code>clip-path<\/code> don\u2019t create the effect I was aiming to achieve:<\/p>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"dPPaoXK\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s reviews page (ellipse) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/dPPaoXK) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/dPPaoXK\">Mike Worth\u2019s reviews page (ellipse) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>I experimented by combining a Gaussian blur filter with a mask defined in SVG, first by creating the filter, and then applying it to the mask\u2019s ellipse:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-svg\"><defs>\n <filter id=\"mask-blur\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"10\" \/><\/filter>\n<\/defs>\n\n<defs>\n <mask id=\"mask\">\n <ellipse cx=\"700\" cy=\"480\" fill=\"#FFF\" rx=\"450\" ry=\"320\" filter=\"url(#mask-blur)\"\/>\n <\/mask>\n<\/defs>\n<\/code><\/pre>\n<\/div>\n<p>And, while this achieved the result I was looking for, the implementation felt over-engineered for what was, after all, a simple effect. By far, the most efficient, elegant, and responsive implementation used a <code>radial-gradient<\/code>, achieving the effect I was hoping for with no bitmap or vector image and just a single CSS property:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">figure {\n mask-image: radial-gradient(ellipse farthest-corner at center center, #000 0%, transparent 75%);\n}\n<\/code><\/pre>\n<\/div>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"MYYLwjj\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s review page (radial gradient mask) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/MYYLwjj) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/MYYLwjj\">Mike Worth\u2019s review page (radial gradient mask) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>This approach enables me to fine-tune my <code>mask-image<\/code> size and even animate its colour stops, position, and size when someone interacts with its content.<\/p>\n<div class=\"partners__lead-place\"><\/div>\n<h2 id=\"layering-multiple-masks\">Layering Multiple Masks<\/h2>\n<p>Lighting is especially important on Mike Worth\u2019s review page, where his orangutan hero needs it to study his treasure map. Like background images, I can apply multiple mask images to create the lighting I need.<\/p>\n<p>I could combine two mask images: a circular, semi-transparent <code>radial-gradient<\/code> to provide the ambiance, plus a <code>linear-gradient<\/code> at a 45-degree angle for the light rays. I applied them both to the <code>figure<\/code> element:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">figure {\n mask-image:\n radial-gradient(circle, rgba(255,16,76,.5) 45%, transparent 55%),\n linear-gradient(45deg, transparent 40%, #ff104c 50%, #ff104c 50%, transparent 60%);\n mask-repeat: no-repeat;\n}\n<\/code><\/pre>\n<\/div>\n<p>I positioned the masks individually, set the <code>radial-gradient<\/code> size to <code>80%<\/code>, and the <code>linear-gradient<\/code> light rays to cover the entire image:<\/p>\n<pre><code class=\"language-css\">figure {\n mask-position: 50% 50%, 0 0;\n mask-size: 80%, cover;\n}\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"myyvJra\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s reviews page (layering multiple masks) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/myyvJra) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/myyvJra\">Mike Worth\u2019s reviews page (layering multiple masks) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>But, I needed more precise control over the position of the light rays to create the effect that they\u2019re coming from the desk lamp. So, I replaced the <code>linear-gradient<\/code> with a soft-edged bitmap image:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">figure {\n mask-image:\n radial-gradient(circle, rgba(255,16,76,.5) 45%, transparent 55%),\n url(mask.webp);\n mask-size: 90%, cover;\n}\n<\/code><\/pre>\n<\/div>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/14-layering-multiple-masks.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"180\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/14-layering-multiple-masks.png\" alt=\"A three-part image demonstrating the use of multiple masks in image editing.\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/14-layering-multiple-masks.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Finally, to add an extra touch of realism, I added a keyframe animation — which changes the <code>mask-size<\/code> and creates the effect that the lamp light is flickering — and applied it to the figure:<\/p>\n<pre><code class=\"language-css\">@keyframes lamp-flicker {\n 0%, 19.9%, 22%, 62.9%, 64%, 64.9%, 70%, 100% { \n mask-size: 90%, auto;\n }\n\n 20%, 21.9%, 63%, 63.9%, 65%, 69.9% { \n mask-size: 90%, 0px;\n }\n}\n\nfigure {\n animation: lamp-flicker 3s 3s linear infinite;\n}\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"yyyZNba\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s review page (multiple mask-images) [forked]](https:\/\/codepen.io\/smashingmag\/pen\/yyyZNba) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/yyyZNba\">Mike Worth\u2019s review page (multiple mask-images) [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<h2 id=\"animating-masks\">Animating Masks<\/h2>\n<p>Animating CSS masks creates exciting reveals and <strong>transitions between scenes<\/strong> and helps someone focus on critical content. It can also bring stories to life, making a person\u2019s experience more engaging and immersive.<\/p>\n<p>In this deleted scene from my design for his website, the orangutan adventurer mascot I created for Mike Worth can be seen driving across the landscape. To help tell the story that he\u2019s being watched from afar by his archnemesis, I wanted to add a binocular-shaped mask.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/15-binocular-shaped-mask.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"549\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/15-binocular-shaped-mask.png\" alt=\"An orangutan adventurer mascot driving across the landscape demonstrating the use of a binocular-shaped mask\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/15-binocular-shaped-mask.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>I started by creating the binocular shape, complete with some viewfinder markers.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/16-binocular-shape.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"549\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/16-binocular-shape.png\" alt=\"A binocular shape\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/16-binocular-shape.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>Then, I applied that image as a mask, setting its position, repeat, and size values to place it in the center of the figure element:<\/p>\n<pre><code class=\"language-css\">figure {\n mask-image: url(mask.svg);\n mask-position: 50% 50%;\n mask-repeat: no-repeat;\n mask-size: 85%;\n}\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"jEEdPLq\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s journey animation with binocular-shaped mask [forked]](https:\/\/codepen.io\/smashingmag\/pen\/jEEdPLq) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/jEEdPLq\">Mike Worth\u2019s journey animation with binocular-shaped mask [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>However, despite the infinitely scrolling background and the motion of the hero\u2019s bumpy ride, the animation still felt static. So I added a subtle animation that shifts the <code>mask-position<\/code>, first by creating the keyframes:<\/p>\n<div class=\"break-out\">\n<pre><code class=\"language-css\">@keyframes pan-mask {\n 0% { mask-position: 45% 45%; } \/* Start lower-left *\/\n 25% { mask-position: 55% 55%; } \/* Move to upper-right *\/\n 50% { mask-position: 43% 52%; } \/* Shift more dramatically *\/\n 75% { mask-position: 57% 48%; } \/* More variation *\/\n 100% { mask-position: 45% 45%; } \/* Loop back *\/\n}\n<\/code><\/pre>\n<\/div>\n<p>Then, I applied it, along with the scrolling background animation, to the figure element:<\/p>\n<pre><code class=\"language-css\">\/* Run both animations simultaneously *\/\nfigure {\n animation:\n background-scroll 5s linear infinite,\n pan-mask 6s ease-in-out infinite alternate;\n}\n<\/code><\/pre>\n<p>After seeing these results, I wondered whether I could connect someone to the story by linking the <code>mask-position<\/code> to the movement of their cursor. I added a script that selects the <code>figure<\/code> element, gets the cursor position relative to the viewport, and dynamically changes the <code>mask-position<\/code>:<\/p>\n<pre><code class=\"language-javascript\"><script>\n \/\/ Select the figure element.\n const figure = document.querySelector('figure');\n document.addEventListener('mousemove', (event) => {\n \n \/\/ Get the cursor position.\n const mouseX = event.clientX;\n const mouseY = event.clientY;\n \n \/\/ Normalise the mask-position.\n const maskX = (mouseX \/ window.innerWidth) * 100;\n const maskY = (mouseY \/ window.innerHeight) * 100;`\n \n \/\/ Dynamically set the mask-position.\n figure.style.maskPosition =${maskX}% ${maskY}%;\n });\n<\/script>\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"oggmXeM\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s journey animation with binoculars following the cursor [forked]](https:\/\/codepen.io\/smashingmag\/pen\/oggmXeM) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/oggmXeM\">Mike Worth\u2019s journey animation with binoculars following the cursor [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<p>With that, there was only one challenge left to complete the effect. Focusing binoculars on a distant target is rarely easy, and when the hero\u2019s archnemesis has hands the size of a silverback gorilla, the task is even more challenging. I extended my script to blur the visible content seen through the binocular-shaped mask and then removed the filter when someone presses their keyboard\u2019s spacebar or presses a mouse button:<\/p>\n<pre><code class=\"language-javascript\"><script>\n \/\/ When mouse button pressed, remove blur\n document.addEventListener('mousedown', () => {\n figure.style.filter = 'blur(0)';\n });\n \n \/\/ When mouse button released, reapply blur\n document.addEventListener('mouseup', () => {\n figure.style.filter = 'blur(5px)';\n });\n \n \/\/ When spacebar pressed, remove blur\n document.addEventListener('keydown', (event) => {\n if (event.key === ' ') {\n figure.style.filter = 'blur(0)';\n }\n });\n\n \/\/ When spacebar released, reapply blur\n document.addEventListener('keyup', (event) => {\n if (event.key === ' ') {\n figure.style.filter = 'blur(5px)';\n }\n });\n<\/script>\n<\/code><\/pre>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"MYYLwEJ\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s journey animation with focussing blur [forked]](https:\/\/codepen.io\/smashingmag\/pen\/MYYLwEJ) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/MYYLwEJ\">Mike Worth\u2019s journey animation with focussing blur [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<h2 id=\"more-masking-animation\">More Masking Animation<\/h2>\n<p>When someone using Mike Worth\u2019s website follows the wrong path or takes a wrong turn, he ends up sinking into hot lava.<\/p>\n<figure class=\"\n \n break-out article__image\n \n \n \"><\/p>\n<p> <a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/17-masking-animation.png\"><\/p>\n<p> <img loading=\"lazy\" width=\"800\" height=\"182\" src=\"https:\/\/res.cloudinary.com\/indysigner\/image\/fetch\/f_auto,q_80\/w_400\/https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/17-masking-animation.png\" alt=\"A cartoon gorilla wearing a fedora and leather jacket is shown inside a circular cutout at the center of a brown background demonstrating a masking effect\" \/><\/p>\n<p> <\/a><figcaption class=\"op-vertical-bottom\">\n (<a href=\"https:\/\/files.smashing.media\/articles\/smashing-animations-part-2-css-masking-add-extra-dimension\/17-masking-animation.png\">Large preview<\/a>)<br \/>\n <\/figcaption><\/figure>\n<p>To let someone know they might\u2019ve reached the end of their adventure, I wanted to ape the zooming-in effect I started this article with:<\/p>\n<pre><code class=\"language-html\"><figure>\n <svg>\u2026<\/svg>\n<\/figure>\n<\/code><\/pre>\n<p>I created a circular <code>clip-path<\/code> and set its default size to <code>75%<\/code>. Then, I defined the animation keyframes to resize the circle from 75% to 15% before attaching it to my figure with a one-second duration and a three-second delay:<\/p>\n<pre><code class=\"language-css\">@keyframes error {\n 0% { clip-path: circle(75%); }\n 100% { clip-path: circle(15%); }\n}\n\nfigure {\n clip-path: circle(75%);\n animation: error 1s 3s ease-in forwards;\n}\n<\/code><\/pre>\n<p>The animation now focuses someone\u2019s attention on the hapless hero, before he sinks lower and lower into the bubblingly hot lava.<\/p>\n<p>Try this yourself:<\/p>\n<figure class=\"break-out\">\n<p data-height=\"480\" data-theme-id=\"light\" data-slug-hash=\"qEEgdxy\" data-user=\"smashingmag\" data-default-tab=\"result\" class=\"codepen\">See the Pen [Mike Worth\u2019s error page [forked]](https:\/\/codepen.io\/smashingmag\/pen\/qEEgdxy) by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/p><figcaption>See the Pen <a href=\"https:\/\/codepen.io\/smashingmag\/pen\/qEEgdxy\">Mike Worth\u2019s error page [forked]<\/a> by <a href=\"https:\/\/codepen.io\/malarkey\">Andy Clarke<\/a>.<\/figcaption><\/figure>\n<h2 id=\"bringing-it-all-to-life\">Bringing It All To Life<\/h2>\n<p>Masking adds an <strong>extra dimension to web animation<\/strong> and makes stories more engaging and someone\u2019s experience more compelling — all while keeping animations efficiently lightweight. Whether you\u2019re revealing content, guiding focus, or adding more depth to a design, masks offer endless creative possibilities. So why not experiment with them in your next project? You might uncover a whole new way to bring your animations to life.<\/p>\n<p>The end. Or is it? \u2026<\/p>\n<p>Mike Worth\u2019s website will launch in June 2025, but you can <a href=\"https:\/\/codepen.io\/collection\/YwMKPb\">see examples from this article on CodePen<\/a> now.<\/p>\n<div class=\"signature\">\n <img src=\"https:\/\/www.smashingmagazine.com\/images\/logo\/logo--red.png\" alt=\"Smashing Editorial\" width=\"35\" height=\"46\" loading=\"lazy\" \/><br \/>\n <span>(yk)<\/span>\n<\/div>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension Andy Clarke 2025-05-14T13:00:00+00:00 2025-05-20T14:32:36+00:00 Despite keyframes and scroll-driven events, CSS animations have remained relatively rudimentary. As I wrote in Part 1, they remind me of the 1960s Hanna-Barbera animated series I…<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[],"_links":{"self":[{"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/posts\/63"}],"collection":[{"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/comments?post=63"}],"version-history":[{"count":1,"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/posts\/63\/revisions"}],"predecessor-version":[{"id":64,"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/posts\/63\/revisions\/64"}],"wp:attachment":[{"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/media?parent=63"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/categories?post=63"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jibblemuffzoodle.com\/index.php\/wp-json\/wp\/v2\/tags?post=63"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}