26

I have created a toolbar using Angular Material. However, it is not responsive. How can I make the toolbar responsive?

Code for toolbar:

<md-toolbar color = "primary">
    <button md-button class="md-primary" [routerLink]="['/basic']"><md-icon class = "icon-20">home</md-icon> &nbsp;Angular Concepts</button>
    <button md-button [mdMenuTriggerFor]="bMenu">Basic Concepts</button>
    <md-menu #bMenu="mdMenu">
      <button md-menu-item [routerLink]="['/a4']">Angular Component</button>
      <button md-menu-item [routerLink]="['/cli ']">Angular CLI</button>
      <button md-menu-item [routerLink]="['/inout']">Event Emitters</button>
      <button md-menu-item [routerLink]="['/template']">Template Driven Forms</button>
      <button md-menu-item [routerLink]="['/reactive']">Data Driven Forms</button>
      <button md-menu-item [routerLink]="['/directives']">Angular Custom Directives</button>
      <button md-menu-item [routerLink]="['/pipes']">Custom Pipes</button>
      <button md-menu-item [routerLink]="['/viewchild']">View Child</button>
      <button md-menu-item [routerLink]="['/view']">View Encapsulation</button>
    </md-menu>

    <button md-button [mdMenuTriggerFor]="aMenu">Advanced Concepts</button>
    <md-menu #aMenu="mdMenu">
      <button md-menu-item [routerLink]="['/ngrx']">Angular Redux using ngrx/store</button>
      <button md-menu-item [routerLink]="['/guard']">Angular Guards</button>
      <button md-menu-item [routerLink]="['/host']">Host & Host-Context</button>
    </md-menu>

    <button md-button (click)="openDialog()">&nbsp;Contact Card</button>
  </md-toolbar>

5 Answers 5

54

Here is my favorite way of creating a responsive Navigation Bar in Angular. If you use Angular 6, make sure you use a version 6.1+
Working example on Stackblitz: https://stackblitz.com/edit/angular-v6xwte

Example on a smaller screen: Toolbar on a small screen

Example on a larger screen: Toolbar on a large screen

Here are precise steps how to do it:

1) Install necessary packages. Type in your terminal:

npm install --save @angular/material @angular/cdk @angular/animations

npm install @angular/flex-layout --save

2) Import necessary modules in your app.module.ts

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FlexLayoutModule } from '@angular/flex-layout';
import {
  MatIconModule, MatButtonModule, MatSidenavModule, MatToolbarModule
} from '@angular/material';

Remember to add these modules to the imports array below.

3) Add Material Icons link to your index.html
The link must go before any Angular content.

<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">

4) In your styles.css add an Angular theme and set margins to 0%

@import "~@angular/material/prebuilt-themes/indigo-pink.css";
body{
    margin: 0%;
}

5) Add toolbar HTML code in your app.component.html

<div> 
  <mat-toolbar color="primary">
    <div fxShow="true" fxHide.gt-sm="true">
      <button mat-icon-button (click)="sidenav.toggle()">
        <mat-icon>menu</mat-icon>
      </button>
    </div>

    <a mat-button class="companyName" routerLink="/">
      <span>Site name</span>
    </a>
    <span class="example-spacer"></span>
    <div fxShow="true" fxHide.lt-md="true">
      <a mat-button routerLink="/about-us">About us</a>
      <a mat-button routerLink="/prices">Prices</a>
      <a mat-button routerLink="/start-page">Start page</a>
      <a mat-button routerLink="/offer">Offer</a>
      <a mat-button routerLink="/contact">Contact</a>
    </div>

  </mat-toolbar>
  <mat-sidenav-container fxFlexFill class="example-container">

    <mat-sidenav color="primary" #sidenav fxLayout="column" mode="over"  opened="false" fxHide.gt-sm="true">
      <div fxLayout="column">
        <a mat-button routerLink="/about-us">About us</a>
        <a mat-button routerLink="/prices">Prices</a>
        <a mat-button routerLink="/start-page">Start page</a>
        <a mat-button routerLink="/offer">Offer</a>
        <a mat-button routerLink="/contact">Contact</a>
      </div>
    </mat-sidenav>
    <mat-sidenav-content fxFlexFill>
      Awesome content
    </mat-sidenav-content>
  </mat-sidenav-container>
