使用SVG调整窗口大小

4

我已经得到了当前正在渲染的HTML:

<div style="width: 912px; height: 673px;">
    <div id="img-container" style="height: 58.82%; width: 47.07%; top: 20.59%; left: 26.46%; position: absolute;">
        <img class="grid-img" src="grid.jpg" alt="grid" style="width: 100%; height: 100%;"/>
        <div style="top: 40.55%; left: 50.13%; width: 11.7%; height: 19.33%; z-index: 13; position: absolute; transform: rotate(0deg); display: block;">
            <svg viewBox="0 0 100 100" height="100%" width="100%" id="square-0" preserveAspectRatio="none" class="annotation" name="square">
                <rect x=".5%" y=".5%" height="98.5%" width="99%" stroke="white" fill="#cc0000" stroke-width="4"/>
            </svg>
        </div>
        <div style="top: 40.34%; left: 26.72%; width: 11.96%; height: 19.75%; z-index: 14; position: absolute; transform: rotate(0deg); display: block;">
            <svg viewBox="0 0 100 100" height="100%" width="100%" id="roundedSquare-1" class="annotation" name="roundedSquare" preserveAspectRatio="none">
                <rect x=".5%" y=".5%" height="98.5%" width="99%" stroke="white" fill="#990099" stroke-width="4" rx="6"/>
            </svg>
        </div>
        <div style="top: 21.43%; left: 27.1%; width: 11.58%; height: 19.12%; z-index: 15; position: absolute; transform: rotate(0deg); display: block;">
            <svg viewBox="0 0 100 100" height="100%" width="100%" id="squareLetter-2" class="annotation" name="squareLetter" preserveAspectRatio="none">
                <rect x="1.5" y="1.5" height="97" width="97" stroke="#00ffff" stroke-width="4" fill="#ff9900"/>
                <text class="step-text" x="50" y="50" dy="26.5" dx="0.0em" text-anchor="middle" fill="white" font-size="74.96px">A</text>
            </svg>
        </div>
    </div>
</div>

这将呈现为: {{link1:在此输入图片描述}}
目标是在调整浏览器窗口大小时,保持图像的纵横比,并使SVG调整大小以在网格图像内保持位置和形状。我尝试将 div上的高度设置为auto,这确实保持了图像的比例。但是SVG仍然以一种对我来说不合理的方式调整大小:

enter image description here

我尝试将围绕SVG的

元素的height更改为auto,它们看起来大小正确,但位置偏移了:

enter image description here

我的问题是如何实现窗口大小调整,同时保持图像和SVG的纵横比,并将SVG保留在网格图像上的位置?
编辑: 我应该澄清,最终的网格图像可以是任何图像。我只是使用它作为模板和指南来实现目标。最终,无论哪个图像以及任何SVG都需要一起适当地调整大小,以便始终具有相同的外观。

你能否提供一个带有你的 网格图像 (grid.jpg) 的工作示例,因为现在 grid.jpg 只存在于你的本地硬盘上。而 任何图像 这是指网格图像中的每个单元格还是整个网格图像? - Anton
在您的图像上使用 https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio,并使用 https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout 进行布局。 - Carol McKay
2个回答

2
我建议使用CSS的gridsvg布局来保持宽高比。绝对定位会使响应式布局变得更加复杂。
编辑:新增了一个使用绝对定位的示例。

示例1:Svg网格布局

在一个父级SVG中包含瓷砖/列

let resize = document.querySelector('.resize');

function setWidth(width) {
  resize.style.width = width + '%';
}
.resize {
  overflow: auto;
  padding: 1em;
  border: 1px solid #ccc;
  resize: both;
  width: 100%;
}

.svg-grid {
  width: 100%;
}

:root {
  --transX: translateX(0);
  --transY: translateY(0);
}

.col {
  transform: var(--transX) var(--transY);
}

.row-2 {
  --transY: translateY(100px);
}

.row-3 {
  --transY: translateY(200px);
}

.col-2 {
  --transX: translateX(100px);
}

.col-3 {
  --transX: translateX(200px);
}

.col-4 {
  --transX: translateX(300px);
}
<p>
  <button type="button" onclick="setWidth(33)">33% width</button>
  <button type="button" onclick="setWidth(50)">50% width</button>
  <button type="button" onclick="setWidth(75)">75% width</button>
  <button type="button" onclick="setWidth(100)">100% width</button>
