在具有不同 resolutions/scaling 的 SVG 和边框宽度之间保持相同大小和对齐的问题
Problem maintaining same size and alignment between SVG and border width with different resolutions/scaling
我必须制作各种对话泡泡,我已经为我提供了一个 SVG 用于指向演讲者的泡泡部分。我试图让盒子本身成为一个规则的边框 div(这个 div 将根据其内容具有动态高度和宽度,但是 SVG 将保持相同的大小)。
我做了类似于此 stackblitz 示例的操作:https://stackblitz.com/edit/angular-ivy-64a8xk 将 svg 绝对定位在 div 元素内并移动它,以便 SVG 路径与div 元素。
问题:
这在 Macbook Pro 2560x1600 上看起来不错:
但是当使用外接显示器或什至 Windows 带有 2560x1440 显示器的 PC 时,SVG 看起来并不完全对齐。
使用浏览器缩放时问题更加明显。这是 Windows PC 在 75% 缩放时的样子:
这里的边框好像缩小到了1px宽度,所以SVG路径看起来不仅没有对齐,而且尺寸也不对。
有没有办法让 SVG 的行为方式与 border-width 相同,以便它们始终对齐且大小相同?也许有其他方法可以达到同样的效果?
浏览器不会在 borders
上呈现 sub-pixels,但会在 SVG
上呈现。这意味着在 125% DPI 下缩放边框在技术上是 2.5px,但四舍五入为 2px。
解决这个问题的一种方法是添加 resolution media queries
.
@media (min-resolution: 120dpi) {
.box {
border-width: 2.5px;
}
}
演示:
https://stackblitz.com/edit/angular-ivy-vbqtnz
下面是缩放级别和相应 dpi 值的简短列表:
- 较小的 100%(默认)= 96 dpi
- 中 125% = 120 dpi
- 更大 150% = 144 dpi
- 超大 200% = 192 dpi
我不确定您对此能做些什么。 SVG 具有围绕缩放和 anti-aliasing 的行为,这与浏览器处理边框宽度缩放的方式不同。
一种解决方案(您可能不太喜欢)是通过关闭 anti-aliasing 让 SVG 的行为与边框的行为相似。您可以通过将 shape-rendering="crispEdges"
添加到 <path>
.
来完成此操作
<path
d="M43 37L38 37C38 37 34 29.6686 26 22.4215C18 15.1745 7.5 8.34577 5 10.3566C2.5 12.3674 5.5 15.8864 6 24.9351C6.5 33.9838 5 37 5 37L0 37"
stroke="currentcolor"
stroke-width="2"
shape-rendering="crispEdges"
/>
SVG 描边的大小将更接近边框宽度。但是路径的弯曲形状现在看起来“参差不齐”。
我的建议:将整个对话泡泡切换为相同的技巧。两者都 HTML,或者两者都是 SVG。
或者接受细微的差别。
您还可以通过使用 responsive/flexible 背景 svg 实现一致的边框渲染:
在这种情况下,您不会应用 viewBox
属性。
<rect>
元素(通过 rx
和 ry
的圆角将需要一个 y 偏移来为你的气泡的“尾巴”提供足够的 space)。
外部气泡边框元素只是通过 relative/absolute 位置上下文拉伸。
:root {
--stroke-width: 2;
--stroke-width-bg: 4;
--stroke-color: orange;
--bubble-bg:#fff;
}
* {
box-sizing: border-box;
}
body {
font-size: 5vmin;
line-height: 1.35em;
font-family: "Segoe UI", sans-serif;
}
.resize {
resize: both;
position: relative;
border: 1px solid #ccc;
overflow: auto;
padding: 1em;
width: 75vw;
margin: 0 auto;
}
.text-box {
position: relative;
border: none;
overflow: visible;
width: 100%;
padding: 40px 0 1em 0;
margin-bottom: 40px;
}
.text-box p {
margin: 0;
}
.text-box-left .svgBG {
transform: scale(-1, 1);
--stroke-color: blue;
--bubble-bg: #9edbfa;
}
.text-content {
position: relative;
padding-top: 3em;
padding: 0 1.5em;
z-index: 10;
}
.svgBG {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
height: 100%;
width: 100%;
overflow: visible;
padding-bottom: 1em;
}
<div class="resize">
<div class="text-box">
<svg class="svgBG">
<use href="#bubbleOuter" />
</svg>
<div class="text-content">
<h3>mdn webdocs: vector-effect</h3>
<p>The vector-effect property specifies the vector effect to use when drawing an object. Vector effects are applied before any of the other compositing operations, i.e. filters, masks and clips. <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vector-effect">readmore</a></p>
</div>
</div>
<div class="text-box text-box-left">
<svg class="svgBG">
<use href="#bubbleOuter" />
</svg>
<div class="text-content">
<h3>mdn webdocs: viewBox</h3>
<p>The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.
The value of the viewBox attribute is a list of four numbers: min-x, min-y, width and height. The numbers, which are separated by whitespace and/or a comma, specify a rectangle in user space which is mapped to the bounds of the viewport established for the associated SVG element (not the browser viewport). <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox">readmore</a></p>
</div>
</div>
<p style="text-align:right">resize me</p>
</div>
<svg class="svgAsset" style="position:absolute; width:0; height:0; visibility:hidden" overflow="visible">
<symbol viewBox="0 0 43 43" id="bubble">
<path d="M43 37 C38 37 34 29.6686 26 22.4215 C18 15.1745 7.5 8.34577 5 10.3566 C2.5 12.3674 5.5 15.8864 6 24.9351 C6.5 33.9838 5 37 5 37 z" />
</symbol>
<symbol id="bubbleOuter" overflow="visible">
<use class="bubble-bg" href="#bubble" x="40" y="-9" width="43" height="43" style="stroke-width:var(--stroke-width-bg); stroke:var(--stroke-color); fill:var(--bubble-bg)" />
<rect fill="#fff" stroke="#000" x="0" y="25" rx="8" ry="8" width="100%" height="100%" style="stroke-width:var(--stroke-width); stroke:var(--stroke-color); fill:var(--bubble-bg)" />
<use href="#bubble" x="40" y="-9" width="43" height="43" style="fill:var(--bubble-bg)" />
</symbol>
</svg>
但是:这种方法需要对填充和边距进行大量调整(取决于您的 svg 图形、布局等)。
我必须制作各种对话泡泡,我已经为我提供了一个 SVG 用于指向演讲者的泡泡部分。我试图让盒子本身成为一个规则的边框 div(这个 div 将根据其内容具有动态高度和宽度,但是 SVG 将保持相同的大小)。
我做了类似于此 stackblitz 示例的操作:https://stackblitz.com/edit/angular-ivy-64a8xk 将 svg 绝对定位在 div 元素内并移动它,以便 SVG 路径与div 元素。
问题:
这在 Macbook Pro 2560x1600 上看起来不错:
但是当使用外接显示器或什至 Windows 带有 2560x1440 显示器的 PC 时,SVG 看起来并不完全对齐。
使用浏览器缩放时问题更加明显。这是 Windows PC 在 75% 缩放时的样子:
这里的边框好像缩小到了1px宽度,所以SVG路径看起来不仅没有对齐,而且尺寸也不对。
有没有办法让 SVG 的行为方式与 border-width 相同,以便它们始终对齐且大小相同?也许有其他方法可以达到同样的效果?
浏览器不会在 borders
上呈现 sub-pixels,但会在 SVG
上呈现。这意味着在 125% DPI 下缩放边框在技术上是 2.5px,但四舍五入为 2px。
解决这个问题的一种方法是添加 resolution media queries
.
@media (min-resolution: 120dpi) {
.box {
border-width: 2.5px;
}
}
演示: https://stackblitz.com/edit/angular-ivy-vbqtnz
下面是缩放级别和相应 dpi 值的简短列表:
- 较小的 100%(默认)= 96 dpi
- 中 125% = 120 dpi
- 更大 150% = 144 dpi
- 超大 200% = 192 dpi
我不确定您对此能做些什么。 SVG 具有围绕缩放和 anti-aliasing 的行为,这与浏览器处理边框宽度缩放的方式不同。
一种解决方案(您可能不太喜欢)是通过关闭 anti-aliasing 让 SVG 的行为与边框的行为相似。您可以通过将 shape-rendering="crispEdges"
添加到 <path>
.
<path
d="M43 37L38 37C38 37 34 29.6686 26 22.4215C18 15.1745 7.5 8.34577 5 10.3566C2.5 12.3674 5.5 15.8864 6 24.9351C6.5 33.9838 5 37 5 37L0 37"
stroke="currentcolor"
stroke-width="2"
shape-rendering="crispEdges"
/>
SVG 描边的大小将更接近边框宽度。但是路径的弯曲形状现在看起来“参差不齐”。
我的建议:将整个对话泡泡切换为相同的技巧。两者都 HTML,或者两者都是 SVG。
或者接受细微的差别。
您还可以通过使用 responsive/flexible 背景 svg 实现一致的边框渲染:
在这种情况下,您不会应用 viewBox
属性。
<rect>
元素(通过 rx
和 ry
的圆角将需要一个 y 偏移来为你的气泡的“尾巴”提供足够的 space)。
外部气泡边框元素只是通过 relative/absolute 位置上下文拉伸。
:root {
--stroke-width: 2;
--stroke-width-bg: 4;
--stroke-color: orange;
--bubble-bg:#fff;
}
* {
box-sizing: border-box;
}
body {
font-size: 5vmin;
line-height: 1.35em;
font-family: "Segoe UI", sans-serif;
}
.resize {
resize: both;
position: relative;
border: 1px solid #ccc;
overflow: auto;
padding: 1em;
width: 75vw;
margin: 0 auto;
}
.text-box {
position: relative;
border: none;
overflow: visible;
width: 100%;
padding: 40px 0 1em 0;
margin-bottom: 40px;
}
.text-box p {
margin: 0;
}
.text-box-left .svgBG {
transform: scale(-1, 1);
--stroke-color: blue;
--bubble-bg: #9edbfa;
}
.text-content {
position: relative;
padding-top: 3em;
padding: 0 1.5em;
z-index: 10;
}
.svgBG {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
height: 100%;
width: 100%;
overflow: visible;
padding-bottom: 1em;
}
<div class="resize">
<div class="text-box">
<svg class="svgBG">
<use href="#bubbleOuter" />
</svg>
<div class="text-content">
<h3>mdn webdocs: vector-effect</h3>
<p>The vector-effect property specifies the vector effect to use when drawing an object. Vector effects are applied before any of the other compositing operations, i.e. filters, masks and clips. <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/vector-effect">readmore</a></p>
</div>
</div>
<div class="text-box text-box-left">
<svg class="svgBG">
<use href="#bubbleOuter" />
</svg>
<div class="text-content">
<h3>mdn webdocs: viewBox</h3>
<p>The viewBox attribute defines the position and dimension, in user space, of an SVG viewport.
The value of the viewBox attribute is a list of four numbers: min-x, min-y, width and height. The numbers, which are separated by whitespace and/or a comma, specify a rectangle in user space which is mapped to the bounds of the viewport established for the associated SVG element (not the browser viewport). <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox">readmore</a></p>
</div>
</div>
<p style="text-align:right">resize me</p>
</div>
<svg class="svgAsset" style="position:absolute; width:0; height:0; visibility:hidden" overflow="visible">
<symbol viewBox="0 0 43 43" id="bubble">
<path d="M43 37 C38 37 34 29.6686 26 22.4215 C18 15.1745 7.5 8.34577 5 10.3566 C2.5 12.3674 5.5 15.8864 6 24.9351 C6.5 33.9838 5 37 5 37 z" />
</symbol>
<symbol id="bubbleOuter" overflow="visible">
<use class="bubble-bg" href="#bubble" x="40" y="-9" width="43" height="43" style="stroke-width:var(--stroke-width-bg); stroke:var(--stroke-color); fill:var(--bubble-bg)" />
<rect fill="#fff" stroke="#000" x="0" y="25" rx="8" ry="8" width="100%" height="100%" style="stroke-width:var(--stroke-width); stroke:var(--stroke-color); fill:var(--bubble-bg)" />
<use href="#bubble" x="40" y="-9" width="43" height="43" style="fill:var(--bubble-bg)" />
</symbol>
</svg>
但是:这种方法需要对填充和边距进行大量调整(取决于您的 svg 图形、布局等)。