【问题标题】:SVG fails to size properly in absolutely positioned parentSVG 无法在绝对定位的父级中正确调整大小
【发布时间】:2017-10-18 15:31:51
【问题描述】:

我遇到了这样一个问题:当内联 <svg> 元素被包裹在绝对定位的父元素中时,它不会拉伸到其原生大小,正如其 viewBox 属性中所声明的那样:

  • 使用width: 100% 似乎只会强制SVG 拉伸到浏览器定义的默认大小300px。这也会导致 <img> 无法调整到其原始尺寸。
  • 使用 width: auto 会导致 SVG 完全折叠成 0px x 0px 的尺寸,但 <img> 现在的尺寸已调整为其原始尺寸

有趣的是,可以通过将 SVG 用作 src 元素的 src 属性的 data:image/svg+xml 来复制此行为,因此 SVG 似乎不会将其本机尺寸“传递”到其包含的父级(无论是 <svg> 还是 <img> 元素)。

所以,我的问题是,如果 CSS 中有任何可靠的方法可以根据其视图框属性强制 SVG 调整到其原生大小。我可以通过阅读viewBox 属性和use the fixed aspect ratio hack 以将我的SVG 显示为固定纵横比<div> 元素的背景图像来使用JS 蛮力,但我尽量避免这样做。我可能误解了浏览器对 SVG 规范的实现,但我似乎找不到解决方法。


我的问题可以在下面的代码 sn-p 中重现。你可以:

  • 使用页面顶部的复选框打开/关闭父级的绝对定位
  • <img><svg> 元素上选择width 声明(自动或100%)

// The JS logic below is only used to dynamically set styles based on checkbox/select changes, has nothing to do with SVG layout

// Change positioning strategy
document.getElementById('absPosToggle').addEventListener('change', function() {
  var parents = document.querySelectorAll('.parent');
  
  if (this.checked) {
    for (var i = 0; i < parents.length; i++) {
      parents[i].classList.remove('no-absolute-positioning');
    }
  } else {
    for (var i = 0; i < parents.length; i++) {
      parents[i].classList.add('no-absolute-positioning');
    }
  }
});

// Change width declaration of <svg>/<img> elements
document.getElementById('widthSetting').addEventListener('change', function() {
  var images = document.querySelectorAll('img, svg');
  var value = this.options[this.selectedIndex].value;
  
  if (value === '100%') {
    for (var i = 0; i < images.length; i++) {
      images[i].classList.add('width--100');
    }
  } else {
    for (var i = 0; i < images.length; i++) {
      images[i].classList.remove('width--100');
    }
  }
});
body {
  margin: 0;
  padding: 50px 0 0 0;
}

form {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  display: block;
  background-color: #fff;
  z-index: 1;
  padding: 5px;
}

.wrapper {
  width: 100%;
  height: 250px;
  background-color: #eee;
  margin-bottom: 10px;
  position: relative;
  text-align: center;
}

.parent {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.parent.no-absolute-positioning {
  position: relative;
  top: 0;
  left: 0;
  transform: none;
}

img,
svg {
  display: block;
  width: auto;
}

img.width--100,
svg.width--100 {
  width: 100%;
}
<form>
  <label><input type="checkbox" id="absPosToggle" checked />Toggle absolute positioning</label><br />
  <label for="widthSetting">Set svg/img widths to:</label><select id="widthSetting">
    <option value="auto">Auto</option>
    <option value="100%">100%</option>
  </select>
</form>

<!-- <img> -->
<div class="wrapper">
  <div class="parent">
    <img src="https://via.placeholder.com/500x150/173755/ffffff" />
  </div>
  <span>This is an <code>&lt;img&gt;</code> element</span>
</div>

<!-- Inline <svg> -->
<div class="wrapper">
  <div class="parent">
    <svg viewBox="0 0 500 150" xmlns="http://www.w3.org/2000/svg"><rect x="0" y="0" width="500" height="150" fill="#b13131" /><g transform="translate(250, 75)"><text fill="#ffffff" style="text-anchor: middle; font-size: 50; font-family: Arial;" dy="0.35em">500 x 150</text></g></svg>
  </div>
  <span>This is an inline <code>&lt;svg&gt;</code> element</span>
</div>

<!-- <img> with SVG as data:image -->
<div class="wrapper">
  <div class="parent">
    <img src="data:image/svg+xml;charset=utf8,%3Csvg%20viewBox=%220%200%20500%20150%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%3Crect%20x=%220%22%20y=%220%22%20width=%22500%22%20height=%22150%22%20fill=%22#b13131%22%20/%3E%3Cg%20transform=%22translate(250,%2075)%22%3E%3Ctext%20fill=%22#ffffff%22%20style=%22text-anchor:%20middle;%20font-size:%2050;%20font-family:%20Arial;%22%20dy=%220.35em%22%3E500%20x%20150%3C/text%3E%3C/g%3E%3C/svg%3E" 
    />
  </div>
  <span>This is an <code>&lt;img&gt;</code> element with SVG as data:image</span>
</div>

【问题讨论】:

  • 很好的问题。向 SVG 添加宽度和高度属性不是一种选择吗?您是否已经通过css-tricks.com/scale-svg,看看是否有任何建议可以解决问题?我认为问题的根本原因是,通过绝对定位,您使父级的宽度计算方法变得适合,并且 内容也没有适当的内在宽度,这很好捕获 22,这可能解释了退回到“标准”300px 宽度。
  • @CBroe 这实际上是一个非常好的观点。在提问之前我确实读过那篇文章,它建议不要设置widthheight 属性,而是使用viewBox。然而,这种方法的缺点似乎是 SVG 在绝对定位时将不再保持正确的纵横比或折叠尺寸。解决方法似乎必须声明 widthheight
  • “似乎这种方法的缺点是 SVG 将不再保持正确的纵横比” - 你检查过 preserveAspectRatio, viewbox' "sidekick “正如文章所说,也不能解决这个问题吗? css-tricks.com/scale-svg/#article-header-id-4
  • @CBroe 根据我对 SVG 规范的理解(如有错误请指正),preserveAspectRatio 在未声明时默认为xMidYMid meet,相当于@987654353 @ 在 CSS 中。
  • 啊,所以您希望绝对定位的父级从内部的 SVG 图像中获取其尺寸?不,我认为 preserveAspectRatio 确实无济于事。

标签: css svg


【解决方案1】:

我认为问题的根本原因是,通过绝对定位,您使父级的宽度计算方法变为shrink-to-fit,并且内容也没有适当的固有宽度,这有点像第 22 个问题,它可能会解释回退到“标准”300px 宽度。

正如我们所知道的,您已经经历过https://css-tricks.com/scale-svg/,似乎将widthheight 属性添加到SVG 本身可能是(在这种特殊情况下)赋予SVG 的唯一工作方式一个适当的内在高度,以便它可以反过来“跨越”其绝对定位的父级。

【讨论】:

    猜你喜欢
    • 2012-06-29
    • 2018-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多