目前正在构建一个基于浏览器的SVG应用程序。在这个应用程序中,用户可以设置各种形状的样式和位置,包括矩形。
当我将笔画宽度应用到SVG矩形元素(比如1px)时,不同的浏览器会以不同的方式将笔画应用到矩形的偏移和插入。这被证明是很麻烦的,特别是当我试图计算一个矩形的外部宽度和视觉位置,并将其放置在其他元素旁边时。
例如:
Firefox添加了1px的插入(底部和左侧)和1px的偏移(顶部和右侧)
Chrome添加了1px的插入(顶部和左侧),和1px的偏移(底部和右侧)
到目前为止,我唯一的解决方案是自己绘制实际的边界(可能是用路径工具),并将边界定位在描边元素的后面。但这种解决方案是一种令人不快的变通方法,如果可能的话,我宁愿不走这条路。
所以我的问题是,你能控制SVG的笔画宽度如何在元素上绘制吗?
不能,不能指定笔画在元素内部还是外部。我在2003年向SVG工作组提出了这个功能的建议,但是没有得到任何支持(或讨论)。
正如我在提案中提到的,
你可以通过加倍描边宽度来实现与“inside”相同的视觉效果,然后使用剪辑路径将对象剪辑到自身
你可以通过将描边宽度加倍,然后将对象的无描边副本叠加在其上,从而获得与“外部”相同的视觉效果。
编辑:这个答案将来可能是错误的。应该可以使用SVG矢量效果来实现这些结果,通过结合veStrokePath与veIntersect(用于“内部”)或与veExclude(用于“外部”)。然而,矢量效果仍然是一个工作草案模块,没有实现,我还能找到。
编辑2:SVG 2规范草案包括一个笔画对齐属性(在可能的值之外的|中有中心|)。这个特性可能最终会被应用到无人机中。
编辑3:有趣而令人失望的是,SVG工作组已经从SVG 2中删除了笔画对齐。您可以在这里看到文章之后描述的一些问题。
下面是一个函数,它将计算你需要添加多少像素-使用给定的笔画-到顶部,右侧,底部和左侧,所有这些都基于浏览器:
var getStrokeOffsets = function(stroke){
var strokeFloor = Math.floor(stroke / 2), // max offset
strokeCeil = Math.ceil(stroke / 2); // min offset
if($.browser.mozilla){ // Mozilla offsets
return {
bottom: strokeFloor,
left: strokeFloor,
top: strokeCeil,
right: strokeCeil
};
}else if($.browser.webkit){ // WebKit offsets
return {
bottom: strokeCeil,
left: strokeFloor,
top: strokeFloor,
right: strokeCeil
};
}else{ // default offsets
return {
bottom: strokeCeil,
left: strokeCeil,
top: strokeCeil,
right: strokeCeil
};
}
};
Xavier Ho的解决方案是将笔画宽度增加一倍,并改变着色顺序,尽管只有在填充颜色为纯色且不透明的情况下才有效。
我已经开发了其他方法,更复杂,但适用于任何填充。它也适用于椭圆或路径(后者存在一些具有奇怪行为的角落情况,例如交叉自己的开放路径,但并不多)。
诀窍是在两层中显示形状。一个没有笔画(只有填充),另一个只有两倍宽度的笔画(透明填充),并通过一个遮罩,显示整个形状,但隐藏了没有笔画的原始形状。
<svg width="240" height="240" viewBox="0 0 1024 1024">
<defs>
<path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z"/>
<mask id="mask">
<use xlink:href="#ld" stroke="#FFFFFF" stroke-width="160" fill="#FFFFFF"/>
<use xlink:href="#ld" fill="#000000"/>
</mask>
</defs>
<g>
<use xlink:href="#ld" fill="#00D2B8"/>
<use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="red" mask="url(#mask)"/>
</g>
</svg>
这里是一个关于内边框矩形使用符号和使用的工作。
例如:https://jsbin.com/yopemiwame/edit?html,输出
SVG:
<svg>
<symbol id="inner-border-rect">
<rect class="inner-border" width="100%" height="100%" style="fill:rgb(0,255,255);stroke-width:10;stroke:rgb(0,0,0)">
</symbol>
...
<use xlink:href="#inner-border-rect" x="?" y="?" width="?" height="?">
</svg>
注意:一定要替换?用真正的价值。
背景:这样工作的原因是因为symbol通过用svg替换symbol并在shadow DOM中创建一个元素来建立一个新的视口。阴影DOM的svg随后链接到当前svg元素。注意,svg可以嵌套,并且每个svg都会创建一个新的视口,它会剪辑所有重叠的部分,包括重叠的边界。要想更详细地了解正在发生的事情,请阅读Sara Soueidan的这篇精彩文章。