将SVG元素保留在精确像素上

Piw*_*aka 7 html css svg

我有一个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>
Run Code Online (Sandbox Code Playgroud)

CSS:

body{
    font-family:sans-serif;
    font-size:10px;
}
.offpixel {
    padding:3.5px;
}
Run Code Online (Sandbox Code Playgroud)

Sci*_*dix 8

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

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

body{
    font-family:sans-serif;
    font-size:10px;
}
.offpixel {
    padding:3.5px;
}
.crisp {
    transform: translate(0, 0);
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

  • 这是一个有趣的副作用。 (2认同)

Pie*_*r21 2

您遇到的是设计问题,而不是标记/样式问题。

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

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

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

那么您仍然遇到滚动/缩放问题,我认为 getBoundingClientRect 方法是正确的方法。但如果您担心性能,可以将其附加到计时器事件。

  • 我所在的应用程序使用 em 单位来表示大多数填充和边距等。这样做是为了通过字体大小控制比例。这是页面上唯一需要像素完美对齐的元素。这是无法改变的。我正在寻找解决浏览器错误的方法,因为 Chrome 和 Safari 表现正常。我正在寻找比计时器或侦听器更好的解决方案,然后使用 getBoundingClientRect() 进行对齐。不过还是感谢您考虑这一点! (2认同)