After fiddling around some time with this problem I figured this is not a problem with the grid layout.
Since you never define height/max-height or width/max-width for your SVG, what is being computed is width:auto
and height:auto
Note: I bring up max-height/max-width since these would have priority over the width/height values.
Now then, why does your landscape layout work and your portrait layout doesn't work?
Because width is "taking priority" over your height.
And that's why, in block layout, an auto height is based on the total height of descendants and an auto width is based on the containing block width.
Source - Why does width:auto behave differently than height:auto?
This means your SVG is taking the width
from its container and the height
from its descendants.
In your example, your SVG has no descendants, but has a parent with a defined max-width.
But what does this mean for the SVG's height?
The SVG is calculating it's height through the intrisic ratio:
If the ‘viewBox’ on the ‘svg’ element is correctly specified:
- let viewbox be the viewbox defined by the ‘viewBox’ attribute on the ‘svg’ element
- return viewbox.width / viewbox.height
Source
And your intrisic ratio is 1/1 = 1
So you're forcing your height=width
The solution(s)
The solution is setting a width
or a margin
to your SVG depending on the proportion of your parent div.
In the example you gave, you have a proportion of 2:1 so your SVG should have width:50%
or margin: 0 25%
.
This means that if you want to set a different proportion, you must adjust accordingly (see portrait-1-3 in the code bellow).
Setting a CSS rule for each proportion could be avoided if height
is not a constraint, since you could define a width
for your SVG and container, letting the elements adjust the height
to keep your aspect ratio.
I've also added the a final example if someone doesn't care about keeping the aspect ratio but needs to contain the SVG in a set height
and width
container.
.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>
Do note I'm not very proficient working with SVG's and this response is a result of research and a lot of experimentation!
I'd be happy to receive any adjustments and/or corrections to my response.