Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Off-center rendering of inline SVG on iOS Safari

Edit: dev link removed, giving up on this question.

I've been trying to solve a seemingly tiny rendering issue for a week now, and have exhausted all my options, here's my cry for help. I've read all related questions on SO, yet still did not manage to solve this problem.

Goal
My goal is to render a simple symmetrically shaped SVG icon inline on a web page. The SVG is inside a wrapper which has a background color and some padding. This is what a correct rendering would look like:

enter image description here

Above is a magnified view in Chrome of what is a correct rendering. Note how the icon is positioned correctly, it is not off-center in any way.

Note that I am specifically using a small padding and big contrast in color to visualize the problem, as it is a subtle yet disturbing problem.

Problem
The above correct rendering is consistent across desktop browsers on Windows (Firefox, Chrome, Edge) as well as Chrome and Firefox on Android. It only renders incorrectly on iOS Safari. Here's an example of an incorrect rendering:

enter image description here

The above is a magnified screenshot from an iPhone 6S, iOS 11. These are 3 instances of the same icon on the same page. Note how each rendition is incorrect in being off-center. Note also how it's not even consistent in how it renders off-center, it seems almost random.

The icon itself
The icon itself comes from Symbolicons. I checked the vector itself to be sure that it has no spacing in it: enter image description here

It touches the borders, and is fitting geometrically in a viewbox of 24x24. I checked a few other icons in this icon pack, and I'm facing the same problem with other icons, yet only in iOS Safari. So I don't think there's a problem in the SVG itself.

Problem details
A bit more detail on iOS Safari behavior. I tested on iOS 10 and 11, iPhone 5, iPhone 6S, iPad Pro 10", iPad Pro 12". The incorrectness of the rendering seems to differ on the size of the device and its orientation. For example, the iPhone5 is the only one having a perfect rendering, yet when turning it into landscape mode and refreshing the page, it fails. On the iPads, it pretty much always fails yet it can differ from a subpixel of to way off, depending on the size of the screen and its orientation.

This behavior is perhaps a hint that some scaling effect is at work.

A solid baseline
The page I'm integrating these icons on is relatively complicated, with possibly many factors influencing rendering, so I started off with a minimum test case:

https://codepen.io/fchristant/pen/PQKWww

I tested this codepen across all iOS devices and they lead to a perfect rendering in any scenario, no off-center issues. Note how the codepen takes full control of rendering, using pixels instead of relative values:

.icon-wrap {
    display:block;
    background:green;
    margin:0;
    padding:0;
    width:16px;
    height:16px;
    border:1px solid red;
    box-sizing:content-box;
    padding:4px;
    margin-bottom:20px;
}

.myicon {
    display:block;
    width:100%;
    height:100%;
    padding:0;
    margin:0;
    border:1px solid purple;
    box-sizing:border-box;
}

Furthermore, both the wrapper and SVG are display:block, to avoid any spacing issues.

As said, this minimum test case works perfectly. Which means its possible to correctly render this scenario on mobile Safari.

Yet when integrating it back into my page, it fails. I've spent days chasing conditions in my page that may affect it, and am running out of options. Here are some of the things I experimented with:

  • Setting width / height on the SVG itself, despite also having it in CSS. Does not seem to matter.
  • Trying different values for preserveAspectRatio on the SVG: makes no difference
  • Setting the SVG version: no differences
  • Variations of position relative/absolute: no difference
  • Instead of width/height:100%, using hardcoded pixels: no difference
  • Placing it inside specific layout containers or outside (flexbox, grid): sometimes changes rendering, but still never consistently correct.
  • Playing around with meta viewport values: no difference
  • Trying different values for shape-rendering: no difference

I've considering that this may be a subpixel rounding issue, but logically that makes no sense. I'm using hardcoded dividable-by-2 pixel values everywhere. Plus, the original codepen works.

Bottom line: between the working codepen and my test page, there is some race condition that triggers the incorrect rendering, and I haven't found it despite days of searching.

Test page
Here's the test page: [removed]

It's on my dev server. I'll try to keep it up whilst the question gets activity, if any. You can find the "globe" icon positioned on some of the thumbnail on the page. Unfortunately, you can only see the problem on a real iOS device, and only by zooming in as far as you can.

And yes, I know it seems absurd to go into extreme lengths to solve such a tiny issue, but this one really is throwing me off. It sticks out like a sore thumb once you see it. Plus, knowing that Safari can render this correctly, as demonstrated in the codepen, makes me hopeful that this can be solved.

I would be most grateful for a structural fix. I've had some tries with one-off fixes, for example by reducing or increasing 1px of size on the outer layout container. These kind of solutions solve it in one device/orientation, yet create new problems in the other scenarios. I'm hoping to consistently render such icons no matter in which context I put it. All browsers can do it, yet not mobile Safari. Well, Safari can (see codepen), yet there's something I'm doing that triggers it into behaving badly, and I have no idea what it is.

Edit: Suggestion was to replace the SVG with a CSS box, to see if this also suffers from the rendering glitch. Here a screenshot of that situation, it renders perfectly:

enter image description here

So it looks like it really is SVG-related.

like image 524
Fer Avatar asked Feb 19 '18 20:02

Fer


1 Answers

Well, try this...

I see that the wrapping span has width and height equal to the svg dimensions. However you have 1px padding. Unfortunately this is in the blind since we can't test it on our own. Try this:

.c_observation__indicator--country .c_observation__icon {
  background: #000;
  border-radius: 50%;
  width:25px;
  height:25px;
  padding:1px;
}
like image 99
scooterlord Avatar answered Nov 08 '22 18:11

scooterlord