Search code examples
csspngbackground-imagetransparencyimage-masking

Why does this PNG not work for CSS background-image when used elsewhere as a mask, but after uploading to Imgur it does?


This is driving me nuts. I thought this was a masking issue at first (might still be), but it seems that the original version doesn't even work as a background image in some cases.

The only difference between the two is that the latter ("Imgur") was uploaded to Imgur, and appears to be re-saved.

Original
Original metadata

Imgur
Imgur metadata

.mask {
  background-color: navy;
  -webkit-mask-size: 144px;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: 0 0;
  mask-size: 144px;
  mask-repeat: no-repeat;
  mask-position: 0 0;
}
 #orig .mask {
  -webkit-mask-image: url("https://i.sstatic.net/ebAGH.png");
  mask-image: url("https://i.sstatic.net/ebAGH.png");
}
 #orig .bg {
  background-image: url("https://i.sstatic.net/ebAGH.png");
}
 #imgur .mask {
  -webkit-mask-image: url("https://i.sstatic.net/LcBj8.png");
  mask-image: url("https://i.sstatic.net/LcBj8.png");
}
 #imgur .bg {
 background-image: url("https://i.sstatic.net/LcBj8.png");
}
/* just fluff below */
body {
  background-color: #a0a0a0;
  background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}
p {
  background-color: white;
  padding: 5px;
}
.mask, .bg, img {
  border: 1px solid black;
  display: inline-block;
  width: 144px;
  height: 144px;
}
<div id="orig">
  <p>Orignal</p>
  <div class="mask"></div>
  <div class="bg"></div>
  <img src="https://i.sstatic.net/ebAGH.png">
</div>
<div id="imgur">
  <p>Imgur</p>
  <div class="mask"></div>
  <div class="bg"></div>
  <img src="https://i.sstatic.net/LcBj8.png">
</div>

Why isn't the top original image working for the background?

Also, if I comment out the masking part, the background works again? I am so lost...

EDIT: it appears in Firefox that the background image does work, but it still doesn't work as a mask.

EDIT 2: I should note that this image is not unique and hasn't been corrupted. It was exported from Photoshop or Illustrator (by our designer) along with several other similar images, all of which have the same problem.


Solution

  • This is because per specs the <image> resource used for mask-image is fetched with cross-origin: anonymous:

    <mask-source>s and <clip-source>s have special requirements on fetching resources.

    User agents must use the potentially CORS-enabled fetch method defined by the [FETCH] specification for all <mask-source>, <clip-source> and <image> values on the mask-image, mask-border-source and clip-path properties. When fetching, user agents must use “Anonymous” mode, set the referrer source to the stylesheet’s URL and set the origin to the URL of the containing document. If this results in network errors, the effect is as if the value none had been specified.

    The sub-domain https://i.stack.imgur.com doesn't pass the proper Access-Control-Allow-Origin: * HTTP header and thus the request is blocked.
    On the other hand, https://i.sstatic.net/ does send the proper headers, so there we can load the image safely:

    https://i.stack.imgur.com/ebAGH.png: <img src="https://i.stack.imgur.com/ebAGH.png" crossorigin="anonymous"><br>
    https://i.sstatic.net/aSwgX.png: <img src="https://i.sstatic.net/aSwgX.png" crossorigin="anonymous">

    (Note that there is this meta request to change StackOverflow's subdomain behavior).


    According to BUG 786507 there wasn't really any identified threat here, but this follows an ongoing best-practice "to fully protect images behind CORS".
    So that's how it is.


    As for why it doesn't work in your Chrome as background-image sometimes, I'm not entirely sure and can't reproduce on my side, but I'd suspect it's some caching issue where they use the cross-origin: anonymous request instead of the default one. You may want to open an issue at https://crbug.com after you check the "Network" panel of your dev-tools.