Search code examples
htmlcssvertical-alignment

CSS centered square child limited by both width and height of its parent (like background-size:contain + center)


So I've seen many solutions for making square divs, but I have yet to find a simple one that behaves exactly like a background-size:contain; background-position:center center;

The goal:

  • A child div that remains square
  • If the parent width is narrower than its height, the child square fits that width
  • If the parent height is narrower than its width, the child square fits that height
  • Remains centered at all times, so if it is limited by the width of the parent the square is vertically centered in it (that's the hard part).

This approach is almost perfect, but it doesn't center the square vertically: https://jsfiddle.net/8s4chau9/

#wrapper {
  width: 50%;
  height: 300px;
  border: 1px solid blue;
}
#square {
  aspect-ratio: 1/1;
  max-width: 100%;
  max-height: 100%;
  margin: auto;
  box-sizing: border-box;
  background-color: red;
}
<div id=wrapper>
    <div id=square></div>
</div>

I thought that making the wrapper a flex would work but it does not: display:flex; align-items:center; justify-content:center;

Hopefully someday none of this will be necessary when someone will finally create the css units pw (parent width), ph (parent height), pmin and pmax (like vmin/vmax but for parent rather than viewport).


Solution

  • If I've understood well, your current problem is that the square doesn't align vertically. This can be easily fixed with the translate CSS function:

    #wrapper {
      width: 50%;
      height: 300px;
      border: 1px solid blue;
    }
    #square {
      position: relative;
      top: 50%;
      aspect-ratio: 1/1;
      max-width: 100%;
      max-height: 100%;
      margin: auto;
      box-sizing: border-box;
      background-color: red;
      transform: translateY(-50%);
    }
    <div id=wrapper>
        <div id=square></div>
    </div>

    First, you assign a position to your square other than static, so that you can assign a top value to it. In this case we'd prefer it to be positioned relatively.

    Then, you assign a top: 50%, that will be tweaked to give a centered result with transform: translateY(-50%).

    Here you have your edited fiddle: https://jsfiddle.net/Bettylex/6ncks2fx/2/