Search code examples
cssangularsassangular-materialscrollbar

How do I fix my scrolling issue with Angular Material sidebar


My expected result:

  • Having a 'fixed' sidebar on the left side of the screen when on desktop which takes the full screen height and has a width of 226px.
  • On mobile there should be a toolbar available to open up the side panel from the left side
  • The user should not be able to scroll away the toolbar, should only be able to scroll the content

I'm currently experiencing trouble with point number 3, where I cannot seem to get the height and overflows right. The padding at the bottom is not becoming visible and there are two scrollbars available. In order to get to the full bottom/top you need to scroll both scrollbars to the bottom/top, so I cannot just hide them. I think I made a mistake with the setting the heights, but I cannot find the mistake.

How do I get the one scrollbar that just scrolls the content in mat-sidenav-content?

Stackblitz link*: https://stackblitz.com/edit/stackblitz-starters-eapqhq2k?file=src%2Fsidebar%2Fsidebar.component.scss

*my signal for isMobile() doesn't seem to work in stackblitz, so to test the desktop version you have to map it to false or find a different way to solve it. But this does represent my code the best

sidebar html

@if (isMobile()) {
  <mat-toolbar class="mobile-toolbar" aria-label="Toolbar">
    <button (click)="sidenav.toggle()">Toggle</button>
  </mat-toolbar>
}

<mat-sidenav-container class="sidenav-container" [class.mobile]="isMobile()">
  <mat-sidenav
    #sidenav
    class="sidenav"
    [class.mobile]="isMobile()"
    [mode]="isMobile() ? 'over' : 'side'"
    [opened]="!isMobile()"
  >
    <div class="sidebar-content">
      <button>
        test
      </button>
    </div>
  </mat-sidenav>

  <mat-sidenav-content
    class="sidenav-content"
    [class.mobile]="isMobile()">
    <router-outlet></router-outlet>
    <div class="test-long-content">
      <h1>Test</h1>
    </div>
  </mat-sidenav-content>
</mat-sidenav-container>

sidebar scss

.sidenav-container {
  height: 100vh;

  &.mobile {
    overflow-y: auto;
    height: calc(100vh - 64px);
  }
}

.sidenav-content {
  background-color: grey;
  overflow-y: auto;

  &.mobile {
    padding: 2vh 5vw 2vh 5vw;
  }

  .test-long-content {
    height: 1000px;
    background-color: red;
  }
}

.sidenav {
  background-color: black;

  overflow-y: auto;
  width: 226px;

  display: flex;
  flex-direction: column;
  justify-content: space-between;

  .mobile {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000;
    margin-top: 64px;
  }

  .sidebar-content {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    height: 100%;
  }
}

.mobile-toolbar {
  background: black;
  height: 64px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1000;
}

Solution

  • The padding is causing the size of the mat-sidenav-content dimensions to exceed the set limits.

    We can use the CSS box-sizing: border-box; so that the padding will pad the inner dimensions of the element, instead of the outer dimensions, which cause the extra scrollbars.

    Box Sizing CSS - MDN Docs

    .sidenav-content {
      background-color: grey;
      overflow-y: auto;
    
      &.mobile {
        padding: 2vh 5vw 2vh 5vw;
        box-sizing: border-box; // <- changed here!
      }
    
      .test-long-content {
        height: 1000px;
        background-color: red;
      }
    }
    

    Stackblitz Demo