惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
S
Schneier on Security
T
The Exploit Database - CXSecurity.com
Webroot Blog
Webroot Blog
AI
AI
P
Palo Alto Networks Blog
Attack and Defense Labs
Attack and Defense Labs
WordPress大学
WordPress大学
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
Spread Privacy
Spread Privacy
T
Tor Project blog
罗磊的独立博客
小众软件
小众软件
S
Security Affairs
酷 壳 – CoolShell
酷 壳 – CoolShell
量子位
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
NISL@THU
NISL@THU
博客园_首页
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
IT之家
IT之家
N
News and Events Feed by Topic
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Forbes - Security
Forbes - Security
博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
T
Threat Research - Cisco Blogs
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
腾讯CDC
Security Latest
Security Latest
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
The Cloudflare Blog
A
About on SuperTechFans
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
TaoSecurity Blog
TaoSecurity Blog
宝玉的分享
宝玉的分享
G
GRAHAM CLULEY
雷峰网
雷峰网
F
Full Disclosure
I
Intezer
Cloudbric
Cloudbric
博客园 - 三生石上(FineUI控件)
U
Unit 42

CSS Articles by Temani Afif

Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks Let’s Play With Gap Decorations! How to Control Infinite CSS Animations (Part 2 of 2) How to Control Infinite CSS Animations (Part 1 of 2) Two Circles, One Arrow, and Anchor Positioning Making a Responsive Pyramidal Grid With Modern CSS | CSS-Tricks How to Create a CSS-only Elastic Text Effect Making Complex CSS Shapes Using shape() | CSS-Tricks Responsive Hexagon Grid Using Modern CSS | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 2) | CSS-Tricks Responsive List of Avatars Using Modern CSS (Part 1) | CSS-Tricks Perfectly Pointed Tooltips: To The Corners Perfectly Pointed Tooltips: All Four Sides Perfectly Pointed Tooltips: A Foundation Sequential linear() Animation With N Elements | CSS-Tricks Infinite Marquee Animation using Modern CSS Better CSS Shapes Using shape() — Part 4: Close and Move | CSS-Tricks Drawing CSS Shapes using corner-shape Better CSS Shapes Using shape() — Part 3: Curves | CSS-Tricks Better CSS Shapes Using shape() — Part 2: More on Arcs | CSS-Tricks Better CSS Shapes Using shape() — Part 1: Lines and Arcs | CSS-Tricks Creating Blob Shapes using clip-path: shape() Creating Flower Shapes using clip-path: shape() Custom progress element using the attr() function A CSS-Only Star Rating Component and More! (Part 2) | CSS-Tricks A CSS-Only Star Rating Component and More! (Part 1) | CSS-Tricks How to Create Wavy Boxes Using CSS Full-Bleed Layout with Modern CSS Fancy Menu Navigation Using Anchor Positioning | CSS-Tricks How to Create a Zig-Zag Box Using CSS How to Create Zig-Zag CSS Loaders Using One Element Custom Progress Element Using Anchor Positioning & Scroll-Driven Animations How to Create Filling CSS Loaders Using One Element How to Create Curved-Edge and Rounded-Edge Shapes Using CSS CSS Tricks That Use Only One Gradient | CSS-Tricks How to create Shapes with Inner Curves using CSS Mask Custom Range Slider Using Anchor Positioning & Scroll-Driven Animations How to Get the Width/Height of Any Element in Only CSS How Keyboard Navigation Works in a CSS Game How To Create Cut-Out Shapes using The clip-path property The Modern Guide For Making CSS Shapes — Smashing Magazine css-shape.com: The Ultimate Collection of CSS-only Shapes ⚡️ Sliding 3D Image Frames In CSS — Smashing Magazine CSS Tricks To Master The clip-path Property Creating Wavy Circles with Fancy Animations in CSS Modern CSS Tooltips And Speech Bubbles (Part 2) — Smashing Magazine Do you need a Tooltip or a Speech Bubble? I have created 100 using CSS 😲 Modern CSS Tooltips And Speech Bubbles (Part 1) — Smashing Magazine Creating Flower Shapes using CSS Mask & Trigonometric Functions CSS Shapes: The Triangle The Complex But Awesome CSS border-image Property — Smashing Magazine CSS Tricks to add 3D Effects to your Text CSS Responsive Multi-Line Ribbon Shapes (Part 2) — Smashing Magazine CSS Responsive Multi-Line Ribbon Shapes (Part 1) — Smashing Magazine I have made 100+ CSS-only Ribbon Shapes | The Perfect Collection 🎀 How to create a CSS-only infinite scroll animation Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 2) — Smashing Magazine Re-Creating The Pop-Out Hover Effect With Modern CSS (Part 1) — Smashing Magazine How to Create CSS Ribbon Shapes with a Single Element CSS Shapes: The Ribbon css-loaders.com: The Biggest Collection of Loading Animations (more than 500 🤯) How To Define An Array Of Colors With CSS — Smashing Magazine CSS effects on images II Shines, Perspective, And Rotations: Fancy CSS 3D Effects For Images — Smashing Magazine What's your Lucky CSS Pattern? Check It Now! How to Add a CSS Reveal Animation to Your Images Modern Layouts using CSS Grid I created 100+ unique CSS patterns | The best collection 🤩 How to Create a Custom Range Slider Using CSS CSS Shapes: The Heart CSS Shapes: Polygon & Starburst A Text Reveal Animation using CSS CSS Tip: learn CSS the easy way! How to build a CSS-only accordion How to create Breadcrumb Navigation with CSS Different Ways to Get CSS Gradient Shadows | CSS-Tricks A CSS-only responsive Stepper component A Fancy Hover Effect For Your Avatar | CSS-Tricks How to make a zoom effect using CSS Creating a Custom Cursor using CSS CSS Infinite 3D Sliders | CSS-Tricks CSS Infinite Slider Flipping Through Polaroid Images | CSS-Tricks How to create a responsive sidebar menu using CSS CSS Infinite and Circular Rotating Image Slider | CSS-Tricks Making Static Noise From a Weird CSS Gradient Bug | CSS-Tricks CSS Grid and Custom Shapes, Part 3 | CSS-Tricks Fancy Image Decorations: Outlines and Complex Animations | CSS-Tricks Fancy Image Decorations: Masks and Advanced Hover Effects | CSS-Tricks Fancy Image Decorations: Single Element Magic | CSS-Tricks How to create an infinite image slider using CSS How to Create Wavy Shapes & Patterns in CSS | CSS-Tricks How I Made a Pure CSS Puzzle Game | CSS-Tricks How to create a Tooltip/Speech Bubble using CSS CSS Grid and Custom Shapes, Part 2 | CSS-Tricks CSS Grid and Custom Shapes, Part 1 | CSS-Tricks Zooming Images in a Grid Layout | CSS-Tricks How to create a CSS-only loader with one element Exploring CSS Grid’s Implicit Grid and Auto-Placement Powers | CSS-Tricks How to create background pattern using CSS & conic-gradient Single Element Loaders: The Bars | CSS-Tricks
Revealing Images With CSS Mask Animations — Smashing Magazine
https://www.smashingmagazine.com/author/temani-afif/ · 2023-09-15 · via CSS Articles by Temani Afif

