Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      CodeSOD: A Unique Way to Primary Key

      July 22, 2025

      BrowserStack launches Figma plugin for detecting accessibility issues in design phase

      July 22, 2025

      Parasoft brings agentic AI to service virtualization in latest release

      July 22, 2025

      Node.js vs. Python for Backend: 7 Reasons C-Level Leaders Choose Node.js Talent

      July 21, 2025

      The best CRM software with email marketing in 2025: Expert tested and reviewed

      July 22, 2025

      This multi-port car charger can power 4 gadgets at once – and it’s surprisingly cheap

      July 22, 2025

      I’m a wearables editor and here are the 7 Pixel Watch 4 rumors I’m most curious about

      July 22, 2025

      8 ways I quickly leveled up my Linux skills – and you can too

      July 22, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      The Intersection of Agile and Accessibility – A Series on Designing for Everyone

      July 22, 2025
      Recent

      The Intersection of Agile and Accessibility – A Series on Designing for Everyone

      July 22, 2025

      Zero Trust & Cybersecurity Mesh: Your Org’s Survival Guide

      July 22, 2025

      Execute Ping Commands and Get Back Structured Data in PHP

      July 22, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      A Tomb Raider composer has been jailed — His legacy overshadowed by $75k+ in loan fraud

      July 22, 2025
      Recent

      A Tomb Raider composer has been jailed — His legacy overshadowed by $75k+ in loan fraud

      July 22, 2025

      “I don’t think I changed his mind” — NVIDIA CEO comments on H20 AI GPU sales resuming in China following a meeting with President Trump

      July 22, 2025

      Galaxy Z Fold 7 review: Six years later — Samsung finally cracks the foldable code

      July 22, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Tech & Work»Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension

    Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension

    May 14, 2025

    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 grew up watching on TV. Shows like Dastardly and Muttley in Their Flying Machines, Scooby-Doo, The Perils of Penelope Pitstop, Wacky Races, and, of course, Yogi Bear.

    Mike loves ’90s animation — especially Disney’s Duck Tales). So, that is the aesthetic applied throughout the design.

    I used animations throughout and have recently added an extra dimension to them using masking. So, to explain how this era of animation relates to masking in CSS, I’ve chosen an episode of The Yogi Bear Show, “Disguise and Gals,” first broadcast in May 1961. In this story, two bank robbers, disguised as little old ladies, hide their loot in a “pic-a-nic” basket in Yogi and Boo-Boo’s cave!

    What could possibly go wrong?

    What’s A Mask?

    One simple masking example comes at the end of “Disguise and Gals” and countless other cartoons. Here, an animated vignette gradually hides more of Yogi’s face. The content behind the mask isn’t erased; it’s hidden.

    In CSS, masking controls visibility using a bitmap, vector, or gradient mask image. When a mask’s 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’s clear to me which areas will be visible.

    A clip-path functions similarly to a mask 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’ll refer to them as two entrances to the same cave and call using either “masking.”

    In this sequence from “Disguise and Gals,” one of the robbers rushes the picnic basket containing their loot into Yogi’s cave. Masking defines the visible area, creating the illusion that the robber is entering the cave.

    How do I choose when to use clip path and when to choose mask?

    I’ll explain my reasons in each example.

    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’ve otherwise been static images.

    Masking Using A Clipping Path

    On Mike’s 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:

    <figure>
      <svg viewBox="0 0 1400 960" id="cave">
        <g class="background">…</g>
        <g class="foreground">…</g>
      </svg>
    </figure>
    

    I defined a keyframe animation that moves the character from 2000px on the right to its natural position in the center of the frame by altering its translate value:

    @keyframes foreground {
      0% { 
        opacity: .75; 
        translate: 2000px 0;
      }
      60% { 
        opacity: 1;
        translate: 0 0;
      }
      80% {
        opacity: 1; 
        translate: 50px 0;
      }
      100% {
        opacity: 1;
        translate: 0 0;
      }
    }
    

    Then, I applied that animation to the foreground group:

    .foreground {
      opacity: 0;
      animation: foreground 5s 2s ease-in-out infinite;
    }
    

    Try this yourself:

    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 clip-path.

    There are several ways to define a clip-path in CSS. I could use a primitive shape like a rectangle, where each of the first four values specifies its corner positions. The round keyword and the value that follows define any rounded corners:

    clip-path: rect(0px 150px 150px 0px round 5px);
    

    Or xywh (x, y, width, height) values, which I find easier to read:

    clip-path: xywh(0 0 150px 150px round 5px);
    

    I could use a circle:

    clip-path: circle(60px at center);
    

    Or an ellipse:

    clip-path: ellipse(50% 40% at 50% 50%);
    

    I could use a polygon shape:

    clip-path: polygon(...);
    

    Or even the points from a path I created in a graphics app like Sketch:

    clip-path: path("M ...");
    

    Finally — and my choice for this example — I might use a mask that I defined using paths from an SVG file:

    clip-path: url(#mask-cave);
    

    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:

    <figure>
      <svg viewBox="0 0 1400 960" id="cave">...</svg>
      <svg height="0" width="0" id="mask">...</svg>
    </figure>
    

    This contains a single SVG clipPath. By placing this inside the defs element, this path isn’t rendered, but it will be available to create my CSS clip-path:

    <svg height="0" width="0" id="mask">
      <defs>
        <clipPath id="mask-cave">...</clipPath>
      </defs>
    </svg>
    

    I applied the clipPath URL to my illustration, and now Mike’s mascot only becomes visible when he enters the cave:

    #cave {
      clip-path: url(#mask-cave);
    }
    

    Try this yourself:

    While a clipPath will give me the result I’m looking for, the complexity and size of these paths can sometimes negatively affect performance. That’s when I choose a CSS mask as its properties have been baseline and highly usable since 2023.

    The mask property is a shorthand and can include values for mask-clip, mask-mode, mask-origin, mask-position, mask-repeat, mask-size, and mask-type. I find it’s best to learn these properties individually to grasp the concept of masks more easily.

    Masks control visibility using bitmap, vector, or gradient mask images. Again, when a mask’s filled pixels cover an element, its content will be visible. When they‘re 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:

    mask-image: url(mask.webp);
    

    I could apply a mask using a vector graphic:

    mask-image: url(mask.svg);
    

    Or generate an image using a conical, linear, or radial gradient:

    mask-image: linear-gradient(#000, transparent); 
    

    …or:

    mask-image: radial-gradient(circle, #ff104c 0%, transparent 100%);
    

    I might apply more than one mask to an element and mix several image types using what should be a familiar syntax:

    mask-image:
      image(url(mask.webp)),
      linear-gradient(#000, transparent);
    

    mask shares the same syntax as CSS backgrounds, which makes remembering its properties much easier. To apply a background-image, add its URL value:

    background-image: url("background.webp");
    

    To apply a mask, swap the background-image property for mask-image:

    mask-image: url("mask.webp");
    

    The mask property also shares the same browser styles as CSS backgrounds, so by default, a mask will repeat horizontally and vertically unless I specify otherwise:

    /* Options: repeat, repeat-x, repeat-y, round, space, no-repeat */
    mask-repeat: no-repeat;
    

    It will be placed at the top-left corner unless I alter its position:

    /* Options: Keywords, units, percentages */
    mask-position: center;
    

    Plus, I can specify mask-size in the same way as background-size:

    /* Options: Keywords (auto, contain, cover), units, percentages */
    mask-size: cover;
    

    Finally, I can define where a mask starts:

    mask-origin: content-box;
    mask-origin: padding-box;
    mask-origin: border-box;
    

    Using A Mask Image

    Mike’s 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’s journey. So, I created a scalable mask-image which defines the visible area and applied it to the figure element:

    figure {
      mask-image: url(mask.svg);
    }
    

    To ensure the mask matched the illustration’s dimensions, I also set the mask-size to always cover its content:

    figure {
      mask-size: cover;
    }
    

    Try this yourself:

    figure {
      clip-path: ellipse(45% 35% at 50% 50%);
    }
    

    However, the hard edges of a clip clip-path don’t create the effect I was aiming to achieve:

    Try this yourself:

    Finally, to add an extra touch of realism, I added a keyframe animation — which changes the mask-size and creates the effect that the lamp light is flickering — and applied it to the figure:

    @keyframes lamp-flicker {
      0%, 19.9%, 22%, 62.9%, 64%, 64.9%, 70%, 100% { 
        mask-size: 90%, auto;
      }
    
      20%, 21.9%, 63%, 63.9%, 65%, 69.9% { 
        mask-size: 90%, 0px;
      }
    }
    
    figure {
      animation: lamp-flicker 3s 3s linear infinite;
    }
    

    Try this yourself:

    I started by creating the binocular shape, complete with some viewfinder markers.

    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:

    figure {
      mask-image: url(mask.svg);
      mask-position: 50% 50%;
      mask-repeat: no-repeat;
      mask-size: 85%;
    }
    

    Try this yourself:

    To let someone know they might’ve reached the end of their adventure, I wanted to ape the zooming-in effect I started this article with:

    <figure>
      <svg>…</svg>
    </figure>
    

    I created a circular clip-path and set its default size to 75%. 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:

    @keyframes error {
      0% { clip-path: circle(75%); }
      100% { clip-path: circle(15%); }
    }
    
    figure {
      clip-path: circle(75%);
      animation: error 1s 3s ease-in forwards;
    }
    

    The animation now focuses someone’s attention on the hapless hero, before he sinks lower and lower into the bubblingly hot lava.

    Try this yourself:

    See the Pen Mike Worth’s error page [forked] by Andy Clarke.

    Bringing It All To Life

    Masking adds an extra dimension to web animation and makes stories more engaging and someone’s experience more compelling — all while keeping animations efficiently lightweight. Whether you’re 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.

    The end. Or is it? …

    Mike Worth’s website will launch in June 2025, but you can see examples from this article on CodePen now.

    Source: Read More 

    news
    Facebook Twitter Reddit Email Copy Link
    Previous ArticleCodeRabbit brings AI-powered code review into Visual Studio Code
    Next Article Anaconda launches unified AI platform, Parasoft adds agentic AI capabilities to testing tools, and more – SD Times Daily Digest

    Related Posts

    Tech & Work

    CodeSOD: A Unique Way to Primary Key

    July 22, 2025
    Tech & Work

    BrowserStack launches Figma plugin for detecting accessibility issues in design phase

    July 22, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    CVE-2025-31144 – Quick Agent Windows RCE Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    CVE-2025-52557 – Mail-0’s Zero JavaScript Injection Vulnerability

    Common Vulnerabilities and Exposures (CVEs)

    Microsoft Replaces JScript with JScript9Legacy for Better Security in Windows 11

    Operating Systems

    CISA Releases ICS Advisories Covering Vulnerabilities & Exploits

    Security

    Highlights

    CVE-2025-38175 – Linux Kernel Binder UAF Vulnerability

    July 4, 2025

    CVE ID : CVE-2025-38175

    Published : July 4, 2025, 11:15 a.m. | 37 minutes ago

    Description : In the Linux kernel, the following vulnerability has been resolved:

    binder: fix yet another UAF in binder_devices

    Commit e77aff5528a18 (“binderfs: fix use-after-free in binder_devices”)
    addressed a use-after-free where devices could be released without first
    being removed from the binder_devices list. However, there is a similar
    path in binder_free_proc() that was missed:

    ==================================================================
    BUG: KASAN: slab-use-after-free in binder_remove_device+0xd4/0x100
    Write of size 8 at addr ffff0000c773b900 by task umount/467
    CPU: 12 UID: 0 PID: 467 Comm: umount Not tainted 6.15.0-rc7-00138-g57483a362741 #9 PREEMPT
    Hardware name: linux,dummy-virt (DT)
    Call trace:
    binder_remove_device+0xd4/0x100
    binderfs_evict_inode+0x230/0x2f0
    evict+0x25c/0x5dc
    iput+0x304/0x480
    dentry_unlink_inode+0x208/0x46c
    __dentry_kill+0x154/0x530
    […]

    Allocated by task 463:
    __kmalloc_cache_noprof+0x13c/0x324
    binderfs_binder_device_create.isra.0+0x138/0xa60
    binder_ctl_ioctl+0x1ac/0x230
    […]

    Freed by task 215:
    kfree+0x184/0x31c
    binder_proc_dec_tmpref+0x33c/0x4ac
    binder_deferred_func+0xc10/0x1108
    process_one_work+0x520/0xba4
    […]
    ==================================================================

    Call binder_remove_device() within binder_free_proc() to ensure the
    device is removed from the binder_devices list before being kfreed.

    Severity: 0.0 | NA

    Visit the link for more details, such as CVSS details, affected products, timeline, and more…

    Amazon Aurora Global Database introduces support for up to 10 secondary Regions

    May 22, 2025

    CVE-2025-53488 – Wikimedia Foundation Mediawiki WikiHiero Extension Stored XSS

    July 7, 2025

    I can finally use this awesome NVIDIA feature on my RTX 40-series GPU, and you can too — if you’re willing to test an unstable preview driver

    July 14, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.