</p>
<div class="resize">
  <svg class="svg-grid" viewBox="0 0 400 300" overflow="visible">
    <image x="0" y="0" width="100%" height="100%" class="bg" href="data:image/svg+xml,%3Csvg class='svg-grid' viewBox='0 0 400 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cpattern x='-2' y='-2' id='grid' width='100' height='100' patternUnits='userSpaceOnUse'%3E%3Crect width='100%25' height='100%25' fill='%23000' /%3E%3Crect x='0' y='0' width='100%25' height='100%25' fill='none' stroke='%23fff' stroke-width='8' /%3E%3C/pattern%3E%3C/defs%3E%3Crect class='bg' x='0' y='0' width='100%25' height='100%25' fill='url(%23grid)' /%3E%3C/svg%3E"  />
    <g class="col row-2 col-3">
      <rect x="0" y="0" height="100" width="100" stroke="white" fill="red" stroke-width="0" />
    </g>
    <g class="col row-2 col-1">
      <rect class="annotation" name="roundedSquare" x="0" y="0" height="100" width="100" stroke="white" fill="#990099" stroke-width="4" rx="6" />
    </g>
    <g class="annotation col row-1 col-1" name="squareLetter">
      <rect x="0" y="0" height="100" width="100" stroke="#00ffff" stroke-width="4" fill="orange" />
      <text class="step-text" x="0" y="0" dy="50" dx="50" dominant-baseline="central" text-anchor="middle" fill="white" font-size="74.96px">A</text>
    </g>
  </svg>
</div>

基于Temani Afif的答案:如何在一个元素上应用多个变换声明?,我们可以使用CSS变量来获取伪SVG网格。
所有的SVG网格元素基本上都定位于x/y=0,并通过行和列类设置变换属性(如transform: translateX(0) translateY(100))以满足网格列/行位置。

示例2:CSS网格方法(使用内联SVGs)

let resize = document.querySelector('.resize');
function setWidth(width){
  resize.style.width = width+'%';
}
* {
  box-sizing: border-box;
}

.resize {
  overflow: auto;
  padding: 1em;
  border: 1px solid #ccc;
  resize: both;
  width: 100%;
}


.aspect4-3 > * {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
}

.aspect4-3:before {
  content: "";
  padding-top: 75%;
  display: block;
}

.gridWrpOuter {
  display: grid;
  width: 100%;
  position: relative;
  grid-gap: 0px;
}

.gridWrp {
  display: grid;
  grid-template-columns: [col1] 25% [col2] 25% [col3] 25% [col4] 25%;
  grid-template-rows: [row1] 33.333% [row2] 33.333% [row3] 33.333%;
  grid-gap: 0px;
  outline: 1px solid red;
}

.bg {
  position: absolute;
  width: 100%;
  height: 100%;
}

.col {
  width: 100%;
}

.col-2 {
  grid-column-start: col2;
  grid-column-end: col3;
}

.col-3 {
  grid-column-start: col3;
  grid-column-end: col4;
}

.col-4 {
  grid-column-start: col4;
  grid-column-end: 100%;
}

.row-2 {
  grid-row-start: row2;
  grid-row-end: row3;
}

.row-3 {
  grid-row-start: row3;
  grid-row-end: 100%;
}
<p>
  <button type="button" onclick="setWidth(33)">33% width</button>
  <button type="button" onclick="setWidth(50)">50% width</button>
  <button type="button" onclick="setWidth(75)">75% width</button>
  <button type="button" onclick="setWidth(100)">100% width</button>
</p>
<div class="resize">
  
<div class="gridWrpOuter aspect4-3">
    <img class="bg" src="data:image/svg+xml,%3Csvg class='svg-grid' viewBox='0 0 400 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cpattern x='-2' y='-2' id='grid' width='100' height='100' patternUnits='userSpaceOnUse'%3E%3Crect width='100%25' height='100%25' fill='%23000' /%3E%3Crect x='0' y='0' width='100%25' height='100%25' fill='none' stroke='%23fff' stroke-width='8' /%3E%3C/pattern%3E%3C/defs%3E%3Crect class='bg' x='0' y='0' width='100%25' height='100%25' fill='url(%23grid)' /%3E%3C/svg%3E" alt="">
  <div class="gridWrp">
    <div class="col row-3 col-4">
      <svg class="svg-col" viewBox="0 0 100 100">
        <rect class="" x="0" y="0" height="100" width="100" fill="#cc0000" stroke-width="4" stroke="green" />
      </svg>
    </div>
    <div class="col row-1 col-2">
      <svg class="svg-col" viewBox="0 0 100 100">
        <rect class="" x="0" y="0" height="100" width="100" fill="orange" stroke-width="4" stroke="green" />
      </svg>
    </div>
    <div class="col row-2 col-3">
      <svg class="svg-col" viewBox="0 0 100 100">
        <rect class="" x="0" y="0" height="100" width="100" fill="orange" stroke-width="4" stroke="green" />
      </svg>
    </div>
    <div class="col row-2 col-1">
      <svg class="svg-col" viewBox="0 0 100 100">
        <g class="annotation col row-1 col-1" name="squareLetter">
          <rect x="0" y="0" height="100" width="100" stroke="#00ffff" stroke-width="4" fill="orange" />
          <text class="step-text" x="0" y="0" dy="50" dx="50" dominant-baseline="central" text-anchor="middle" fill="white" font-size="74.96px">A</text>
        </g>
      </svg>
    </div>
    </div>
  </div>
