cssiossvgsafari

In Safari svg mask looks blurry like if it's raster


In Safari but not in Chrome applying svg mask on svg icon renders blurry edges. I've created minimal reproducible example... at least I hope that it's reproducible. Because this effect is not constant:

I've tried it on desktop in 15.6.1 and 16.4 and in webviews on an assortment of Apple mobile devices.

The actual result:

enter image description here

The expected result:

enter image description here

<html>
<head>
    <style>
    .logo {
        width: 96px;
        height: 96px;
        -webkit-mask-size: contain;
        mask-size: contain;
        -webkit-mask-image:
            url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PG1hc2sgaWQ9ImEiIHN0eWxlPSJtYXNrLXR5cGU6YWxwaGEiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiIHg9IjAiIHk9IjAiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCI+PHBhdGggZD0iTTQ4IDI0YzAgMTkuMjA1LTQuNzk1IDI0LTI0IDI0UzAgNDMuMjA1IDAgMjQgNC43OTUgMCAyNCAwczI0IDQuNzk1IDI0IDI0eiIgZmlsbD0iI2ZmZiIvPjwvbWFzaz48ZyBtYXNrPSJ1cmwoI2EpIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMCAwaDQ4djQ4SDB6Ii8+PC9nPjwvc3ZnPg==);
        mask-image:
            url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PG1hc2sgaWQ9ImEiIHN0eWxlPSJtYXNrLXR5cGU6YWxwaGEiIG1hc2tVbml0cz0idXNlclNwYWNlT25Vc2UiIHg9IjAiIHk9IjAiIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCI+PHBhdGggZD0iTTQ4IDI0YzAgMTkuMjA1LTQuNzk1IDI0LTI0IDI0UzAgNDMuMjA1IDAgMjQgNC43OTUgMCAyNCAwczI0IDQuNzk1IDI0IDI0eiIgZmlsbD0iI2ZmZiIvPjwvbWFzaz48ZyBtYXNrPSJ1cmwoI2EpIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMCAwaDQ4djQ4SDB6Ii8+PC9nPjwvc3ZnPg==);
        background-image:
            url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iIzAwMCIgZD0iTTAgMGgyMHYyMEgweiIvPjwvc3ZnPg==);
            background-size: cover;
    }
    </style>
</head>
<body>
    <div class="logo"/>
</body>
</html>

SVGs

  1. The mask:
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_16513_8424" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="48" height="48">
<path d="M48 24C48 43.2052 43.2052 48 24 48C4.79475 48 0 43.2052 0 24C0 4.79475 4.79475 0 24 0C43.2052 0 48 4.79475 48 24Z" fill="white"/>
</mask>
<g mask="url(#mask0_16513_8424)">
<rect width="48" height="48" fill="black"/>
</g>
<defs>
</defs>
</svg>
  1. The icon:
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="20" fill="#000000"/>
</svg>

Solution

  • Apparently, safari has problems with mask-images containing masked elements.

    Fortunately you can simplify your mask:

    .logo {
      width: 96px;
      height: 96px;
      background: #000;
      display: inline-block;
      mask-size: contain;
      -webkit-mask-size: contain;
      -webkit-mask-image:url("data:image/svg+xml,%3Csvg width='48' height='48' fill='none' viewBox='0 0 48 48' xmlns='http://www.w3.org/2000/svg'%3E%3Cmask id='a' style='mask-type:alpha' maskUnits='userSpaceOnUse' x='0' y='0' width='48' height='48'%3E%3Cpath d='M48 24c0 19.205-4.795 24-24 24S0 43.205 0 24 4.795 0 24 0s24 4.795 24 24z' fill='%23fff'/%3E%3C/mask%3E%3Cg mask='url(%23a)'%3E%3Cpath fill='%23000' d='M0 0h48v48H0z'/%3E%3C/g%3E%3C/svg%3E");
    }
    
    .logo2 {
      width: 96px;
      height: 96px;
      background: #000;
      display: inline-block;
      mask-size: contain;
      -webkit-mask-size: contain;
      -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Cpath d='M48 24c0 19.205-4.795 24-24 24S0 43.205 0 24 4.795 0 24 0s24 4.795 24 24z' fill='%23000' /%3E%3C/svg%3E");
         
    }
    <p>Original</p>
    <div class="logo"></div>
    <p>Fixed</p>
    <div class="logo2"></div>

    Your mask svg can be reduced to the mask shape itself:

    <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48">
      <path d="M48 24c0 19.205-4.795 24-24 24S0 43.205 0 24 4.795 0 24 0s24 4.795 24 24z" fill="#000" />
    </svg>
    

    You can also use Yoksel's data-URL converter.
    This way, your data-URL is more readable.