Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizing window with SVGs

Tags:

html

css

svg

I've got the current HTML being rendered:

<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>

This renders out like this: enter image description here

The goal is that on resizing the browser window, I'd like to keep the aspect ratio of the image, as well as have the SVG's resize to maintain position and shape inside the grid image. I've tried setting the height on the img-container div to auto, which does maintain the ratio for the image. But the SVGs still resize in a manner that doesn't make sense to me:

enter image description here

I've tried changing the height on the divs surrounding the SVGs to auto, and they look the right size, but the locations are off:

enter image description here

My question is how can I achieve the goal of resizing the window, and keeping the aspect ratio of the image and SVGs, as well as keeping the SVGs in the location on the grid image?

EDIT: I should clarify that ultimately, the grid image can be any image. I'm just using it as a template and guide to achieve the goal. Ultimately, whatever image is there along with any SVGs would need to resize appropriately together so that they always have the same look.

like image 994
PiousVenom Avatar asked Oct 19 '25 08:10

PiousVenom


1 Answers

I'd rather recommend a css grid or svg layout to keep aspect ratios.

Absolute positioning is rather complicating responsive layouts.
Edit: New example added using absolute positions.

Example1: Svg grid layout

Including tiles/columns in one parent 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>

Based on Temani Afif's answer: How can I apply multiple transform declarations to one element? we can use css-variables to get a pseudo svg-grid.
All svg grid elements are basically positioned at x/y=0 and moved by row and column classes setting transform properties like transform: translateX(0) translateY(100) to meet grid column/row positions.

Example2: CSS grid approach (using inlined 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>

Example 3: grid based on relative/absolute positions

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>

It's crucial to define an aspect ratio for the parent grid element like so:

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

Or use the aspect ratio padding workaround.

like image 164
herrstrietzel Avatar answered Oct 21 '25 21:10

herrstrietzel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!