<!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.
The first image is with the page scale of 110%, the second - 100%, third - 90%. Why is it that blurry on 100% page scale?
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