Dan
Dan

Reputation: 573

Bootstrap grid that fills viewport without overflow

I'm using Bootstrap 5 to try to come up with what I think is a really simple layout. I want to show an MxN grid of cells. Each cell being the same size. I want this to fill the entire viewport without scrollbars in either direction. Scrollbars are where I'm getting stuck.

I've tried different combinations of height and max-height on the various divs. This was helpful on the container div to keep it from growing too tall, but the rows end up overflowing vertically. What I really want is for everything to shrink down to where there are no scrollbars, even if it means the columns get narrower. Ideally I'd like to use bootstrap, but that's not necessarily a requirement.

The below snippet is where I'm at. It seems to be about 20% taller than the viewport.

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid">
  <div class="row p-0">
    <div class="col p-0 border">
      <span class="ratio ratio-16x9 d-flex align-items-center justify-content-center">
        Cell
      </span>
    </div>
    <div class="col p-0 border">
      <span class="ratio ratio-16x9 d-flex align-items-center justify-content-center">
        Cell
      </span>
    </div>
  </div>
  <div class="row p-0">
    <div class="col p-0 border">
      <span class="ratio ratio-16x9 d-flex align-items-center justify-content-center">
        Cell
      </span>
    </div>
    <div class="col p-0 border">
      <span class="ratio ratio-16x9 d-flex align-items-center justify-content-center">
        Cell
      </span>
    </div>
  </div>
</div>

Edit 1:

It appears the issue is with aspect-ratio. It seems to want to fill the width even at the expense of growing the height larger than the cell.

Here's an updated example without the ratios. It renders and responds correctly:

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid d-flex h-100 mh-100 vh-100 flex-column">
  <div class="row p-0 flex-grow-1">
    <div class="col p-0 border d-flex align-items-center justify-content-center">
      <div>
        Cell
      </div>
    </div>
    <div class="col p-0 border d-flex align-items-center justify-content-center">
      <div>
        Cell
      </div>
    </div>
  </div>
  <div class="row p-0 flex-grow-1">
    <div class="col p-0 border d-flex align-items-center justify-content-center">
      <div>
        Cell
      </div>
    </div>
    <div class="col p-0 border d-flex align-items-center justify-content-center">
      <div>
        Cell
      </div>
    </div>
  </div>
</div>

The ultimate goal would be to get the cell divs to always be at a 16/9 aspect ratio without growing larger than the parent div as well as being centered both horizontally and vertically in the parent. I suppose in other words, the cell divs need to grow until either the height or width reaches the parent and stop there. Instead, it seems to grow until width reaches the parent width, even if the height is taller than the parent.

Also, I should clarify the number of rows/columns is dynamic so that might affect how a solution would work as I wouldn't be able to hard-code any sizing relative to number of rows and columns.

If it helps, the end goal is to have a grid of videos that have to be shown on one screen without scrolling.

Edit 2:

Just for more clarification, here's what I'm expecting in the solution:

  1. No scrollbars anywhere. This is likely to be used in situations where the user can't be expected to scroll.
  2. Needs to work regardless of how many rows/columns I have in the layout, though it's reasonable to assume there will be a small enough number of cells that the content is still easily visible.
  3. Content of each cell will be videos.
  4. All videos need to have the same aspect ratio.
  5. Since it's unlikely that the cell dimensions are going to match video aspect ratio, the video needs to be centered horizontally and vertically in the cell.
  6. User may be resizing the browser, so resizing needs to happen accordingly.
  7. Ideally I'd prefer to stick with bootstrap or straight up css, but will consider other options if this isn't possible.

Upvotes: 1

Views: 677

Answers (1)

exside
exside

Reputation: 3884

Not 100% sure if the following is what you are after, but have a look. Note that it uses the CSS4 property aspect-ratio, read more about it here https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio and see browser support here https://caniuse.com/mdn-css_properties_aspect-ratio

I didn't use bootstrap for a long time now, so not too familiar with it's classes anymore ;), but I think if you really want to use it, you can easily find the matching classes within the bootstrap framework to replicate the little CSS this implementation needs (look at utility classes mainly)

PS: Ignore the JS code, it's just for demonstration purposes so you can dynamically add or remove items from the grid and see how it reacts.

    function addItem(e) {
        document.querySelector('.container').appendChild(document.querySelector('.col:first-of-type').cloneNode(true));
    }

    function removeItem(e) {
        e.remove();
    }
body {
  margin: 0;
}

.container {
    display: grid;
    grid-gap: 12px;
    grid-template-columns: repeat(auto-fit, minmax(20%, 1fr));
    grid-template-rows: repeat(auto-fit, minmax(0, 1fr));
    width: 100%; height: 100vh;
}
.col {
    background: #444;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    align-content: center;
}
.col > * {
    background: #999;
    aspect-ratio: 16 / 9;
    object-fit: contain;
    max-height: 100%; max-width: 100%;
}
<div class="container">
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
    <div class="col" onclick="removeItem(this)">
        <img src="https://via.placeholder.com/720x405?text=16:9" alt="Thumbnail" title="Click me and i will disappear!" />
    </div>
</div>

<button onclick="addItem(this)" style="background: #be0000; color: white; border: 0; border-radius: 3px; padding: 8px 24px; position: fixed; top: 12px; left: 12px;">Add item</button>

<style>

</style>

<script>

</script>

Upvotes: 0

Related Questions