</div>

示例3:基于相对/绝对位置的网格

let resize = document.querySelector('.resize');
function setWidth(width){
  resize.style.width = width+'%';
}
* {
  box-sizing: border-box;
}

.resize {
  overflow: auto;
  padding: 1em;
  border: 1px solid #ccc;
  resize: both;
  width: 100%;
}

.aspect4-3 > * {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 100%;
}

.aspect4-3:before {
  content: "";
  padding-top: 75%;
  display: block;
}

.gridWrp {
  display: block;
  width:100%;
  position: relative;
  outline: 1px solid red;
}

.bg {
  position: absolute;
  width: 100%;
  height: 100%;
}

.col {
  width: 25%;
  height: 33.333%;
}

.col-2 {
  left: 25%;
}

.col-3 {
  left: 50%;
}

.col-4 {
  left: 75%;
}

.row-2 {
  top: 33.333%;
}

.row-3 {
  top: 66.666%;
}
<p>
  <button type="button" onclick="setWidth(33)">33% width</button>
  <button type="button" onclick="setWidth(50)">50% width</button>
  <button type="button" onclick="setWidth(75)">75% width</button>
  <button type="button" onclick="setWidth(100)">100% width</button>
</p>

<div class="resize">
  <div class="gridWrp aspect4-3">
    <img class="bg" src="data:image/svg+xml,%3Csvg class='svg-grid' viewBox='0 0 400 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cpattern x='-2' y='-2' id='grid' width='100' height='100' patternUnits='userSpaceOnUse'%3E%3Crect width='100%25' height='100%25' fill='%23000' /%3E%3Crect x='0' y='0' width='100%25' height='100%25' fill='none' stroke='%23fff' stroke-width='8' /%3E%3C/pattern%3E%3C/defs%3E%3Crect class='bg' x='0' y='0' width='100%25' height='100%25' fill='url(%23grid)' /%3E%3C/svg%3E" alt="">

    <div class="col row-3 col-4">
      <svg class="svg-col" viewBox="0 0 100 100">
        <rect class="" x="0" y="0" height="100" width="100" fill="#cc0000" stroke-width="4" stroke="green" />
      </svg>
    </div>
    <div class="col row-1 col-2">
      <svg class="svg-col" viewBox="0 0 100 100">
        <rect class="" x="0" y="0" height="100" width="100" fill="orange" stroke-width="4" stroke="green" />
      </svg>
    </div>
    <div class="col row-2 col-3">
      <svg class="svg-col" viewBox="0 0 100 100">
        <rect class="" x="0" y="0" height="100" width="100" fill="orange" stroke-width="4" stroke="green" />
      </svg>
    </div>
    <div class="col row-2 col-1">
      <svg class="svg-col" viewBox="0 0 100 100">
        <g class="annotation col row-1 col-1" name="squareLetter">
          <rect x="0" y="0" height="100" width="100" stroke="#00ffff" stroke-width="4" fill="orange" />
          <text class="step-text" x="0" y="0" dy="50" dx="50" dominant-baseline="central" text-anchor="middle" fill="white" font-size="74.96px">A</text>
        </g>
      </svg>
    </div>
  </div>
</div>

定义一个父级网格元素的宽高比非常重要,例如:

.gridWrp{
  aspect-ratio: 4/3;
}

或者使用宽高比填充解决方案。


@PiousVenom:修订了所有片段(现在它们都包括背景图像元素),并添加了一种绝对网格方法(在Safari中可能比css-grid更强大)。 - herrstrietzel

1

您已经在矩形块中使用了height="97" width="97",您应该将其更新为height="auto" min-width="97"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接