Sticky footer in Angular 2 Material

25,023

Solution 1

An approach that uses Flexbox:

When we utilize Flexbox we can get a cleaner solution. Also my solution will cover that the first component of your page should take 100% of the height. This is often needed to position elements appropriately or to work with backgrounds. The code matches the current version of Material 2 - at the time of writing this is 2.0.0-beta.12.

Markup:

<mat-sidenav-container class="all-wrap" fullscreen>
  <mat-sidenav #sidenav>
    <mat-list>
      <mat-list-item [routerLink]="['/']"> Foo</mat-list-item>
      <mat-list-item [routerLink]="['/bar']"> Bar</mat-list-item>
    </mat-list>
  </mat-sidenav>

  <div class="page-wrap">
    <header role="banner">
      <mat-toolbar color="primary">
        <button
          type="button"
          mat-icon-button
          (click)="sidenav.open()"
          title="Open sidenav">
          <mat-icon>menu</mat-icon>
        </button>
        Your Toolbar
      </mat-toolbar>
    </header>
    <main class="content">
      <router-outlet></router-outlet>
    </main>
    <footer>
      Your sticky footer with a variable height.
    </footer>
  </div>
</mat-sidenav-container>

Styles:

/*
 * Actual Sticky Footer Styles
 */
.all-wrap {
  min-height: 100vh;
}

.page-wrap {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.content {
  flex: 1;
}


/*
 * Make the Component injected by Router Outlet full height:
 */
main {
  display: flex;
  flex-direction: column;
  > *:not(router-outlet) {
    flex: 1;
    display: block;
  }
}

You can find a more detailed description in a Blogpost that I wrote since I was unhappy with the solution I found here. There is also a demo.

Solution 2

Here is a solution in few lines:

app.component.html:

<div fxLayout="column" fxFlexFill>
    <app-header></app-header> // your header
    <div fxFlex>
        <router-outlet></router-outlet> // your content
    </div>
    <app-footer></app-footer> // your footer
</div>

styles.css:

html, body {
    height: 100%;
    box-sizing: border-box;
    margin: 0;
}

Another alternative if you prefer to fill the footer instead of your content:

app.component.html:

<div fxLayout="column" style="height: 100%;">
    <app-header></app-header> // your header
    <router-outlet></router-outlet> // your content
    <app-footer fxFlexOffset="auto"></app-footer> // your footer
</div>

styles.css:

html, body {
    height: 100%;
}
Share:
25,023
Cacoon
Author by

Cacoon

I am a programmer of sorts who is always learning new things, currently making a C# administrative tool to control my users and databases quickly from my very own aplication. :)

Updated on July 09, 2022

Comments

  • Cacoon
    Cacoon almost 2 years

    I have been searching and searching for about 3 hours now because I didn't want to have to ask, but how can I keep a 'footer' variable at the bottom but not like fixed at the bottom, so if the content I have is very small it won't just sit halfway in the page but if I have lots of information it won't lock right at the bottom of the page and sit there over data while you scroll

    I have tried several ways including this: https://david-kerwick.github.io/2017/01/14/material-2-flex-layout-making-a-sticky-footer.html and most questions related to this I've tested and failed with or don't seem to work at all.

    Heres my current code:

    <div class="content">
      <app-navbar></app-navbar>
      <app-footer></app-footer>
    </div>
    

    and the <app-content></app-content> is within the navbar because the navbar controls a fullpage sidenav.

    The whole app-navbar looks like this:

    <mat-sidenav-container fullscreen>
    
      <mat-sidenav mode="push" #sidenav>
        <div fxLayout="column">
          <mat-toolbar fxLayoutAlign="center center" color="primary">
            <button mat-icon-button routerLink="/home" (click)="sidenav.close()">
              <mat-icon>keyboard_backspace</mat-icon>
            </button>
          </mat-toolbar>
          <button mat-button routerLink="/dashboard" (click)="sidenav.close()" >Information</button>
          <button mat-button routerLink="/second" (click)="sidenav.close()" >Web tools</button>
        </div>
      </mat-sidenav>
      <mat-toolbar color="primary" class="fixed-navbar mat-elevation-z10">
        <button mat-icon-button (click)="sidenav.open()" fxHide="false" fxHide.gt-xs>
          <mat-icon>menu</mat-icon>
        </button>
    
        <div fxLayout="row">
          <button fxLayout="flex-shrink: 0;" mat-button class="title" style="font-size: 25px;">{{this.title}}</button>
          <button fxShow="false" fxShow.gt-xs mat-button routerLink="/dashboard" [matMenuTriggerFor]="infoMenu">Information</button>
          <button fxShow="false" fxShow.gt-xs mat-button routerLink="/second" [matMenuTriggerFor]="toolsMenu">Web tools</button>
        </div>
        <!-- fxFlex will fill the empty space and push the following items to the right -->
        <div fxFlex></div>
        <button mat-icon-button>
          <mat-icon>face</mat-icon>
        </button>
      </mat-toolbar>
      <app-container></app-container>
    
    </mat-sidenav-container>
    

    And the footer is just a super basic component that looks like this:

    <mat-toolbar>
      <div class="container">
        <span>this is a toolbar</span>
      </div>
    </mat-toolbar>
    

    Only styling ive applied so far is this:

    @import url('https://fonts.googleapis.com/css?family=Comfortaa');
    .title {
      font-family: "Comfortaa";
    }
    html, body {
      height: 100%;
      margin: 0;
    }
    .content {
      min-height: 100%;
    }
    

    Which is in the global style.css file.

  • Cacoon
    Cacoon about 6 years
    Just want to say that this solution is still brilliant and works with the latest version of Material (5) and the latest version of angular along side it (5)
  • Alexander Mills
    Alexander Mills about 5 years
    I don't understand how this makes the footer sticky, I don't see any css applied to the footer? idk
  • Can
    Can about 5 years
    @AlexanderMills excellent question, the footer is indeed not altered. Instead the containing div.page-wrap is made a flexbox column and then the main.content is set to flex:1. So he takes up all space.
  • Can
    Can about 5 years
    You can actually play around with this on flexy boxes the-echoplex.net/flexyboxes/…