skip to Main Content

I have a component on my page (named grid in the example).

I’d like this component to achieve the following constraints:

  • maintain 1:1 aspect ratio
  • be as big as possible
  • stay within the bounds of the viewport (no scrollbars)
  • ideally without JavaScript

I’ve been able to satisfy 1, 2, and 4, but not 3:

  • when the viewport is portrait-oriented (more height than width), the grid and its children will shrink as desired, to maintain the 1:1 aspect ratio.
  • when the viewport is landscape-oriented, the grid component expands beyond the bottom of the viewport, creating a scrollbar.

Here’s the HTML I’m looking at:

    <div id="wholePage" class="black">
      <div>top bar placeholder</div>
      <div id="grid">
        <div class="row darkGray">
          <div class="column red"></div>
          <div class="column yellow"></div>
        </div>
        <div class="row lightGray">
          <div class="column green"></div>
          <div class="column blue"></div>
        </div>
      </div>
    </div>

And here’s the associated CSS:

#wholePage {
  background-color: gray;
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

#grid {
  width: auto;
  height: auto;
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  aspect-ratio: 1;
}

.row {
  height: 50%;
  width: 100%;
  flex: 0 1 auto;
  display: flex;
  flex-direction: row;
}

.column {
  height: 100%;
  width: 100%;
  flex: 0 1 auto;
}

2

Answers


  1. You can use aspect-ratio and max-width/height to keep it from going outside parent container (here <body>):

    * {
      box-sizing: border-box; /* Needed here to prevent border making scrollbar */
    }
    
    html,
    body {
      margin: 0;
      width 100%; /* Or any other size */
      height: 100%; /* Or any other size */
    }
    
    .box {
      aspect-ratio: 1 / 1; /* This keeps it square */
      max-height: 100%; /* This sets largest side */
      border: 5px solid green;
    }
    <div class="box"></div>
    Login or Signup to reply.
  2. As per @AHaworth’s comment, the key here is width: 100vmin, and I would use a grid to implement the rows and columns.

    body, html {
      height: 100%;
    }
    
    body {
      margin: 0;
      background-color: gray;
      display: flex;
      justify-content: center;
      align-items: center;
      color: white;
    }
    
    #grid {
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-template-rows: 1fr 1fr;
      border: 3px solid black;
      width: 100vmin;
      aspect-ratio: 1;
      box-sizing: border-box;  
    }
    
    .row {
      display: contents;
    }
    
    .red {
      background: red;
    }
    
    .yellow {
      background: gold;
    }
    
    .green {
      background: green;
    }
    
    .blue {
      background: blue;
    }
    <div id="grid">
      <div class="row darkGray">
        <div class="column red"></div>
        <div class="column yellow"></div>
      </div>
      <div class="row lightGray">
        <div class="column green"></div>
        <div class="column blue"></div>
      </div>
    </div>

    After running this snippet, use the full page link to test the responsive behaviour.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search