【问题标题】:Keep SVG element on exact pixel将 SVG 元素保持在精确的像素上
【发布时间】:2014-12-20 16:47:31
【问题描述】:

我有一个 SVG 元素,可以将项目绘制到精确的像素。当元素本身被放置在 DOM 中的一个精确像素上时,它在所有主流浏览器中都不会出现锯齿。但是,当元素的祖先中有任何子像素偏移时,它就会变得混叠。

我可以通过将形状渲染设置为清晰边缘或优化速度来防止在大多数浏览器中出现锯齿,但是如果 SVG 以错误的方向四舍五入,可能会使 SVG 的内容错位 1 个像素,因此像素行可能是错过了图片的顶部或侧面。

我可以使用 el.getBoundingClientRect() 解决问题并调整边距以消除子像素偏移。这工作一次,但如果元素在 dom 中移动 - 通过滚动、拖动等,则必须重新应用该方法。这意味着监听 DOM,这似乎效率不高。

我想找到一个 CSS 规则,或者我可以将 SVG 包裹在其中以强制将其定位在精确像素处的元素。我想知道是否有一些原生元素 - 例如一个复选框,浏览器可能会为了自己的渲染目的而强制在一个精确的像素上渲染。然后我可以将 SVG 相对于那个对齐......

http://codepen.io/anon/pen/HvCcK(这个问题在Firefox中得到最好的演示)

HTML:

Crisp on FF and Chrome/Safari:<br/>
<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block;"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>

<br/>


<div class='offpixel'>
Blurry on Firefox (not on exact pixel):<br/>

<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block;"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>

<br/>
Crisp on Firefox - but not properly drawn: (not on exact pixel, but uses shape-rendering):<br/>       
<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block; shape-rendering: crispedges"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>

</div>

CSS:

body{
    font-family:sans-serif;
    font-size:10px;
}
.offpixel {
    padding:3.5px;
}

【问题讨论】:

  • 你能用一个相对位置,然后用一些 CSS 来圆整吗?就像总是产生 int 的计算规则一样?
  • 你解决了吗?
  • @JorisMans 我最近找到了一个简单的解决方案。看看我的回答吧。希望它仍然对您有所帮助,因为您的评论还不算太旧...

标签: html css svg


【解决方案1】:

我也为此搜索了解决方案。似乎没有人对此有答案。无论是在 stackoverflow 上还是在互联网的其余部分上。然而解决方案竟然如此简单......

正如您已经猜到的那样,Firefox 不会将 SVG 与像素栅格对齐。但是,它会对齐通过 CSS 转换规则转换的元素。因此,只需将 svg 转换 0 像素,它就会与像素栅格对齐。我在您的代码中附加了一个公开此技术的示例。

body{
    font-family:sans-serif;
    font-size:10px;
}
.offpixel {
    padding:3.5px;
}
.crisp {
    transform: translate(0, 0);
}
<div class="crisp">
<!-- ^^ Reset. Just in case this snippet adds some unwanted subpixel offset -->
Crisp on FF and Chrome/Safari:<br/>
<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block;"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>

<br/>


<div class='offpixel'>
Blurry on Firefox (not on exact pixel):<br/>

<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block;"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>

<br/>
Crisp on Firefox - but not properly drawn: (not on exact pixel, but uses shape-rendering):<br/>       
<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block; shape-rendering: crispedges"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>
<br/>
Crisp on Firefox and correctly drawn (uses transform snapping):<br/>

<div id="s2" style="width:21px; height:7px; background-color:#FFFFFF;">
    <svg class="crisp" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" overflow="hidden" viewBox="0 0 50 70" preserveAspectRatio="xMinYMin" style="display: block;"><defs></defs><g style="display: block;">
    <rect x="0" y="0" width="100%" height="100%" fill="red" stroke="none"></rect>
    <path d="M10 10 L 40 10  40 20  20 20  20 30  40 30  40 60  10 60  10 50  30 50  30 40  10 40 Z" fill="white" stroke="none"></path>
    </g></svg>
</div>

</div>
</div>

【讨论】:

  • 这是一个有趣的副作用。
【解决方案2】:

您有设计问题,而不是标记/样式问题。

渲染您的 SVG 代码像素完美的责任应该是 SVG 代码、页面代码和浏览器行为的共同责任。

所以我想说,保持 SVG 代码不变,因为它是像素完美的。

页面和标记设计应该是像素完美的,所以在更高级别的设计中没有 3.5px 值。

那么你仍然有滚动/缩放问题,我认为 getBoundingClientRect 方法是正确的。但是如果你害怕性能,可以将它附加到一个计时器事件中。

【讨论】:

  • 我在一个应用程序的上下文中,它使用 em 单位进行大多数填充和边距等。这样做是为了通过字体大小控制比例。这是页面上唯一需要像素完美对齐的元素。这是无法改变的。我正在寻找解决浏览器错误的方法,因为 Chrome 和 Safari 运行正常。我正在寻找比计时器或侦听器更好的解决方案,然后使用 getBoundingClientRect() 进行对齐。感谢您考虑这一点!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
  • 2012-04-30
  • 2014-01-28
  • 2019-11-14
  • 2014-05-13
  • 2021-11-29
相关资源
最近更新 更多