Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG circle should adapt to CSS grid height without overlapping

In the following example, the circle adapts to the grid width and keeps its aspect ratio. As the container width shrinks, the circles shrinks with it...

When height is smaller than width however (second box), the circle doesn't shrink overlaps outside the grid instead Is there a way to have it adapt to the height too while keeping the aspect ratio?

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

The result should look like this: enter image description here

like image 840
Th3S4mur41 Avatar asked Jan 09 '20 14:01

Th3S4mur41


People also ask

How do you expand the grid in CSS?

Span the first column over the two rows by using grid-row: span 2. Span the first row in the second column by using grid-column: span 2 . Extend the table over the last grid item by using 100% width and height.


1 Answers

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:

  1. let viewbox be the viewbox defined by the ‘viewBox’ attribute on the ‘svg’ element
  2. 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.

like image 147
H. Figueiredo Avatar answered Oct 27 '22 22:10

H. Figueiredo