</div>

6) Style the toolbar in your app.component.css

.companyName{
    font-size: 150%;
}

.mat-toolbar{
  height: 7vh;
}

div {
    overflow: inherit;
}

.mat-sidenav-container{
  background-color: lightskyblue;
  min-height: 93vh !important;
}

a{
    text-decoration: none;
    font-size: 110%;
    white-space: normal;
}

button{
    font-size: 110%;
    min-width: min-content;
}

.example-icon {
    padding: 0 14px;
  }

  .example-spacer {
    flex: 1 1 auto;
  }

  .mat-sidenav-content{
      font-size: 200%;
      text-align: center;
  }
Sign up to request clarification or add additional context in comments.

7 Comments

Great one. I just wanted to let you know that, after opening the menu in small screen, how about closing it automatically as the screen size increases.
Thanks for this advice. It was enough to add fxHide.gt-sm="true" to mat-sidenav. The sidenav disappears. All that remains is the darkened main content, but it vanishes after a click anywhere.
This is awesome. Thanks @TomaszChudzik . For future readers, in case you get error(in my case it was MediaQueryList) in compiling flexbox remember to move to lower versions. Just run npm install @angular/[email protected]
I'm using this great example but on a large screen I get a vertical scrollbar because height: 100%; min-height: 100%; for mat-sidenav-container is set. This makes the container larger than the page, with the height of the top menu. I've been trying to solve this but can't get it to work.
I found a different, but simar solution. change the first <div> to <div style="height: calc(100vh - 65px);">, where 65px is the size of your toolbar.
|
17

Problem

You need a way to make your navigation bar responsive.

Solution

You can use Material Angular with ToolBar and Flex-Layout.

Example

npm install @angular/flex-layout --save

Example Angular Material Toolbar with Flex Layout.

<div style="height: 100vh;">

  <mat-toolbar color="primary">

    <span>Responsive Navigation</span>

    <span class="example-spacer"></span>

    <div fxShow="true" fxHide.lt-md="true">

      <!-- The following menu items will be hidden on both SM and XS screen sizes -->

      <a href="#" mat-button>Menu Item 1</a>

      <a href="#" mat-button>Menu Item 2</a>

      <a href="#" mat-button>Menu Item 3</a>

      <a href="#" mat-button>Menu Item 4</a>

      <a href="#" mat-button>Menu Item 5</a>

      <a href="#" mat-button>Menu Item 6</a>

    </div>

    <div fxShow="true" fxHide.gt-sm="true">

      <a href="#" (click)="sidenav.toggle()">Show Side Menu</a>

    </div>

  </mat-toolbar>

  <mat-sidenav-container fxFlexFill class="example-container">

    <mat-sidenav #sidenav fxLayout="column">

      <div fxLayout="column">

        <a (click)="sidenav.toggle()" href="#" mat-button>Close</a>

        <a href="#" mat-button>Menu Item 1</a>

        <a href="#" mat-button>Menu Item 2</a>

        <a href="#" mat-button>Menu Item 3</a>

        <a href="#" mat-button>Menu Item 4</a>

        <a href="#" mat-button>Menu Item 5</a>

        <a href="#" mat-button>Menu Item 6</a>

      </div>

    </mat-sidenav>

    <mat-sidenav-content fxFlexFill>Main content</mat-sidenav-content>

  </mat-sidenav-container>

</div>

6 Comments

I had already used bootstrap components to make the navbar but i want to make use of angular material components not bootstrap and make them responsive
Yes but i need the same feel of the material components , the way the material ui look i want the nav bar to be like that even the links
This is for angular js , is ot applicable to angular 2 also. As the new material is build upside down
@wuno - I think there needs to make some changes. Where to put the main content (I mean the body of each menu/link). Now it is inside <mat-sidenav-content fxFlexFill>. I don't think that is the right way.
Thank you for letting me know. I updated the answer to remove the link to the outdated tutorial.
|
5

Use angular/flex-layout for responsiveness.

Comments

1

