41
votes

I am attempting to create an Angular material layout. My goal is to create a page where it fills the entire browser window without creating a vertical scroll bar. At the top of the page is a toolbar that consumes 100% of the width of the page. Under the toolbar is a title area that also consumes 100% of the width. Under the title area I would like a nav menu on the left and a client area on the right. My goal is to have both the nav menu and the client area fill vertically the entire browser window.

To give you a visual of what I am trying to accomplish: enter image description here

I have been experimenting with the layout row and column along with the attributes flex and layout-fill. Every other post that I have found indicates that this should be possible with the right combination however the solution has eluded me. I have created a Plunker to demonstrate my problem:

http://plnkr.co/edit/Eva0Cf6KKa0z6I9YsR8t?p=info

Here is my index.html:

<!DOCTYPE html>
<html class="no-js">

<head>
  <meta charset="utf-8">
  <title>adasd</title>
  <meta name="viewport" content="width=device-width">
  <link rel="stylesheet" href="//rawgit.com/angular/bower-material/master/angular-material.css">
  <link rel="stylesheet" href="nav.css">
  <link rel="stylesheet" href="style.css">
</head>
<body ng-app="plunker" ng-controller="MainCtrl">
  <md-toolbar layout="row" class="md-hue-3">
      <div flex="15" layout layout-align="center center" >
        <span>Logo</span>
      </div>
      <div flex="85" layout layout-align="center center" >
        <span>Toolbar Header</span>
      </div>
  </md-toolbar>

  <div flex >
    <div ng-view flex layout-fill></div>
  </div>
  <!-- Angular Material Dependencies -->
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-route.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-aria.min.js"></script>

  <!-- Angular Material Javascript now available via Google CDN; version 0.6 used here -->
  <script src="//rawgit.com/angular/bower-material/master/angular-material.min.js"></script>

  <script src="app.js"></script>
</body>

</html>

And the main.html (gets displayed in the ng-view):

<div layout="column" flex layout-fill>
  <div layout="row" flex layout-fill>
      <md-whiteframe flex="100" layout layout-align="center center" style="margin-bottom: 16px;height: 60px;">
          <div flex="100"><span id="site-name">Some sort of a title goes here...</span></div>
      </md-whiteframe>
  </div>
  <div layout="row" flex layout-fill>
      <md-sidenav layout-fill class="md-sidenav-left " id="siteMenu" md-component-id=" left" md-is-locked-open="$mdMedia('gt-sm')">
          <md-content layout-fill role="navigation">
              <ul class="docs-menu">
                <li ng-repeat="section in sections" class="parent-list-item">
                      <h2 class="menu-heading" ng-if="section.type === 'heading'" id="heading_{{ section.name | nospace }}">
                          {{section.name}}
                      </h2>
                      <menu-link section="section" ng-if="section.type === 'link'"></menu-link>
                </li>

                  <li ng-repeat="section in menu.sections" class="parent-list-item" ng-class="{'parentActive' : isSectionSelected(section)}">
                      <h2 class="menu-heading" ng-if="section.type === 'heading'" id="heading_{{ section.name | nospace }}">
                          {{section.name}}
                      </h2>
                      <menu-link section="section" ng-if="section.type === 'link'"></menu-link>

                      <menu-toggle section="section" ng-if="section.type === 'toggle'"></menu-toggle>

                      <ul ng-if="section.children" class="menu-nested-list">
                          <li ng-repeat="child in section.children" ng-class="{'childActive' : isSectionSelected(child)}">
                              <menu-toggle section="child"></menu-toggle>
                          </li>
                      </ul>
                  </li>
              </ul>
          </md-content>
      </md-sidenav>

      <md-content layout="row" class="content-wrapper md-padding" flex layout-fill id="content">
        <div flex layout-fill>
          <h2>Home Content</h2>

          <ul>
            <li>Page Content goes here...</li>
            <li>and here...</li>
            <li>and here...</li>
          </ul>
        </div>
      </md-content>
  </div>
</div>

Of course, look at the Plunker to see everything wired together and visually see the problem.

Any help would be greatly appreciated!

PS. I just tested this Plunker on IE 11 and it is having other display issues. But that is for another question another day. It should work correctly on Chrome. Also, the menu will auto hide on windows less than 600px wide. To show the window, make the Plunker display window wider.

3
I had this working and then when I tried to edit the plunker, I lost it. This should get you started on the right direction (I just don't have time to figure out exactly what I'd done right now): <div flex style="height: -webkit-calc(100% - 76px)"> <div ng-view flex layout-fill style="height: 100%"></div> </div>Mordred
Thanks Mordred, that worked. I added the style you suggested on both elements. That made both the menu and client area expand to fill the entire window. It also increased the title area but that was easily fixed with a flex="10" attribute. I am guessing to be compabile with all browsers I would need to also add -moz-calc(100% - 76px) and -o-calc(100% - 76px) and calc(100% - 10px)?Briz
I don't know if opera supports it, but you'd definitely need the others. Also, I'm not sure what the calc support is on mobile. See more here: developer.mozilla.org/en-US/docs/Web/CSS/…Mordred
Are you familiar with the viewport CSS units? height: 100vh and width: 100vw applied to an element would ensure that that element is the full width and height of the viewport. Adding position: absolute and left: 0, top: 0 would make sure that it's up in the top left corner. Not sure if that'd solve the issue or not.Benjamin Solum
I've answered in this question to articulate how layout-fill actually works in angular-material: stackoverflow.com/questions/29002473/… Have a look there and it might help.kavare

3 Answers

31
votes

You can also do it without adding extra styles just using the Angular Material elements.

Basically you need to add layout to all the parents of the elements you want to fill vertically. You also don't need to use so many layout-fills.

Here the demo: http://plnkr.co/edit/E244WNhvMXw9VC7DpAW0?p=preview

I also added a background color to the sidebar to demonstrate that it also fills vertically.

11
votes
<div flex style="height: -webkit-calc(100% - 76px)">
    <div ng-view flex layout-fill style="height: 100%">
    </div>
</div>

Just thought that this answer should go in an answer to make it easier for others.

5
votes

Simple Example:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
</head>
<body ng-app="MyApp" layout="column" ng-cloak>
    <div flex layout="row" layout-align="center center" style="background: plum;">
        <div>page filled and content centered</div>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.js"></script>
    <script>
        angular.module("MyApp", ["ngMaterial"]);
    </script>
</body>
</html>

Output:

enter image description here