Reputation: 187
Trying to figure out how this svg viewBox thing works but sadly the code below is breaking all logic we know lol. Please someone explain if this is a bug or it's the correct svg behaviour. I can't see what I'm getting wrong...
<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>
This my svg symbol here and I'm trying to stack more of them (both horizzontally and vertically)
//vertical stack ->viewBox = 0, 0, 10*1, 7*2
<svg viewBox="0 0 10 14">
<use href="#Atom"/>
<use href="#Atom" y="7"/>
</svg>
//horizontal stack ->viewBox = 0, 0, 10*2, 7*1
<svg viewBox="0 0 20 7">
<use href="#Atom"/>
<use href="#Atom" x="10"/>
</svg>
//"diagonal" stack ->viewBox = 0, 0, 10*2, 7*2
<svg viewBox="0 0 20 14">
<use href="#Atom"/>
<use href="#Atom" x="10"/>
<use href="#Atom" y="7"/>
</svg>
First one is 2 symbols in vertical so I kept the same viewBox as the symbol but doubling the height from 7 to 14. Works perfectly.
Second one is 2 symbols in horizontal so I kept the same viewBox as the symbol but doubled the width from 10 to 20. Works as well.
Third one is 2 symbols in horizontal and 2 symbols in vertical making both viewBox's width and height twice as the original. This doesn't work.
As you can see from the image the symbols get all messed up togheter (seems like I have a wrong viewBox)
This is kinda what I'm looking for (though as you can see I'm using overflow: visible and the symbols goes out of the viewbox)
Can somebody explain me what I'm getting wrong here? Any help is really appreciated.
Here's a codepen for playing with this stuff
Upvotes: 0
Views: 148
Reputation: 187
So I ended up replying to myself but I really want to thanks @ciekals11 for its input.
The solution to get the result I wanted was to specify width and height attributes in my symbol. This makes everything works perfectly. Not sure why it does need this, but anyway I'll share my symbol again so you can see the difference.
<svg class="symbol"><symbol width="10" height="7" id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"/></symbol></svg>
Upvotes: 1
Reputation: 2155
your symbol want to take full width or height when you stretch only one dimension of viewport then it fit nicely because it take full width or height and stops from stretching in other direction because it want to preserve aspect ratio.
But in this svg
viewport is 2x bigger than symbol so it take it all
here is simple solution
.svg {
max-width: 200px;
border: 1px solid red;
}
<svg class="svg" viewBox="0 0 20 14">
<use href="#Atom" x="0" y="0" width="50%" />
<use href="#Atom" x="0" y="7" width="50%" />
<use href="#Atom" x="10" y="0" width="50%" />
<use href="#Atom" x="10" y="7" width="50%" />
</svg>
<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>
UPDATE:
if you doesn't want to manually add width
to use
tag AND you are creating them programmatically then (I assumed that you use javascript but you could use same logic for other language) you just want to calc rows and columns in your viewport and calculate width and height of every use
here is an example
const config = {
svg: {
width: 20,
height: 14,
rows: 2,
cols: 2,
symbol: '#Atom'
}
}
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewBox', '0 0 '+config.svg.width+' '+config.svg.height);
for (let i = 0; i < config.svg.rows; i++) {
for (let j = 0; j < config.svg.cols; j++) {
const xPosition = (config.svg.width / config.svg.rows) * i;
const yPosition = (config.svg.height / config.svg.cols) * j;
const width = (100 / config.svg.rows);
const height = (100 / config.svg.cols);
const svgUse = document.createElementNS('http://www.w3.org/2000/svg', 'use');
svgUse.setAttribute('href', config.svg.symbol);
svgUse.setAttribute('x', xPosition);
svgUse.setAttribute('y', yPosition);
svgUse.setAttribute('width', width + '%');
svgUse.setAttribute('height', height + '%');
svg.append(svgUse);
}
}
document.body.prepend(svg)
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<svg class="symbol"><symbol id="Atom" preserveAspectRatio="xMinYMin meet" viewBox="0 0 10 7"><path d="M3 6 4 7 6 7 4 4 5 3 8 7 10 7 5 0 0 7 2 7Z"></path></symbol></svg>
</body>
</html>
Upvotes: 2