Element's border missing after css mask-image

3.1k Views Asked by At

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.

3

There are 3 best solutions below

2
On

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>

3
On

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.

2
On

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>