【问题标题】:Off-center rendering of inline SVG on iOS SafariiOS Safari 上内联 SVG 的偏心渲染
【发布时间】:2018-02-19 20:14:13
【问题描述】:

编辑:开发者链接被删除,放弃这个问题。

一个星期以来,我一直在尝试解决一个看似很小的渲染问题,并且已经用尽了所有选择,这是我的求助。我已经阅读了关于 SO 的所有相关问题,但仍然无法解决这个问题。

目标
我的目标是在网页上内嵌一个简单的对称形状的 SVG 图标。 SVG 位于具有背景颜色和一些填充的包装器内。这是正确渲染的样子:

以上是 Chrome 中正确渲染的放大视图。请注意图标是如何正确定位的,它不会以任何方式偏离中心。

请注意,我专门使用小填充和大对比来可视化问题,因为这是一个微妙但令人不安的问题。

问题
上述正确渲染在 Windows 上的桌面浏览器(Firefox、Chrome、Edge)以及 Android 上的 Chrome 和 Firefox 上是一致的。它仅在 iOS Safari 上无法正确呈现。下面是一个错误渲染的例子:

以上是 iPhone 6S、iOS 11 的放大截图。这是同一页面上相同图标的 3 个实例。请注意每个演绎在偏离中心时是如何不正确的。另请注意,它在偏离中心的渲染方式上什至不一致,看起来几乎是随机的。

图标本身
图标本身来自 Symbolicons。我检查了向量本身以确保它没有间距:

它触及边界,并且在几何上适合 24x24 的视图框。我检查了这个图标包中的一些其他图标,我在其他图标上遇到了同样的问题,但只在 iOS Safari 中。所以我认为 SVG 本身没有问题。

问题详情
关于 iOS Safari 行为的更多细节。我在 iOS 10 和 11、iPhone 5、iPhone 6S、iPad Pro 10"、iPad Pro 12" 上进行了测试。渲染的不正确性似乎因设备的大小及其方向而异。比如 iPhone5 是唯一一个渲染完美的,但是当它变成横向模式并刷新页面时,它就失败了。在 iPad 上,它几乎总是失败,但它可能会因屏幕大小及其方向而异。

这种行为可能暗示某种缩放效应在起作用。

坚实的基线
我集成这些图标的页面比较复杂,可能影响渲染的因素很多,所以我从一个最小的测试用例开始:

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

我在所有 iOS 设备上测试了这个 codepen,它们在任何情况下都能实现完美的渲染,没有偏离中心的问题。请注意 codepen 如何完全控制渲染,使用像素而不是相对值:

.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;
}

此外,包装器和 SVG 都是 display:block,以避免任何间距问题。

如前所述,这个最小测试用例完美运行。这意味着它可以在移动 Safari 上正确呈现此场景。

然而,当它重新集成到我的页面时,它失败了。我花了几天时间在我的页面中寻找可能影响它的条件,并且我已经没有选择了。以下是我尝试过的一些东西:

  • 在 SVG 本身上设置宽度/高度,尽管它也在 CSS 中。似乎无关紧要。
  • 在 SVG 上尝试不同的 preserveAspectRatio 值:没有区别
  • 设置 SVG 版本:无差异
  • 相对/绝对位置的变化:没有区别
  • 使用硬编码像素代替宽度/高度:100%:没有区别
  • 将其放置在特定布局容器内或外部(flexbox、网格):有时会更改渲染,但始终不能始终正确。
  • 使用元视口值:没有区别
  • 尝试不同的形状渲染值:没有区别

我考虑过这可能是一个亚像素舍入问题,但从逻辑上讲这没有任何意义。我到处都在使用硬编码的可除以 2 的像素值。另外,原始的 codepen 可以工作。

底线:在工作的 codepen 和我的测试页面之间,有一些竞争条件触发了不正确的渲染,尽管搜索了几天,我还是没有找到它。

测试页面
这是测试页面: [已删除]

它在我的开发服务器上。我会尽量保持它,而问题得到活动,如果有的话。您可以在页面上的某些缩略图上找到“地球”图标。不幸的是,您只能在真正的 iOS 设备上看到问题,并且只能尽可能放大。

是的,我知道为了解决这么一个小问题而竭尽全力解决这个问题似乎很荒谬,但这个问题真的让我很反感。一旦你看到它,它就会像疼痛的拇指一样伸出来。另外,正如 codepen 中所展示的那样,知道 Safari 可以正确呈现这个问题,让我希望这个问题可以得到解决。

如果能提供结构性修复,我将不胜感激。我已经尝试过一次性修复,例如在外部布局容器上减小或增加 1px 的大小。这些解决方案在一个设备/方向上解决了它,但在其他场景中产生了新问题。无论我把它放在哪个上下文中,我都希望能够始终如一地呈现这样的图标。所有浏览器都可以做到,但移动版 Safari 则不行。好吧,Safari 可以(见 codepen),但我正在做的事情会触发它表现不佳,我不知道它是什么。

编辑:建议将 SVG 替换为 CSS 框,看看这是否也受到渲染故障的影响。这是该情况的屏幕截图,它完美呈现:

所以看起来它确实与 SVG 相关。

