Applying multiple mask-image to a single div
Asked Answered
U

1

7

I can apply a mask-image at any place on a div I want, but can I apply more than one mask-image on the same div?

Example with a single mask-image:

div {
  width: 200px;
  height: 200px;
  background-color: green;
  border: 2px solid black;
  
  -webkit-mask-image: radial-gradient(
    circle at center top,
    transparent 30px,
    black 31px
  );
}
<div></div>

What would the code look like if I wanted to have the same mask applied at the top and at the bottom at the same time?

div {
  width: 200px;
  height: 200px;
  background-color: green;
  border: 2px solid black;
  
  -webkit-mask-image: radial-gradient(
    circle at center top,
    transparent 30px,
    black 31px
  ), radial-gradient(
    circle at center bottom,
    transparent 30px,
    black 31px
  );
}
<div></div>

Edit: I'm aware Chrome supports mask-composite, but that works (at the time of writing this) only with Chrome.

Unpretentious answered 2/11, 2020 at 12:51 Comment(0)
L
7

You need to play with the size and position. mask work the same way as background-image so simply imagine your self making two images on the same element (one on the top and the other on the bottom)

div {
  width: 200px;
  height: 200px;
  background-color: green;
  border: 2px solid black;
  -webkit-mask: 
     radial-gradient( circle at center top,    transparent 30px, black 31px) top, 
     radial-gradient( circle at center bottom, transparent 30px, black 31px) bottom;
  -webkit-mask-size:100% 51%; /* each one half the size */
  -webkit-mask-repeat:no-repeat; /* don't forget this */
}
<div></div>

Another idea with one mask:

div {
  width: 200px;
  height: 200px;
  background-color: green;
  border: 2px solid black;
  -webkit-mask: radial-gradient(circle, transparent 30px, black 31px) 0 100px; /* 100px is half the height */
}
<div></div>

and with the border:

div {
  width: 200px;
  height: 200px;
  background: radial-gradient(circle, transparent 30px, black 0 33px,green 33px) 0 100px border-box;
  border: 2px solid black;
  -webkit-mask: radial-gradient(circle, transparent 30px, black 31px) 0 100px; /* 100px is half the height */
}
<div></div>

A solution with mask-composite:

div {
  width: 200px;
  height: 200px;
  background-color: green;
  border: 2px solid black;
  -webkit-mask: 
     radial-gradient( circle at center top,    transparent 30px, black 31px), 
     radial-gradient( circle at center bottom, transparent 30px, black 31px),
     linear-gradient(black,black); /* this layer is mandatory */
   -webkit-mask-composite: destination-in;
   mask-composite: exclude; /* for non-webkit browser */
}
<div></div>
Lauraine answered 2/11, 2020 at 12:56 Comment(9)
I like your first approach, but I can't get it working with a random number of masks / images: Check jsfiddle.net/2Ly5amz1 for example.Unpretentious
@Unpretentious the size I am using is not universal, you need to adjust the sizing based on each case ... there is no generic solution, I can give you a solution for each case but it won't help you if you don't get the trick.Lauraine
@Unpretentious for a random gradient your only solution is mask-composite but you need to correctly use it .. check the update, added a solution that works in chrome and firefoxLauraine
I get the trick with the mask-size, but I think it will work only for some edge cases. For example, I'm trying to have one mask at the top center and one mask on each of the bottom edges. Unless I'm missing something in the specifications of mask-size, there is no way of specifying that "size" (shape).Unpretentious
@Unpretentious you can have any shape you want (jsfiddle.net/js8n1rcv) there is no restriction, you simply need to set the correct size/positionLauraine
Oh, I see! I wasn't understanding the trick. Now I get it! Perfect! This is exactly what I was looking for! And also thank you for taking the time to port the "border problem" from my other question!Unpretentious
I just noticed a bug in your last jsfiddle. The bottom border is missing. I know why it's happening, but I can't figure out the right combination of masks / sizes / positions in order to uncover it.Unpretentious
The problem is that "mask: right bottom" is telling the renderer: "hey, I want you to apply a mask starting from the bottom right corner and going to the center, until you cover everything", which is making the border disappear. Is there a way I can tell it to start from the center and mask only the bottom right segment of the div?Unpretentious
Sorry, my bad. I must have mixed all the jsfiddles that I'm playing with. Your jsfiddle is perfect-Unpretentious

© 2022 - 2024 — McMap. All rights reserved.