Avoid letterboxing in auto-width max-height flex CSS layout using vh

Viewed 90

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.

2 Answers

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);
}

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