To see how the official Angular website does it, see these components (on Angular 15, replace commit hash 6706fab with main for latest):

import {Component, Input, OnChanges} from '@angular/core';
import {NavigationNode} from 'app/navigation/navigation.model';

@Component({
  selector: 'aio-nav-item',
  templateUrl: 'nav-item.component.html',
})
export class NavItemComponent {
  @Input() isWide = false;

Later:

<aio-nav-item *ngFor="let node of nodeChildren" [level]="level + 1" [isWide]="isWide"
    [isParentExpanded]="isExpanded"
    [node]="node" [selectedNodes]="selectedNodes"></aio-nav-item>

And:

  <nav [attr.aria-label]="navLabel || null">
    <aio-nav-item *ngFor="let node of filteredNodes"
      [node]="node"
      [selectedNodes]="selectedNodes"
      [isWide]="isWide">
    </aio-nav-item>
  </nav>`

With a whole bunch of SCSS to handle it https://github.com/angular/angular/blob/6706fab/aio/src/styles/1-layouts/top-menu/_top-menu.scss

@use '../../mixins';
@use '../../constants';

// VARIABLES
$showTopMenuWidth: 1150px;
$hideTopMenuWidth: $showTopMenuWidth - 1;
$hamburgerShownMargin: 0 8px 0 0;
$hamburgerHiddenMargin: 0 16px 0 -64px;

// DOCS PAGE / STANDARD: TOPNAV TOOLBAR FIXED
mat-toolbar.app-toolbar {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 10;
  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.3);

  // HOME PAGE OVERRIDE: TOPNAV TOOLBAR
  .page-home & {
    @media (min-width: 481px) {
      &:not(.transitioning) {
        background-color: transparent;
        box-shadow: none;
        position: absolute;
        transition: background-color 0.2s linear;
      }
    }
  }

  // DOCS PAGES OVERRIDE: HAMBURGER
  @include mixins.docs-pages($nestParentSelector: true) {
    @media (min-width: $showTopMenuWidth) {
      .hamburger {
        // Hamburger shown on non-marketing pages even on large screens.
        margin: $hamburgerShownMargin;
        visibility: visible;
      }
    }
  }

  mat-toolbar-row {
    padding: 0 16px 0 0;
  }

  // HAMBURGER BUTTON
  .hamburger {
    height: 100%;
    margin: $hamburgerShownMargin;
    padding: 0;

    @media (min-width: $showTopMenuWidth) {
      // Hamburger hidden by default on large screens.
      // (Will be shown per doc.)
      margin: $hamburgerHiddenMargin;
      visibility: hidden;
    }

    @media (max-width: 480px) {
      min-width: 15%;
    }

    &:not(.no-animations) {
      transition-duration: 0.4s;
      transition-property: color, margin;
      transition-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1);
    }

    & .mat-icon {
      position: inherit;
    }
  }
}

Comments

0

My crude implementation attempt with flex-layout and angular-material 5.0.2

.mat-sidenav-container {
  background: rgba(0, 0, 0, 0.08);
}

.blank-grow {
  flex: 1 1 auto;
}
<mat-sidenav-container fullscreen>
  <mat-sidenav #sidenav>
    <mat-nav-list>
      <a mat-list-item>
        <mat-icon mat-list-icon>home</mat-icon>
        <span mat-line>home</span>
      </a>

      <a mat-list-item>
        <mat-icon mat-list-icon>backup</mat-icon>
        <span mat-line>Backup</span>
      </a>
    </mat-nav-list>
  </mat-sidenav>
  <mat-toolbar color="primary">
    <button mat-icon-button (click)="sidenav.open()" fxHide="false" fxHide.gt-sm>
      <mat-icon>menu</mat-icon>
    </button>
    <span> Big Header</span>
    <span class="blank-grow"></span>
    <div fxLayout="row" fxShow="false" fxShow.gt-sm>
      <a>
        <mat-icon mat-list-icon>home</mat-icon>
        <span mat-line>home</span>
      </a>

      <a>
        <mat-icon mat-list-icon>backup</mat-icon>
        <span mat-line>Backup</span>
      </a>
    </div>
  </mat-toolbar>
</mat-sidenav-container>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.