Let’s play with images and experiment with CSS masks. The idea is fairly simple: take a single <img> tag and harness the power of CSS to accomplish complex hover transitions. Through different demos, you will see how CSS masks combined with gradients allow us to create fancy effects — with efficient, reusable code.

In a previous article, we explored fancy hover effects for images that involve shines, rotations, and 3D perspectives. We are going to continue playing with images, but this time, we are making animations that reveal images on hover. Specifically, we will learn about CSS masks and how they can be used to cover portions of an image that are revealed when the cursor hovers over the image.

Here is the HTML we will use for our work:

<img src="" alt="">

Yes, that’s right, only one image tag. The challenge I like to take on with each new CSS project is: Let CSS do all of the work without extra markup.

As we go, you may notice minor differences between the code I share in the article and what is used inside the demos. The code throughout the article reflects the CSS specification. But since browser support is inconsistent with some of the features we’re using, I include prefixed properties for broader support.

Example 1: Circle Reveal

In this first one, an image sits in a square container that is wiped away on hover to reveal the image.

See the Pen [Hover reveal animation using mask](https://codepen.io/smashingmag/pen/abQGGew) by Temani Afif.

See the Pen Hover reveal animation using mask by Temani Afif.

The first step for us is to create the image container and the gradient border around it. The container is actually a repeating linear gradient background set on the <img> tag. If we add a little amount of padding on the image, that allows the gradient background to show through.

img {
  padding: 10px;
  background: repeating-linear-gradient(45deg, #FF6B6B 0 10px, #4ECDC4 0 20px);
}
Two square images with striped gradient borders
Two square images with striped gradient borders. (Large preview)

So, we have two images, each with a gradient background that is revealed with a touch of padding. We could have added a <div> — or perhaps even a <figure> — to the markup to create a true container, but that goes against the challenge of letting CSS do all of the work.

While we were able to work around the need for extra markup, we now have to ask ourselves: How do we hide the image without affecting the gradient background? What we need is to hide the image but continue to show the padded area around it. Enter CSS masks.

It’s not terribly complicated to apply a mask to an element, but it’s a little trickier in this context. The “trick” is to chain two mask layers together and be more explicit about where the masks are applied:

img {
  /* etc. */
  mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0) content-box;
}

Now we have two masks “sources”:

  1. content-box: one that is restricted to the image’s content,
  2. padding-box: one that covers the whole image area, including the padded area.

We need two layers because then we can combine them with the CSS mask-composite property. We have different ways to combine mask layers with mask-composite, one of which is to “exclude” the area where the two masks overlap each other.

img {
  /* etc. */
  mask:
    linear-gradient(#000 0 0) padding-box,
    linear-gradient(#000 0 0) content-box;
  mask-composite: exclude;
}

This will make only the gradient visible (the padded area), as you can see below.

See the Pen [Overview of the exclude composition](https://codepen.io/smashingmag/pen/wvQOJrZ) by Temani Afif.

See the Pen Overview of the exclude composition by Temani Afif.

Notice that we can remove the padding-box from the code since, by default, a gradient covers the whole area, and this is what we need.

Are there other ways we could do this without mask-composite? There are many ways to hide the content box while showing only the padded area. Here is one approach using a conic-gradient as the mask:

mask:
  conic-gradient(from 90deg at 10px 10px, #0000 25%, #000 0)
  0 0 / calc(100% - 10px) calc(100% - 10px);
  /* 10px is the value of padding */

See the Pen [Border-only using conic-gradient](https://codepen.io/smashingmag/pen/vYQPxWr) by Temani Afif.

See the Pen Border-only using conic-gradient by Temani Afif.

There are others, of course, but I think you get the idea. The approach you choose is totally up to you. I personally think that using mask-composite is best since it doesn’t require us to know the padding value in advance or change it in more than one place. Plus, it’s a good chance to practice using mask-composite.

Now, let’s replace the second gradient (the one covering only the content area) with a radial-gradient. We want a circle swipe for the hover transition, after all.

img {
  mask:
    linear-gradient(#000 0 0),
    radial-gradient(#000 70%,#0000 71%) content-box;
  mask-composite: exclude;
}

See the Pen [Adding the radial-gradient](https://codepen.io/smashingmag/pen/wvQOJmb) by Temani Afif.

See the Pen Adding the radial-gradient by Temani Afif.

See that? The exclude mask composite creates a hole in the image. Let’s play with the size and position of that cutout and see what is happening. Specifically, I’m going to cut the size in half and position the circle in the center of the image:

mask:
  linear-gradient(#000 0 0),
  radial-gradient(#000 70%,#0000 71%) content-box
    center / 50% 50% no-repeat;
  mask-composite: exclude;

See the Pen [Updating the radial-gradient size and position](https://codepen.io/smashingmag/pen/YzRgZvj) by Temani Afif.

See the Pen Updating the radial-gradient size and position by Temani Afif.

I bet you can already see where this is going. We adjust the size of the radial-gradient to either hide the image (increase) or reveal the image (decrease). To fully hide the image, we need to scale the mask up to such an extent that the circle covers up the image. That means we need something greater than 100%. I did some boring math and found that 141% is the precise amount, but you could wing it with a round number if you’d like.

That gives us our final CSS for the effect:

img {
  padding: 10px; /* control the thickness of the gradient "border" */
  background: repeating-linear-gradient(45deg, #FF6B6B 0 10px, #4ECDC4 0 20px);
  mask:
    linear-gradient(#000 0 0),
    radial-gradient(#000 70%, #0000 71%) content-box
      50% / var(--_s, 150% 150%) no-repeat;
  mask-composite: exclude;
  transition: .5s;
}
img:hover {
  --_s: 0% 0%;
}

A few minor details:

  • We start with a size equal to 150% 150% to initially hide the image. I am taking the additional step of applying the size as a CSS variable (--_s) with the full size (150% 150%) as a fallback value. This way, all we need to do is update the variable on hover.
  • Add a hover state that decreases the size to zero so that the image is fully revealed.
  • Apply a slight transition of .5s to smooth out the hover effect.

Here’s the final demo one more time:

See the Pen [Hover reveal animation using mask](https://codepen.io/smashingmag/pen/abQGGew) by Temani Afif.

See the Pen Hover reveal animation using mask by Temani Afif.

We just created a nice reveal animation with only a few lines of CSS — and no additional markup! We didn’t even need to resort to pseudo-elements. And this is merely one way to configure things. For example, we could play with the mask’s position to create a slick variation of the effect:

See the Pen [Another variation of the circular reveal animation](https://codepen.io/smashingmag/pen/dyQrvEq) by Temani Afif.

See the Pen Another variation of the circular reveal animation by Temani Afif.

I’m a big fan of putting an idea out there and pushing it forward with more experiments. Fork the demo and let me know what interesting things you can make out of it!

Example 2: Diagonal Reveal

Let’s increase the difficulty and try to create a hover effect that needs three gradients instead of two.

See the Pen [Hover reveal animation using mask II](https://codepen.io/smashingmag/pen/qBQKMKa) by Temani Afif.

See the Pen Hover reveal animation using mask II by Temani Afif.

Don’t look at the code just yet. Let’s try to create it step-by-step, starting with a simpler effect that follows the same pattern we created in the first example. The difference is that we’re swapping the radial-gradient with a linear-gradient:

img {
  padding: 10px; /* control the thickness of the gradient "border" */
  background: repeating-linear-gradient(45deg, #FF6B6B 0 10px, #4ECDC4 0 20px);
  mask:
    linear-gradient(#000 0 0),
    linear-gradient(135deg, #000 50%, #0000 0) content-box 
      0% 0% / 200% 200% no-repeat;
  mask-composite: exclude;
  transition: .5s;
}
img:hover {
  mask-position: 100% 100%;
    }

You’ll notice that the other minor difference between this CSS and the first example is that the size of the mask is equal to 200% 200%. Also, this time, the mask’s position is updated on hover instead of its size, going from 0% 0% (top-left) to 100% 100% (bottom-right) to create a swiping effect.

See the Pen [Diagonal reveal animation using mask](https://codepen.io/smashingmag/pen/OJaqmWV) by Temani Afif.

See the Pen Diagonal reveal animation using mask by Temani Afif.

We can change the swipe direction merely by reversing the linear gradient angle from 135deg to -45deg, then updating the position to 0% 0% on hover instead of 100% 100%:

img {
  padding: 10px; /* control the thickness of the gradient "border" */
  background: repeating-linear-gradient(45deg, #FF6B6B 0 10px, #4ECDC4 0 20px);
  mask:
    linear-gradient(#000 0 0),
    linear-gradient(-45deg, #000 50%, #0000 0) content-box 
      100% 100% / 200% 200% no-repeat;
  mask-composite: exclude;
  transition: .5s;
}
img:hover {
  mask-position: 0% 0%;
}

See the Pen [Diagonal reveal animation using mask](https://codepen.io/smashingmag/pen/ZEmPaYM) by Temani Afif.

See the Pen Diagonal reveal animation using mask by Temani Afif.

One more thing: I defined only one mask-position value on hover, but we have two gradients. If you’re wondering how that works, the mask’s position applies to the first gradient, but since a gradient occupies the full area it is applied to, it cannot be moved with percentage values. That means we can safely define only one value for both gradients, and it will affect only the second gradient. I explain this idea much more thoroughly in this Stack Overflow answer. The answer discusses background-position, but the same logic applies to mask-position.

Next, I’d like to try to combine the last two effects we created. Check the demo below to understand how I want the combination to work:

See the Pen [Combination of two diagonal reveal](https://codepen.io/smashingmag/pen/OJaqOym) by Temani Afif.

See the Pen Combination of two diagonal reveal by Temani Afif.

This time, both gradients start at the center (50% 50%). The first gradient hides the top-left part of the image, while the second gradient hides the bottom-right part of it. On hover, both gradients slide in the opposite direction to reveal the full image.

If you’re like me, you’re probably thinking: Add all the gradients together, and we’re done. Yes, that is the most intuitive solution, and it would look like this:

img {
  padding: 10px; /* control the thickness of the gradient "border" */
  background: repeating-linear-gradient(45deg, #FF6B6B 0 10px, #4ECDC4 0 20px);
  mask:
    linear-gradient(#000 0 0),
    linear-gradient(135deg, #000 50%, #0000 0) content-box 
      50% 50% / 200% 200% no-repeat,
    linear-gradient(-45deg, #000 50%, #0000 0) content-box 
      50% 50 / 200% 200% no-repeat;
  mask-composite: exclude;
  transition: .5s;
  cursor: pointer;
}
img:hover {
  mask-position: 0% 0%, 100% 100%;
}

See the Pen [Combining both effects](https://codepen.io/smashingmag/pen/qBQvVPd) by Temani Afif.

See the Pen Combining both effects by Temani Afif.

This approach kind of works, but we have a small visual glitch. Notice how a strange diagonal line is visible due to the nature of gradients and issues with anti-aliasing. We can try to fix this by increasing the percentage slightly to 50.5% instead of 50%:

See the Pen [Trying to fix the anti-aliasing issue](https://codepen.io/smashingmag/pen/ZEmPaXP) by Temani Afif.

See the Pen Trying to fix the anti-aliasing issue by Temani Afif.

Yikes, that makes it even worse. You are probably wondering if I should decrease the percentage instead of increasing it. Try it, and the same thing happens.

The fix is to update the mask-composite property. If you recall, we are already using the exclude value. Instead of declaring exclude alone, we need to also apply the add value to make sure the bottom layers (the swiping gradients) aren’t excluded from each other but are instead added together:

img {
  mask:
    /* 1st layer */
    linear-gradient(#000 0 0),

    /* 2nd layer */
    linear-gradient(135deg, #000 50.5%, #0000 0) content-box 
      50% 50% / 200% 200% no-repeat,

    /* 3rd layer */
    linear-gradient(-45deg, #000 50.5%, #0000 0) content-box 
      50% 50% / 200% 200% no-repeat;

  mask-composite: exclude, add;
}

Now, the second and third layers will use the add composition to create an intermediate layer that will be excluded from the first one. In other words, we must exclude all the layers from the first one.

I know mask-composite is a convoluted concept. I highly recommend you read Ana Tudor’s crash course on mask composition for a deeper and more thorough explanation of how the mask-composite property works with multiple layers.

This fixes the line issue in our hover effect:

See the Pen [Diagonal reveal animation using mask](https://codepen.io/smashingmag/pen/zYMbPLY) by Temani Afif.

See the Pen Diagonal reveal animation using mask by Temani Afif.

One more small detail you may have spotted: we have defined three gradients in the code but only two mask-position values on the hover state:

img:hover {
  mask-position: 0% 0%, 100% 100%;
}

The first value (0% 0%) is applied to the first gradient layer; it won’t move as it did before. The second value (100% 100%) is applied to the second gradient layer. Meanwhile, the third gradient layer uses the first value! When fewer values are declared on mask-position than the number of mask layers, the series of comma-separated values repeats until all of the mask layers are accounted for.

In this case, the series repeats circles back to the first value (0% 0%) to ensure the third mask layer takes a value. So, really, the code above is a more succinct equivalent to writing this:

img:hover {
  mask-position: 0% 0%, 100% 100%, 0% 0%;
}

Here is the final demo again with both variations. You will see that the second example uses the same code with minor updates.

See the Pen [Hover reveal animation using mask II](https://codepen.io/smashingmag/pen/qBQKMKa) by Temani Afif.

See the Pen Hover reveal animation using mask II by Temani Afif.

Example 3: Zig-Zag Reveal

I have one more example for you, this time revealing the image with zig-zag edges sliding apart, sort of like teeth chomping on the image.

See the Pen [Hover reveal animation using mask III](https://codepen.io/smashingmag/pen/vYQaLaZ) by Temani Afif.

See the Pen Hover reveal animation using mask III by Temani Afif.

While this may look like a more complex hover effect than the last two we covered, it still uses the same underlying CSS pattern we’ve used all along. In fact, I’m not even going to dive into the code as I want you to reverse-engineer it using what you now know about using CSS gradients as masks and combining mask layers with mask-composite.

I won’t give you the answer, but I will share an article I wrote that demonstrates how I created the zig-zag shape. And since I’m feeling generous, I’ll link up this online border generator as another resource.

Wrapping Up

I hope you enjoyed this little experiment with CSS masks and gradients! Gradients can be confusing, but mixing them with masks is nothing short of complicated. But after spending the time it takes to look at three examples in pieces, we can clearly see how gradients can be used as masks as well as how we can combine them to “draw” visible areas.

Once we have an idea of how that works, it’s amazing that all we need to do to get the effect is update either the mask’s position or size on the element’s hover state. And the fact that we can accomplish all of this with a single HTML element shows just how powerful CSS is.

We saw how the same general CSS pattern can be tweaked to generate countless variations of the same effect. I thought I’d end this article with a few more examples for you to play with.

See the Pen [Hover reveal animation using mask IV](https://codepen.io/smashingmag/pen/PoxLMOy) by Temani Afif.

See the Pen Hover reveal animation using mask IV by Temani Afif.

See the Pen [Hover reveal animation using mask V](https://codepen.io/smashingmag/pen/jOQJgxN) by Temani Afif.

See the Pen Hover reveal animation using mask V by Temani Afif.

See the Pen [Hover reveal animation using mask VI](https://codepen.io/smashingmag/pen/gOQEVdQ) by Temani Afif.

See the Pen Hover reveal animation using mask VI by Temani Afif.

Further Reading on Smashing Magazine

Smashing Editorial (gg, yk, il)