【问题讨论】:

  • 我在测试页面上看到.c_observation__icon svg 的 CSS 规则 width/height=24.5px,而封闭跨度设置为 24px。这至少与您的说法“硬编码的可除以 2 像素值无处不在”相反。
  • @ccprog 很抱歉,这是尝试亚像素舍入效果的遗留问题。现在删除该宽度,使其占用 100%。需要明确的是,无论有没有这个声明,问题仍然存在。
  • 如果将 SVG 替换为纯色 CSS 框或嵌入图像,问题是否仍然存在?
  • @Ferdy 对设备和方向的依赖可能与分辨率有关。 WebKit 正在调整 SVG 的确切位置以与屏幕像素对齐,这将其移动到足以使其不在父元素的填充中居中的程度。但除此之外,除了在 WebKit (bugs.webkit.org) 上提交错误之外,我没有任何建议。
  • 在您的代码笔中,您没有将版本声明为 SVG 属性。不确定这是否会在不测试代码的情况下导致渲染问题,但也许您可以自己找出答案。通常 - version="1.1" - 现在用于 SVG。

标签: css svg mobile-safari


【解决方案1】:

在添加之前,我遇到了完全相同的问题:

svg {
  -webkit-transform: translate(0px,0px); /* Safari and Chrome */
}

我希望这能解决其他人的问题!

【讨论】:

  • @Fer 这应该是公认的答案。
【解决方案2】:

免责声明:我留下答案是因为我没有发表评论的声誉,但我无法知道这是否适用于 OP 的特定问题,此外这不是解决方案,而是更多尝试解决问题的探索方向。

我知道这个问题现在已经相当老了,但是我在 Safari for iOs 中遇到了 SVG 对齐问题,我设法用一点 JavaScript 解决了它。由于测试页面已经消失,我无法评论如何在您的特定情况下应用它,但这是一个想法:

通过四处寻找,我注意到 iOs 上的 Safari 在我想要将其他 SVG 元素居中的元素上调用 getBoundingClientRect() 时返回错误的尺寸和定位。我以 250 毫秒的延迟将调用置于超时状态,然后它返回正确的边界矩形,然后我可以在浏览器中正确且一致地对齐我的元素。关键是 Safari 的 SVG 定位代码中似乎存在竞争条件,所以这个错误可能也会影响您的图标。

如果它可以在您的项目上下文中工作,我建议尝试强制 Safari 在 DOM 加载后几百毫秒重新布局 SVG。

【讨论】:

    【解决方案3】:

    好吧,试试这个……

    我看到包装 spanwidthheight 等于 svg 尺寸。但是,您有 1px 填充。不幸的是,这是盲目的,因为我们无法自己测试它。试试这个:

    .c_observation__indicator--country .c_observation__icon {
      background: #000;
      border-radius: 50%;
      width:25px;
      height:25px;
      padding:1px;
    }
    

    【讨论】:

    • 谢谢。刚刚尝试过(现在恢复),但不幸的是它没有任何区别。图标本身仍然在填充框内的各个方向移动。
    • @Ferdy 没有必要恢复它,因为这是正确的做法。您是否尝试过将position:relative 应用于父跨度并将position:absolute;top:1px;left:1px 应用于svg
    • 它是否正确取决于盒子大小。两种类型都没有区别。作为调查的一部分,我确实修改了绝对定位,但它并没有解决问题。如屏幕截图所示,每个图标实例的错位都不同。重新定位可能会修复第一个,但在下一个或什至在不同的分辨率设备上将其丢弃。
    【解决方案4】:

    这可能是一个框外类型的答案,但它可能有帮助..虽然它有点hacky..我只是建议这个答案,因为它似乎你有它在所有其他Safari 以外的其他浏览器,如果你修改太多,可能会在其他浏览器上产生新问题。

    您可以尝试使用 javascript 和一点点 jquery 来帮助解决您的问题。您可以使用它们来检测您使用的浏览器,然后您可以从那里对样式进行微调。您还可以检测横向模式。这是一个 stackoverflow 答案,可帮助您开始如何检测浏览器:

    How to detect Safari, Chrome, IE, Firefox and Opera browser?

    一旦您弄清楚如何检测 safari,您就可以使用 jquery 将 css 样式应用于您的 div 和图像。因此,无论您在 safari 上对该 div 做什么,都不会干扰您使用其他浏览器所做的工作。

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    <script>
        $(document).ready(){
    
            var isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification));
    
            if (isSafari) {
                if(window.innerHeight > window.innerWidth){
                    //portrait mode
                    $('.icon-wrap').css({
                        ... your css for safari code here ...
                    });
    
                    $('.myicon').css({
                        ... your css for safari code here ...
                    });
                } 
                else {
                    //landscape mode
                    $('.icon-wrap').css({
                        ... your css for safari code here ...
                    });
    
                    $('.myicon').css({
                        ... your css for safari code here ...
                    });
                }
            }
        }
    </script>
    

    【讨论】:

    • 感谢您的努力。一个非常沉重的解决方案,但我的主要反对意见是它不能解决问题。我所知道的没有专门针对 iOS Safari 修复它的 CSS。这不像我总是可以偏移 1px 或类似的东西来让它工作。每个图标实例的对齐和越界渲染都不同。
    • 嗯,工作量很大,您可能希望对所有这些实例都这样做。尽可能多地覆盖所有基础。您可以为有问题的设备创建特定的样式表,并根据需要将它们拉出来。与 iPhone 大小相同的设备上的 Google Chrome 是否会发生这种情况?如果是,您必须解决它。您的问题实际上是人们制作其网站的应用版本的众多原因之一。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 2014-01-28
    相关资源
    最近更新 更多