2

This is bit hard to explain but am trying to size an SVG in my page so that it can grow in width according to the width of the container but only so far as it doesn't exceed a certain percentage of the page vh. This part works, but am also trying to lay this out with a side bar, and whenever the max height restriction starts to kick in left and right padding is introduced in the SVG, whereas I want the layout to be as compact as possible in this situation, avoiding "letterboxing" of the SVG.

The requirements for the SVG are:

  • Preserve aspect ratio
  • Use 100% width of container but do not exceed given max height
  • Reduce width (of element) when height is restricted

#container {
  width: 800px;
  margin: 0px auto;
  text-align: center;
  background: #aaaaaa;
}

#flex {
  display: inline-flex;
  align-items: stretch;
  background: red;
}

#main {
  flex-grow: 1
}

svg {
  background: green;
  width: 100%;
  max-height: 75vh;
}

#sidebar {
  background: blue;
  color: white;
  min-width: 100px;
}
<div id="container">
  <div id="flex">
    <div id="main">
      <svg viewBox="0 0 870 690">
        <rect x="0" y="0" width="100%" height="100%" fill="purple" />
      </svg>
    </div>
    <div id="sidebar">
      SIDEBAR
    </div>
  </div>
</div>

Codepen

View when vertical height restriction not exceeded:

First view

View when vertical height restriction in force:

enter image description here

I would like to avoid the green vertical bars and have the SVG and sidebar take up less horizontal space but still be centered in their container.

Am not sure this behaviour is really to do with it being an SVG, and also am pretty sure setting width 100% on the SVG element is part of the issue, but if I don't set a width it has zero width and doesn't appear at all!

Help appreciated.

jugglingcats
  • 698
  • 9
  • 29

2 Answers2

3

Instead of setting the max-height, you could set the aspect-ratio property, e.g.

aspect-ratio: 29 / 23;

(since the viewBox value of the SVG is 0 0 870 690)

This is a new and only partially supported property. If you need to ensure compatibility with all the browsers you can use other methods to keep the aspect ratio (all of them will involve a padding-top whose value – in your case – will be calc(100% * 23 / 29) or ~79.31% )

If you need instead to resize the SVG according to the height try to set

svg {
  background: green;
  max-height: 75vh;
  width: 100%;
  max-width: calc(75vh * 23 / 29);
}
Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
  • Thanks. I replaced `max-height` with `aspect-ratio` as suggested in my pen but now the SVG doesn't reduce in height with the window height. Running Chrome – jugglingcats Mar 09 '21 at 09:59
  • I have updated question with the desired behaviour - hopefully this makes requirement clearer – jugglingcats Mar 09 '21 at 10:25
0

Just add "some" dimensions to SVG (what is a good idea in general) so it gets proper aspect ratio; best use it's viewBox values:

 <svg viewBox="0 0 870 690" width="870" height="690">

width: 100% in the CSS ensures it gets stretched in flex item parent.


Alternatively if you don't want to add intrinsic dimensions and don't mind SVG content's sides being cut off when max-height restriction kicks in, try preserveAspectRatio:

<svg preserveAspectRatio="xMidYMin slice" ...>

or if you can have content deformed so it is visible in any aspect ratio:

<svg preserveAspectRatio="none" ...>
myf
  • 9,874
  • 2
  • 37
  • 49
  • The problem using `preserveAspectRatio` is that the SVG is then cropped top and bottom and the width remains the same, whereas I want the SVG to reduce in width when the vertical height restriction is applied – jugglingcats Mar 09 '21 at 10:02
  • Setting the width and height also doesn't allow the width to reduce when the vh restriction is applied, the letterboxing is still there. Also doesn't allow the SVG to grow in width when there is more vertical space available – jugglingcats Mar 09 '21 at 10:03
  • I see, in Google Chrome, right? Well it really behaves strangely. In Firefox and pre-Chromium Edge the SVG constitutes flex item's width so #flex shrinks below 800px when needed, but in Chromium based browsers the flex always occupies those 800px. – myf Mar 09 '21 at 10:32