Div extending far outside modal, want it to stay inside and scroll

Viewed 267

I have a modal with fixed size. It contains multiple panes selectable with nav buttons. On one of the panes I have a div containing a grid of thumbnail images and a button at the bottom. Currently the images and the button extend far past the bottom of the modal window. I would like the button to remain at the bottom of the pane, and the remaining height of the pane be occupied with the thumbnail div.row, wherein if the image content does not fit inside of the div.row, the content scrolls.

My attempt at this was to make the pane flex-column, and make the div.row overflow-auto, but it has no effect it seems.

HTML

<div class="modal modal-base">
  <div class="modal-overlay"></div>
  <div class="modal-window">
    <div class="close">&times;</div>
    <div class="modal-content">
      <div class="nav-wrapper">
        <ul class="nav nav-pills flex-row" role="tablist">
          <li class="nav-item">
            <a class="nav-link mb-3 active" href="#" role="tab">Image List</a>
          </li>
          <li class="nav-item">
            <a class="nav-link mb-3" href="#" role="tab">Upload</a>
          </li>
        </ul>
      </div>
      <div class="card shadow mb-0">
        <div class="card-body">
          <div class="tab-content">
            <div class="tab-pane fade show active d-flex flex-column" role="tabpanel">
              <div class="row overflow-auto">
                <div class="col-6 mb-2">
                  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
                </div>
                <div class="col-6 mb-2">
                  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
                </div>
                <div class="col-6 mb-2">
                  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
                </div>
              </div>
              <button type="button" class="btn btn-primary w-100 btn-lg">Insert</button>
            </div>
            <div class="tab-pane fade" role="tabpanel">
              <div class="upload-widget"></div>
              <div class="text-center mt-2">
                <button type="button" class="btn btn-primary">Upload</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

CSS (scss)

.modal {
  &.modal-base {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  &-overlay {
    position: absolute;
    z-index: 2000;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
  }

  &-window {
    background: #fff;
    border-radius: 4px;
    margin: auto;
    position: relative;
    width: 400px;
    height: 300px;
    z-index: 2001;

    .close {
      position: absolute;
      right: 2px;
      top: 2px;
      color: gray;
      font-size: 25px;
      z-index: 2002;
    }
  }

  &-content {
    width: 100%;
    height: 100%;
    padding: 20px;
  }
}

Codepen

Using Bootstrap 4 CSS framework. The JS code for the pane switching has been omitted since it is superfluous. I would like a solution that does not require me to fix the height of the div containing the images.

Note: this is a continuation of the question asked here. In that question I had simplified my setup to make everyone's life easier, and was able to get a working solution for that simplified setup, but it does not seem to work when translated over the actual setup I have, hence this question.

Thank you for looking at my question!

3 Answers

You should include an overflow:auto; or do the css code at your containing element

containing element {
    content:"";
    display:table;
    clear:both;
}

Just provide your div containing the card class with appropriate overflow property like this:

<div class="card shadow mb-0" style="overflow-x: hidden; overflow-y: scroll;">

I solved this issue (with help from an online friend) over the course of a few hours, allow me to share the insight gained.

Essentially, flex is the way to go here. We need flex in the pane to keep the button on the bottom while the images take up the remaining space with scrolling overflow. We should also make enclosing divs have a height of 100% (.tab-content, .card-body).

When we get to the .card itself is where things get tricky. We want it to fill the parent, but applying h-100 here is not acceptable since it has a sibling, its height shouldn't be 100% of the parent content area, but rather 100% - height of the .nav-wrapper. It's close to what we want, but not quite.

Seems like we need another flex here to allow the .card to grow just into the remaining space, but if you set the flex here, it is not respected and the card extends way outside of the modal. The secret sauce is that by default, the .card with .d-flex is getting min-height:auto, and what this means is that it will not shrink smaller than the size of its content. Setting min-height:0 on the div.card solves the problem. Since I do not see any Bootstrap utility to do this, I've added one myself globally for this purpose to use in the future as well.

.d-flex > .flex-shrink-content {
  min-height: 0;
}

The full code / demo can be found here for those interested: Codepen

<div class="modal modal-base">
  <div class="modal-overlay"></div>
  <div class="modal-window">
    <div class="close">&times;</div>
    <div class="modal-content d-flex flex-column">
      <div class="nav-wrapper flex-grow-1">
        <ul class="nav nav-pills flex-row" role="tablist">
          <li class="nav-item">
            <a class="nav-link mb-3 active" href="#" role="tab">Image List</a>
          </li>
          <li class="nav-item">
            <a class="nav-link mb-3" href="#" role="tab">Upload</a>
          </li>
        </ul>
      </div>
      <div class="card flex-shrink-content shadow">
        <div class="card-body h-100">
          <div class="tab-content h-100">
            <div class="tab-pane fade show active d-flex flex-column h-100" role="tabpanel">
              <div class="row flex-grow-1 overflow-auto">
                <div class="col-6 mb-2">
                  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
                </div>
                <div class="col-6 mb-2">
                  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
                </div>
                <div class="col-6 mb-2">
                  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Terrier_mixed-breed_dog.jpg/1024px-Terrier_mixed-breed_dog.jpg" class="img-thumbnail">
                </div>
              </div>
              <button type="button" class="btn btn-primary w-100 btn-lg mt-2">Insert</button>
            </div>
            <div class="tab-pane fade h-100" role="tabpanel">
              <div class="upload-widget"></div>
              <div class="text-center mt-2">
                <button type="button" class="btn btn-primary">Upload</button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
.modal {
  &.modal-base {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
  }

  &-overlay {
    position: absolute;
    z-index: 2000;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
  }

  &-window {
    background: #fff;
    border-radius: 4px;
    margin: auto;
    position: relative;
    width: 400px;
    height: 300px;
    z-index: 2001;

    .close {
      position: absolute;
      right: 2px;
      top: 2px;
      color: gray;
      font-size: 25px;
      z-index: 2002;
    }

  }

  &-content {
    width: 100%;
    height: 100%;
    padding: 20px;
  }
  
}

.d-flex > .flex-shrink-content {
  min-height: 0;
}
Related