【问题标题】:SVG circle should adapt to CSS grid height without overlappingSVG 圆应该适应 CSS 网格高度而不重叠
【发布时间】:2020-04-27 04:26:45
【问题描述】:

在下面的示例中,圆适应网格宽度并保持其纵横比。 随着容器宽度的缩小,圆圈也随之缩小......

但是,当高度小于宽度时(第二个框),圆圈不会缩小,而是在网格外重叠 有没有办法让它在保持纵横比的同时也适应高度?

.container {
	display: grid;
	background-color: greenyellow;
	margin: 5px;
	min-height: 10px;
	min-width: 10px;
}

.portrait {
		max-height: 100px;
		max-width: 200px;
}

.landscape {
		max-height: 200px;
		max-width: 100px;
}

.aspect-ratio {
	grid-column: 1;
	grid-row: 1;
	background-color: deeppink;
	border-radius: 50%;
 align-self: center;
	justify-self: center;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

结果应如下所示:

【问题讨论】:

  • 您可以编辑 svg 代码吗?

标签: html css svg css-grid aspect-ratio


【解决方案1】:

在解决这个问题一段时间后,我认为这不是网格布局的问题。

由于您从未为 SVG 定义 height/max-heightwidth/max-width,因此计算的是 width:autoheight:auto p>

注意:我提出 ma​​x-height/max-width,因为这些值优先于 width/height 值。 p>


那么,为什么您的 landscape 布局有效而您的 portrait 布局无效? 因为宽度比身高“优先”。

这就是为什么在块布局中,自动高度基于后代的总高度,而自动宽度基于包含块的宽度。

Source - Why does width:auto behave differently than height:auto?

这意味着您的 SVG 正在从其容器中获取 width 并从其后代中获取 height

在您的示例中,您的 SVG 没有后代,但有一个定义了 ma​​x-width 的父级。 但这对 SVG 的高度意味着什么?

SVG 正在通过内在比率计算它的高度:

如果“svg”元素上的“viewBox”被正确指定:

  1. 让 viewbox 成为由“svg”元素上的“viewBox”属性定义的视图框
  2. 返回 viewbox.width / viewbox.height

Source

而你的内在比率是1/1 = 1

所以你强迫你的height=width


解决方案

解决方案是根据父 div 的比例为 SVG 设置 widthmargin

在您给出的示例中,您的比例为 2:1,因此您的 SVG 应该有 width:50%margin: 0 25%

这意味着如果要设置不同的比例,则必须进行相应的调整(参见下面代码中的 Portrait-1-3)。

如果height 不是约束,则可以避免为每个比例设置 CSS 规则,因为您可以为 SVG 和容器定义 width,让元素调整 height 以保持纵横比。

如果有人不关心保持纵横比但需要将 SVG 包含在一组 heightwidth 容器中,我还添加了最后一个示例。

.container {
  display: grid;
  background-color: greenyellow;
  margin: 5px;
  min-height: 10px;
  min-width: 10px;
}

.portrait {
  max-height: 100px;
  max-width: 200px;
}


/* Add 25% margin left and right to center the image  OR set the image width to 50% */

.portrait>.aspect-ratio {
  margin: 0 25%;
  /*
    or 
    
    width:50%;
  */
}

.landscape {
  max-height: 200px;
  max-width: 100px;
}

.aspect-ratio {
  grid-column: 1;
  grid-row: 1;
  background-color: deeppink;
  border-radius: 50%;
  align-self: center;
  justify-self: center;
}


/* Set fixed max-height and max-width rule (33% proportion)  */

.portrait-1-3 {
  max-height: 100px;
  max-width: 300px;
}


/* Align image with the new proportion */

.portrait-1-3>.aspect-ratio {
  margin: 0 33.33%;
  /*
    or 
    
    width:33.3%;
  */
}


/* Removed max-height and let the container adjust the height according to the max-width rule and the proportion set  */

.portrait-any-height {
  max-width: 400px;
}


/* Height will be adjusted through the width/margin defined here, so 10% width will correspond to 40px of height (10%*400px)*(aspect ratio=1)*/

.portrait-any-height>.aspect-ratio {
   width:10%;
}


/* Set fixed max-height and max-width rule (proportion doesn't matter)  */

.portrait-squeezed {
  max-height: 100px;
  max-width: 300px;
}


/* Make sure SVG complies with the the given max with and height (squeezing your svg)  */

.portrait-squeezed>.aspect-ratio {
  max-height: inherit;
  max-width: inherit;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-1-3">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-any-height">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

<div class="container portrait-squeezed">
  <svg class="aspect-ratio" viewBox="0 0 1 1"></svg>
</div>

请注意,我对 SVG 的使用不是很熟练,这个回复是研究和大量实验的结果! 我很乐意收到对我的回复的任何调整和/或更正。

【讨论】:

  • 感谢您的详细解释...我必须注意到,不幸的是,您的研究返回的结果与我的相同。我的要求似乎没有解决方案: 1. SVG 纵横比是固定的。 2. 容器纵横比可变/未知 3. 容器大小受高度和宽度的限制,具体取决于环境(例如浏览器窗口大小) 建议的解决方案是将 SVG 宽度设置为容器的某个百分比,如果容器有固定的纵横比,但它没有。
  • 放弃 max-height 也不起作用,这只是意味着将溢出问题移至父级
  • 对于这 3 个要求,似乎没有解决方案,即使用 only CSS。是否使用 Javascript 来计算适当的 SVG 宽度?
  • 这就是我目前的解决方案正在做的事情,我想避免;)
  • 我希望宽高比能帮助解决这个问题,但我什至不确定。 drafts.csswg.org/css-sizing-4/#aspect-ratio
【解决方案2】:

将特定高度和宽度与最大高度和最大宽度一起添加到容器中。

vw 和 vh 单位可用于使此布局更加灵活。

  max-height: 100px;
  max-width: 200px;
  width: 100vw;
  height: 100vh;

这样可以将max-width: 100%; max-height: 100%;设置为svg,并且不会重叠。


-编辑-

由于 svg 视图框已经以正确的纵横比渲染,因此可以安全地将 svg 背景移动到 svg 本身内以获得预期结果:cicle 标签就可以解决问题。

是否可以在掩码中使用另一个圆形标签来模仿边界半径

然后,svg 的所有其他元素都应该放在一个掩码组内。 即:&lt;g mask="url(#mask)"&gt;

.container {
  display: grid;
  background-color: greenyellow;
  margin: 5px;
  min-height: 10px;
  min-width: 10px;
}

.portrait {
  max-height: 100px;
  max-width: 200px;
  width: 100vw;
  height: 100vh;
}

.landscape {
  max-height: 200px;
  max-width: 100px;
  width: 100vw;
  height: 100vh;
}

.aspect-ratio {
  grid-column: 1;
  grid-row: 1;
  align-self: center;
  justify-self: center;
  max-width: 100%;
  max-height: 100%;
}

.aspect-ratio .bkg{
  fill: deeppink;
}
<div class="container landscape">
  <svg class="aspect-ratio" viewBox="0 0 1 1">
    <mask id="mask">
      <circle cx=".5" cy=".5" r=".5" fill="#fff"/>
    </mask>
    <circle cx=".5" cy=".5" r=".5" class="bkg"/>
    <g  mask="url(#mask)">

    </g>
  </svg>
</div>

<div class="container portrait">
  <svg class="aspect-ratio"viewBox="0 0 1 1">
    <mask id="mask">
      <circle cx=".5" cy=".5" r=".5" fill="#fff"/>
    </mask>
    <circle cx=".5" cy=".5" r=".5" class="bkg"/>
    <g  mask="url(#mask)">

    </g>
  </svg>
</div>

【讨论】:

  • 指定的问题“有没有办法让它在保持纵横比的同时也适应高度”,而您的示例没有。这是一种在容器内强制 SVG 的方法,但它不会产生预期的结果。这与我响应的最后一个示例相同,其中 svg 被 挤压 以适应容器
  • 解释可能有点混乱,但解决方案建议 svg 高度适应容器的高度。
  • 但它没有保留 SVG 纵横比!您看到 OP 发布的预期结果了吗?
  • 哦,哇...我刚刚用 Chrome 浏览过它,现在我明白你在说什么了。我在 Firefox 上对其进行了编码,并且使用该浏览器可以按预期工作,我没想到结果会如此不同。我的坏
  • 这实际上是非常有趣的行为,我猜 Firefox 和 Chrome 100% 的计算方式不同?无论如何,我们都会犯错,否则就不会存在:D
猜你喜欢
  • 2019-10-18
  • 2022-01-17
  • 2016-09-11
  • 1970-01-01
  • 2015-01-06
  • 2019-08-13
  • 2021-08-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多