How to use Bootstrap 4 flexbox to fill available content?

CssTwitter BootstrapAngularFlexboxBootstrap 4

Css Problem Overview


I have an angular app that uses bootstrap 4. I have a nav bar that sticks to the top, and I want to add content that fills the remaining space in the browser. Aside from the navbar at the top, I have another div that itself contains header and footer content. Between the header and footer, I have a main content section, and I want that section (#two in my example below) to fill all empty space.

I thought I could use css flexbox to accomplish this, but my simple non-bootstrap flexbox example seemed to do nothing when I moved into the bootstrap world. I was using these docs to try to figure this out.

I thought using align-self-stretch should help accomplish this goal, but it sort of looks like the containing elements might be sizing themselves just big enough to hold my #outer content, so there's no flexbox expanding to be done. I tried naively just adding height:100% styles to the containing divs just to try to get some stretching, but that didn't seem to help.

I created this plunker example based on @ZimSystem's response. His codeply example seemed to work exactly as I wanted, but when I tried to piece the changes into my simple angular code, the flex stretching didn't happen. I'm not sure what I'm doing to break it in the conversion.

enter image description here

This is the entirety of the angular component I am viewing at the moment:

<div id="outer" class="d-flex flex-column flex-grow">
    <div id="one" class="">
        header content <br>
        another line <br>
        And another
    </div>
    <div id="two" class="bg-info h-100 flex-grow">
        main content that I want to expand to cover remaining available height
    </div>
    <div id="three" class="">
        footer content
    </div>
</div>

And here's the application container showing the navbar and injection point:

<div class="d-flex flex-column h-100">
    <nav class="navbar navbar-toggleable-md sticky-top bg-faded">
        <a class="navbar-brand" href="#">
            <h1 class="navbar-brand mb-0">My App</h1>
        </a>
        <ul class="navbar-nav"> 
            <li class="nav-item"><a class="nav-link" routerLink="/flex">My flex view</a></li>
        </ul>
    </nav>
    <router-outlet></router-outlet>
</div>  

How can I get my #two div to expand to fill the space while having my #one and #three divs acting as content headers and footers anchored to the top and bottom of the content area?

Css Solutions


Solution 1 - Css

Update Bootstrap 4.1.0

The flex-grow-1 and flex-fill classes are included in Bootstrap 4.1.0

Update Bootstrap 4.0.0

Add a flex-grow class like this:

.flex-grow {
    flex: 1 0 auto;
}

Then, the utility classes can be used for the rest of the layout:

 <div class="d-flex flex-column h-100">
    <nav class="navbar navbar-toggleable-md sticky-top bg-faded">
        <a class="navbar-brand" href="#">
            <h1 class="navbar-brand mb-0">My App</h1>
        </a>
        <ul class="navbar-nav">
            <li class="nav-item"><a class="nav-link">Item 1</a></li>
        </ul>
    </nav>
    <div id="outer" class="d-flex flex-column flex-grow">
        <div id="one" class="">
            header content
            <br> another line
            <br> And another
        </div>
        <div id="two" class="bg-info h-100 flex-grow">
            main content that I want to expand to cover remaining available height
        </div>
        <div id="three" class="">
            footer content 40px height
        </div>
    </div>
</div>

https://www.codeply.com/go/3ZDkRAghGU

Here's another example with on Bootstrap 4.3.1 that has a navbar, sidebar and footer with scrolling content area: https://www.codeply.com/go/LIaOWljJm8

Solution 2 - Css

Your component is wrapped into a <flex> element that needs the same flexbox styling to stretch vertically as well, allowing it's content to stretch with it. So adding class="d-flex flex-column flex-grow" to the <flex> will work. Here's a working fork of your plunker example.

Solution 3 - Css

The problem, when using ZimSystem's markup in your Angular plunker, is that the component is inserted in the rendered HTML as an additional container with the flex tag:

<div class="d-flex flex-column h-100">
    <nav class="navbar navbar-toggleable-md sticky-top bg-faded">
        ...
    </nav>
    <router-outlet></router-outlet>
    <flex>
        <div id="outer" class="d-flex flex-column flex-grow">
            ...
        </div>
    </flex>
</div>

In order to make it work as intended, you can remove the outer div from the component and set the flex classes on the component's host container, as shown in this modified plunker.

import {Component, NgModule, HostBinding, VERSION} from '@angular/core'
import { RouterOutlet, RouterModule } from '@angular/router' 
import {BrowserModule} from '@angular/platform-browser'

@Component({
    selector: 'flex',
    template: `
        <div id="one" class="">
            header content
            <br> another line
            <br> And another
        </div>
        <div id="two" class="bg-info h-100 flex-grow">
            main content that I want to expand to cover remaining available height
        </div>
        <div id="three" class="">
            footer content
        </div>
    `
})
export class FlexComponent {
    @HostBinding('class') classes = 'd-flex flex-column flex-grow';  
    ...
}

Solution 4 - Css

If you can not control the behavor of the class you are using. Just remove all of it and use this css only.

html,
body,
flex {
  height: 100%;
  margin: 0;
}

.outer {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.two {
  background-color: #123;
  flex-grow: 1;
  color: #FFF;
}

<flex>
  <div class="outer">
    <div class="one">
      Hey. This is header. <br> Hey. This is header. <br> Hey. This is header. <br> Hey. This is header. <br>
    </div>
    <div class="two">
      Hey. This is body
    </div>
    <div class="three">
      Hey. This is footer <br> Hey. This is footer <br>
    </div>
  </div>
</flex>

Solution 5 - Css

.wrapper {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.flex-grow {
  flex: 1;
}

Add a wrapper component that holds your content blocks, and apply the flex-grow class to the one that you want to fill the remaining space.

Solution 6 - Css

CSS

html, body {
  height: 100%;
}

.flex-grow {
  flex: 1;
}

flex.components.ts

//our root app component
import {Component, NgModule, VERSION} from '@angular/core'
import { RouterOutlet, RouterModule } from '@angular/router' 
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'flex',
  host: {'class': 'flex-grow'},
  template: `
  
<div id="outer" class="d-flex flex-column h-100 flex-grow">
  <div id="one" class="">
    header content
    <br> another line
    <br> And another
  </div>
  <div id="two" class="bg-info flex-grow">
    main content that I want to expand to cover remaining available height
  </div>
  <div id="three" class="">
    footer content
  </div>
</div>        

  ` 
})
export class FlexComponent {
  constructor() {}
}

Result - https://plnkr.co/edit/vQS7Jw58zmlVshz9YmQ8?p=preview Thanks:)

Solution 7 - Css

You can make the component grow to fill its container and then have it as a flex column as well so the content will also grow. To do this use :host to target the component element.

flex.component.ts

  @Component({
    selector: 'flex',
    template: `
    
  <div id="outer" class="d-flex flex-column flex-grow">
    <div id="one" class="">
      header content
      <br> another line
      <br> And another
    </div>
    <div id="two" class="bg-info h-100 flex-grow">
      main content that I want to expand to cover remaining available height
    </div>
    <div id="three" class="">
      footer content
    </div>
  </div>        
  
    `,
    styles: [':host {flex: 1 0 auto; display: flex; flex-direction: column }']
  })

I've updated the plunk.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChris FarmerView Question on Stackoverflow
Solution 1 - CssZimView Answer on Stackoverflow
Solution 2 - CssTigran PetrossianView Answer on Stackoverflow
Solution 3 - CssConnorsFanView Answer on Stackoverflow
Solution 4 - CssDuannxView Answer on Stackoverflow
Solution 5 - CssSaraView Answer on Stackoverflow
Solution 6 - CssgrinmaxView Answer on Stackoverflow
Solution 7 - CssJayChaseView Answer on Stackoverflow