cssreactjsimagesvg

SVG image is blurry at 100% pages scale but when I zoom in/out it gets normal


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Icon Button Snippet</title>
    <style>

        .icon-btn {
            display: flex;
            justify-content: center;
            align-items: center;
            border: 1px solid transparent;
            padding: 0;
        }

        .sizeMdLg {
            width: 22px;
            height: 22px;
        }

        .icon-btn.sizeXl {
            height: 54px;
            min-width: 54px;
        }

        .icon-btn.radiusFull {
            border-radius: 50%;
        }

        .whiteBorderedDark {
            background-color: white;
            border-color: gray;
        }

        .whiteBorderedDark:hover {
            color: var(--color-neutral-700);
        }

        .icon {
            display: block;
        }


        .border {
            border: none;
            box-shadow: 0 0 0 1px var(--color-blue-50);
        }

        .notificationsBtnWrp {
            position: relative;
        }
    </style>
</head>
<body>

    <div class="notificationsBtnWrp border">
        <button type="button" class="icon-btn whiteBorderedDark sizeXl radiusFull">
            <svg
                width="22px"
                height="22px"
                class="icon sizeMdLg dark"
              
                viewBox="0 0 22 22"
                xmlns="http://www.w3.org/2000/svg"
            >
                <path d="M3.667 17.416v-1.833H5.5V9.166q0-1.902 1.146-3.38a5.3 5.3 0 0 1 2.98-1.936v-.642q0-.573.4-.974.402-.4.974-.401.573 0 .974.401.402.4.401.974v.642a5.3 5.3 0 0 1 2.98 1.936Q16.5 7.264 16.5 9.166v6.417h1.834v1.833zM11 20.166q-.756 0-1.294-.538a1.77 1.77 0 0 1-.539-1.295h3.667q0 .756-.539 1.295-.538.538-1.295.538m-3.666-4.583h7.333V9.166q0-1.512-1.077-2.59Q12.513 5.5 11 5.5T8.41 6.577t-1.076 2.59z"/>
            </svg>
        </button>
    </div>

</body>
</html>

I am struggling to understand why the svg image inside a button in my React app looks blurry when I don't zoom the page in/out, but when I change the scale (110%, 90%) it starts looking normal.

enter image description here

enter image description here

enter image description here

The first image is with the page scale of 110%, the second - 100%, third - 90%. Why is it that blurry on 100% page scale?


Solution

  • As explained by Robert Longson:
    The path geometry doesn't fit very well in the ultimate pixel grid. The render will ultimately produce a lot of interpolated color values due to anti-aliasing – the rendering becomes blurry.

    The used icon was most likely designed on a 24x24 px grid and scaled to 22x22 px – producing a lot of floating point coordinates.

    A quick workaround could be to slightly increase the layout size to 24px:

    .icon-btn {
      display: flex;
      justify-content: center;
      align-items: center;
      border: 1px solid transparent;
      padding: 0;
    }
    
    .sizeMdLg {
      width: 22px;
      height: 22px;
    }
    
    .icon-btn.sizeXl {
      height: 54px;
      min-width: 54px;
    }
    
    .icon-btn.radiusFull {
      border-radius: 50%;
    }
    
    .whiteBorderedDark {
      background-color: white;
      border-color: gray;
    }
    
    .whiteBorderedDark:hover {
      color: var(--color-neutral-700);
    }
    
    .icon {
      display: block;
    }
    
    .border {
      border: none;
    }
    
    .notificationsBtnWrp {
      position: relative;
    }
    <h3>Original - scaled to 24px layout</h3>
    
    <div class="notificationsBtnWrp border">
      <button type="button" class="icon-btn whiteBorderedDark sizeXl radiusFull">
        <svg style="width:24px;height:24px" class="icon sizeMdLg dark" viewBox="0 0 22 22">
          <path d="M3.667 17.416v-1.833H5.5V9.166q0-1.902 1.146-3.38a5.3 5.3 0 0 1 2.98-1.936v-.642q0-.573.4-.974.402-.4.974-.401.573 0 .974.401.402.4.401.974v.642a5.3 5.3 0 0 1 2.98 1.936Q16.5 7.264 16.5 9.166v6.417h1.834v1.833zM11 20.166q-.756 0-1.294-.538a1.77 1.77 0 0 1-.539-1.295h3.667q0 .756-.539 1.295-.538.538-1.295.538m-3.666-4.583h7.333V9.166q0-1.512-1.077-2.59Q12.513 5.5 11 5.5T8.41 6.577t-1.076 2.59z" />
        </svg>
      </button>
    </div>
    
    
    <h3>Original</h3>
    
    <div class="notificationsBtnWrp border">
      <button type="button" class="icon-btn whiteBorderedDark sizeXl radiusFull">
        <svg width="22px" height="22px" class="icon sizeMdLg dark" viewBox="0 0 22 22" >
          <path d="M3.667 17.416v-1.833H5.5V9.166q0-1.902 1.146-3.38a5.3 5.3 0 0 1 2.98-1.936v-.642q0-.573.4-.974.402-.4.974-.401.573 0 .974.401.402.4.401.974v.642a5.3 5.3 0 0 1 2.98 1.936Q16.5 7.264 16.5 9.166v6.417h1.834v1.833zM11 20.166q-.756 0-1.294-.538a1.77 1.77 0 0 1-.539-1.295h3.667q0 .756-.539 1.295-.538.538-1.295.538m-3.666-4.583h7.333V9.166q0-1.512-1.077-2.59Q12.513 5.5 11 5.5T8.41 6.577t-1.076 2.59z" />
        </svg>
      </button>
    </div>
    
    <h3>Optimized to integers - using strokes</h3>
    <div class="notificationsBtnWrp border">
      <button type="button" class="icon-btn whiteBorderedDark sizeXl radiusFull">
        <svg width="22px" height="22px" class="icon sizeMdLg dark" viewBox="0 0 22 22" xmlns="http://www.w3.org/2000/svg">
          <path d="m 3 16 h 16 m -13 0 v -7 a 5 5 0 1 1 10 0 v 7 m -5.5 -12.5 v -1 a 0.5 0.5 0 1 1 1 0 v 1 m 0.5 15.5 a 1 1 0 1 1 -2 0" style="fill:none; stroke:currentColor; stroke-width:2"  />
        </svg>
      </button>
    </div>

    Ideally, your icons are optimized for a common grid-size (e.g 24px) and use integer coordinates natively. But that's admittedly not always feasible - especially when the icon has many fine details.

    Sometimes it can help to upscale the geometry to a larger viewBox so all details can be rounded to integers. You can e.g use yqnn's svg-path-editor app