5

I have applied an svg as mask-image to certain divs. After doing that their border is gone.

.icon {
  padding:5px;
  border:5px solid #000;
  width: 150px;
  height: 150px;
  display: inline-block;
  -webkit-mask: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%;
  -webkit-mask-size: contain;
  mask-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%;
  mask-size: contain;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}
<div class="wrap">
  <div class="icon red"></div>
  <div class="icon blue"></div>
</div>

Any idea why this happens? Any solution should be based solely on css.

Sakis
  • 821
  • 7
  • 12
  • For those of you not seeing the issue, Chrome doesn't support `mask` without a vendor prefix so you'll need to use Firefox – j08691 Oct 09 '20 at 15:01
  • For more details about it: https://caniuse.com/css-masks – MaxiGui Oct 09 '20 at 15:07
  • well, mask apply to all the element including its border – Temani Afif Oct 09 '20 at 15:23
  • @Sakis I would try to solve this by adding an additional div around the masked div. Pls have a look at my answer below. Hope that is the desired result. – Kiran Dash Oct 09 '20 at 15:28
  • Does this answer your question? [CSS Webkit mask image add an outline / border?](https://stackoverflow.com/questions/23861920/css-webkit-mask-image-add-an-outline-border) – MaxiGui Oct 09 '20 at 15:34
  • Thanks. Added a prefixed and non prefixed css. Should work in most browsers. – Sakis Oct 09 '20 at 15:55

3 Answers3

2

The answer for the why is trivial: The mask apply to all the element including its borders. Any part of the element will get affect by the mask even if you have a box-shadow

To avoid this, either use another element to create the borders or consider multiple mask to keep the border visible:

.icon {
  padding:5px;
  border:5px solid #000;
  width: 150px;
  height: 150px;
  display: inline-block;
  -webkit-mask: 
      linear-gradient(#fff 0 0) top   /100% 5px,
      linear-gradient(#fff 0 0) bottom/100% 5px,
      linear-gradient(#fff 0 0) left  /5px 100%,
      linear-gradient(#fff 0 0) right /5px 100%,
      url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) center/contain;
   -webkit-mask-repeat:no-repeat;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}
<div class="wrap">
  <div class="icon red"></div>
  <div class="icon blue"></div>
</div>

I added 4 gradients. Each one will cover a border side to keep it visible.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • That is a very cool way actualy what you made. But that would only work for a square border without border radius, no ? – MaxiGui Oct 10 '20 at 09:51
  • 1
    @MaxiGui it can work with border radius. I simply need to adjust the gradients and consider radial ones to cover the radius – Temani Afif Oct 10 '20 at 11:34
  • Then it seems to more simple than the official usage of what I sent or at least more flexible – MaxiGui Oct 10 '20 at 14:49
0

I am using an extra div wrapper to create border around the div containing mask.

I have added comments to the code to explain my changes.

.maskborder{
  width: 150px;
  height: 150px;
  border:5px solid #000;
  position: relative;
  float: left;
}

.maskborder.two {
  margin-left: 10px; /* Change this to suit how much gap you want between first and second box */
}

.icon {
  padding:5px;
  border:5px solid #000;
  width: 150px;
  height: 150px;
  display: inline-block;
  mask: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%;
  -webkit-mask: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%;
  mask-size: contain;
  -webkit-mask-size: contain;
  position: absolute;
  transform: translate(-10px, -10px) /* To offset the 5px border width so that the icons can be centred correctly in middle */
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}
<div class="wrap">
  <div class="maskborder">
    <div class="icon red"></div>
  </div>
  <div class="maskborder two">
     <div class="icon blue"></div>
  </div>
</div>
Kiran Dash
  • 4,816
  • 12
  • 53
  • 84
  • Thanks. Though i am looking for a css based solution or an explanation why this happens. – Sakis Oct 09 '20 at 15:39
  • Well. The answer is CSS based. You can not add plain old CSS borders to masked element. You must apply either a masked border image. Or in your case since you want plain border CSS, we must apply it to a parent div and position on top of it. Hope that helps – Kiran Dash Oct 09 '20 at 16:05
0

So after serching for a while, I finaly found out the border property for mask, it seems that you need to use an other svg as square that would make the border.

I added the below properties to .icon:

-webkit-mask-box-image: url(https://www.flaticon.com/svg/static/icons/svg/33/33879.svg) 10 repeat;
mask-border: url(https://www.flaticon.com/svg/static/icons/svg/33/33879.svg) 10 repeat;

I actualy find out the trick here: https://css-tricks.com/clipping-masking-css/#border-masks and just adapted it for your case.

I guess you can easily create a svg square with the border that fit and just set it in.

DEMO

.icon {
  padding:5px;
  border:5px solid #000;
  width: 150px;
  height: 150px;
  display: inline-block;
  -webkit-mask: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%;
  -webkit-mask-size: contain;
  mask-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/18515/heart.svg) no-repeat 50% 50%;
  mask-size: contain;
  -webkit-mask-box-image: url(https://www.flaticon.com/svg/static/icons/svg/33/33879.svg) 10 repeat;
  mask-border: url(https://www.flaticon.com/svg/static/icons/svg/33/33879.svg) 10 repeat;
}

.red {
  background-color: red;
}

.blue {
  background-color: blue;
}
<div class="wrap">
  <div class="icon red"></div>
  <div class="icon blue"></div>
</div>
MaxiGui
  • 6,190
  • 4
  • 16
  • 33
  • 1
    Works in chrome but not in Firefox. – Sakis Oct 12 '20 at 12:42
  • Indeed. But this is really features. But even thought this is my answer, I think that answer from @TemaniAfif is much better and flexible than mine. – MaxiGui Oct 12 '20 at 14:39