11

I have been beating my head against this issue for some time now and sort of came up with a solution. I would like a fixed toolbar (navbar) as well as a sticky (floating) footer. The footer should float at the bottom of the main section but be sticky to the bottom when there is no content. It seems that I can do one or the other but not both. With this method the toolbar is fixed but the footer isn't sticky. It butts up to the toolbar when the main section is empty.

<body ng-controller="MainCtrl" layout="row">

  <div layout="column" flex>
    <md-toolbar class="md-medium-tall">
        <div class="md-toolbar-tools">
            <span>HEADER</span>
            <span flex></span>
            <md-button class="md-raised" ng-click="toggleContent(!displayContent)">onOff</md-button>
            <span flex></span>
            <md-button class="md-raised" ng-click="toggleNum()">half/full</md-button>
        </div>
    </md-toolbar>


    <md-content>
        <div layout="column" flex>
            <div ng-if="displayContent" style="background-color:SteelBlue;color:white;" ng-repeat="card in cards|limitTo: displayLim">body {{card.title}}</div>
            <div style="background-color: red;" flex></div>
            <div style="background-color:orange;color:white;" >footer item</div>
        </div>  
    </md-content>           
  </div>    
</body>

The below code works as a sticky footer but then the toolbar scrolls as well.

<body ng-controller="MainCtrl" layout="row">

  <div layout="column" flex>
    <md-toolbar class="md-medium-tall">
        <div class="md-toolbar-tools">
            <span>HEADER</span>
            <span flex></span>
            <md-button class="md-raised" ng-click="toggleContent(!displayContent)">onOff</md-button>
            <span flex></span>
            <md-button class="md-raised" ng-click="toggleNum()">half/full</md-button>
        </div>
    </md-toolbar>

    <div layout="column" flex>
      <div ng-if="displayContent" style="background-color:SteelBlue;color:white;" ng-repeat="card in cards|limitTo: displayLim">body {{card.title}}</div>
      <div style="background-color: red;" flex></div>
      <div style="background-color:orange;color:white;" >footer item</div>
    </div>  
  </div>    
</body>

This seems like the proper flex way to accomplish what I'm trying to do but I just cant get it perfect.

Besides this method I have also used a more traditional approach of implementing a sticky footer using calculated main section height from calc(100vh - header - footer). I nearly had it figured out when BAM.. angular-material decided to make their toolbar size change with viewport size. I'm probably going to put in a change request so that I can use a gap filling <div flex></div> in the md-content section but I wanted to find out if anyone has a better solution first.

Brian Baker
  • 986
  • 1
  • 6
  • 17

3 Answers3

14

I finally figured out what the issue was. When nesting divs under the main content part of md-content there was an issue on safari. I fixed it by adding flex="none" to the top level div.

This works only on Chrome:

<md-content layout="column" flex>
 <div flex layout="column">
  <section>
    <div ng-if="displayContent" style="min-height:20px;background-color:SteelBlue;color:white;" ng-repeat="card in cards|limitTo: displayLim track by $index">{{card.title}}
    </div>
  </section>
  <div flex></div>
  <footer flex="none" style="background-color:orange;color:white;">
    <div>footer item</div>
  </footer>
 </div>
</md-content>

This works on Chrome and Safari:

<md-content layout="column" flex>
 <div flex layout="column">
  <section flex="none">
    <div ng-if="displayContent" style="min-height:20px;background-color:SteelBlue;color:white;" ng-repeat="card in cards|limitTo: displayLim track by $index">{{card.title}}
    </div>
  </section>
  <div flex></div>
  <footer flex="none" style="background-color:orange;color:white;">
    <div>footer item</div>
  </footer>
 </div>
</md-content>
Brian Baker
  • 986
  • 1
  • 6
  • 17
4

You should use md-content as scroll wrapper, put your content inside with flex and the footer with flex="none". It will always stick to the bottom of the md-content container since that has a CSS overflow: auto. angular-material layout children

  <md-toolbar class="md-medium-tall">
    <div class="md-toolbar-tools">
      <span>HEADER</span>
      <span flex></span>
      <md-button class="md-raised" ng-click="toggleContent(!displayContent)">onOff</md-button>
      <span flex></span>
      <md-button class="md-raised" ng-click="toggleNum()">half/full</md-button>
    </div>
  </md-toolbar>

  <md-content layout="column" flex>
    <div flex layout="column">
      <div ng-if="displayContent" style="background-color:SteelBlue;color:white;" ng-repeat="card in cards|limitTo: displayLim">body {{card.title}}</div>
    </div>
    <footer flex="none" style="background-color:orange;color:white;">
      <div>footer item</div>
    </footer>
  </md-content> 

codepen

kuhnroyal
  • 7,188
  • 1
  • 34
  • 47
  • 1
    That solves the issue on desktop but mobile (ios anyway) it breaks the scrolling behavior. It resizes the content divs to fit in the screen. When I set a min-height to fix that, the footer stays fixed in the middle of the content. Here's a forked [codepen](http://codepen.io/anon/pen/adLrLL). View it on desktop as well as on mobile. Any ideas? – Brian Baker Jan 17 '16 at 22:56
  • I updated my pen but I am not sure if that fixes anything. Don't have ios available atm. It works on android chrome. There currently are a lot of open issues in angular-material about ios problems. Which Safari are u using? – kuhnroyal Jan 18 '16 at 00:53
  • 1
    I'll upvote because this mostly solved the issue. It may be that my only option is to put in a bugfix request on github. – Brian Baker Jan 18 '16 at 01:51
1

Maybe this snippet could help:

angular
  .module('myApp', ['ngMaterial'])
  .controller('MainCtrl', function($scope) {
    console.log('MainCtrl');
    $scope.cards = [{
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }, {
      text: 'Bla bla bla bla bla bla bla ',
      title: 'Bla'
    }];
    $scope.displayContent = true;
    $scope.displayLim = 100;
    $scope.toggleContent = function(showContent) {
      $scope.displayContent = showContent;
    };
  });
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular-animate.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular-aria.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angular_material/0.8.3/angular-material.min.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/angular_material/0.8.3/angular-material.min.css">
</head>
<body ng-app="myApp" ng-controller="MainCtrl" layout="row">

  <div layout="column" flex>
    
    <md-toolbar class="md-medium-tall">
        <div class="md-toolbar-tools">
            <span>HEADER</span>
            <span flex></span>
            <md-button class="md-raised" ng-click="toggleContent(!displayContent)">onOff</md-button>
            <span flex></span>
            <md-button class="md-raised" ng-click="toggleNum()">half/full</md-button>
        </div>
    </md-toolbar>
    
    <md-content layout="row" flex>
        <div layout="column" flex>
            <div ng-if="displayContent" style="background-color:SteelBlue;color:white;" ng-repeat="card in cards|limitTo: displayLim">body {{card.title}}</div>
            <div style="background-color: red;" flex></div>
        </div>  
    </md-content>
    
    <div layout="row" class="footer" layout-align="center center">
      <h2>My Footer</h2>
    </div>
    
  </div>    
</body>
beaver
  • 17,333
  • 2
  • 40
  • 66
  • Thanks for the answer and it's very close. I've edited my answer because I forgot to mention that I want the footer to float at the bottom of the main content. In your example it is fixed like the toolbar. – Brian Baker Jan 11 '16 at 21:50