在具有不同 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> 元素(通过 rxry 的圆角将需要一个 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 图形、布局等)。

Codepen Example