Material: SideNav: push-in instead of slideIn overlay.

Created on 8 Apr 2015  路  21Comments  路  Source: angular/material

Is there a way for md-sidenav to open without overlaying main content?

I am trying to reproduce the scenario for right Side Nav on desktop described in the material design guidelines here : http://www.google.com/design/spec/layout/structure.html#structure-side-nav

image

Is there a way to open an md-sidenav and not overlap the main content? I searched for some md-sidenav-someoption css to achieve this with no luck, maybe another one does the trick?

I am using v0.8.3

Thanks for your help!

minor more info enhancement

Most helpful comment

For whoever is looking for this feature can take a look at my codepen: http://codepen.io/anon/pen/qdymaB

Drop in directive:

// suplement sidenav behavior
    module.directive('sidenavPushIn', function () {
        return {
            restrict: 'A',
            require: '^mdSidenav',
            link: function ($scope, element, attr, sidenavCtrl) {
                var body = angular.element(document.body);
                body.addClass('md-sidenav-push-in');
                var cssClass = (element.hasClass('md-sidenav-left') ? 'md-sidenav-left' : 'md-sidenav-right') + '-open';
                var stateChanged = function (state) {
                    body[state ? 'addClass' : 'removeClass'](cssClass);
                };
                // overvwrite default functions and forward current state to custom function
                angular.forEach(['open', 'close', 'toggle'], function (fn) {
                    var org = sidenavCtrl[fn];
                    sidenavCtrl[fn] = function () {
                        var res = org.apply(sidenavCtrl, arguments);
                        stateChanged(sidenavCtrl.isOpen());
                        return res;
                    };
                });
            }
        };
    });

LESS styles:

.md-sidenav-push-in {
    // drawers
    .md-sidenav-push-in-target {
        transform: translate(0px);
        // same as in md-sidenav.md-closed-add.md-closed-add-active, md-sidenav.md-closed-remove.md-closed-remove-active selector
        transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    }
    &.md-sidenav-left-open {
        .md-sidenav-push-in-target {
            transform: translate(304px);
        }
    }
    &.md-sidenav-right-open {
        .md-sidenav-push-in-target {
            transform: translate(-304px);
        }
    }
}

To make use of this: simply add sidenav-push-in attribute to your md-sidenav and add css class 'md-sidenav-push-in-target' to your content element. I firmly believe that this can be integrated to core fairly easily.

All 21 comments

I'm exploring options with this. Right now, you could set the md-is-locked-open property to something other than a media query and toggle it after injecting your detail content

<div layout="column" role="main" flex class="master-view">
    <md-toolbar>...</md-toolbar>
    <md-content ui-view md-scroll-y flex></md-content>
</div>
<md-sidenav class="md-sidenav-right md-whiteframe-z2 detail-view" md-is-locked-open="isDetailOpen">...</md-sidenav>

Does that help?

@cdonohue Using a property to toggle md-is-locked-open instead of $mdSidenav('right').open(); did help! This way the sidenav opens and resizes the md-content successfully.

Now I am trying to do the same thing but with the md-toolbar also resized and with an independent one for the right Side Nav.

While that does it, there is no transitioning when you toggle using md-is-locked-open. You'll have to a custom transition for that event I guess.

I'm not sure if you guys are talking about the same issue I have at the moment: on md-is-locked-openbehaviour is different than the toggle one on smaller screen sizes. On smaller screen size it seems that mdSidenavis connected to the bodywhile on md-is-locked-open state the navigation is aligned on the position inside of the code. It might be helpful if there would be an option to define the parentfor the locked open state.

For whoever is looking for this feature can take a look at my codepen: http://codepen.io/anon/pen/qdymaB

Drop in directive:

// suplement sidenav behavior
    module.directive('sidenavPushIn', function () {
        return {
            restrict: 'A',
            require: '^mdSidenav',
            link: function ($scope, element, attr, sidenavCtrl) {
                var body = angular.element(document.body);
                body.addClass('md-sidenav-push-in');
                var cssClass = (element.hasClass('md-sidenav-left') ? 'md-sidenav-left' : 'md-sidenav-right') + '-open';
                var stateChanged = function (state) {
                    body[state ? 'addClass' : 'removeClass'](cssClass);
                };
                // overvwrite default functions and forward current state to custom function
                angular.forEach(['open', 'close', 'toggle'], function (fn) {
                    var org = sidenavCtrl[fn];
                    sidenavCtrl[fn] = function () {
                        var res = org.apply(sidenavCtrl, arguments);
                        stateChanged(sidenavCtrl.isOpen());
                        return res;
                    };
                });
            }
        };
    });

LESS styles:

.md-sidenav-push-in {
    // drawers
    .md-sidenav-push-in-target {
        transform: translate(0px);
        // same as in md-sidenav.md-closed-add.md-closed-add-active, md-sidenav.md-closed-remove.md-closed-remove-active selector
        transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
    }
    &.md-sidenav-left-open {
        .md-sidenav-push-in-target {
            transform: translate(304px);
        }
    }
    &.md-sidenav-right-open {
        .md-sidenav-push-in-target {
            transform: translate(-304px);
        }
    }
}

To make use of this: simply add sidenav-push-in attribute to your md-sidenav and add css class 'md-sidenav-push-in-target' to your content element. I firmly believe that this can be integrated to core fairly easily.

@cmoiccool @dohomi isn't that the expected result?

Related #3027.

+1 this happens to me as well, but i wouldn't like to use md-is-locked-open cause.. when you toggle it to true.. this sideNav would start expanding from width: 0px instead of sliding like $mdSidenav().toggle() does.. this causes the layout inside the sideNav to look a little broken while it's still being expanded until it is fully expanded

@FDIM answer is not consistent. The transform size should be adjusted according the current breakpoint. How to get the current size of sidenav in a less file ? I guess i should use $layout-breakpoint-XX combined to his solution.

@sam2x I am not sure what is the situation now, but at the time I commented I am pretty sure the size was fixed to 304px. But I noticed that at certain size my content jumps a bit - something might have changed I guess.

Yes the size is changed according the breakpoint. Actually the constants are the following :

 $sidenav-mobile-width: 320px !default;
 $sidenav-desktop-width: 400px !default;
 $sidenav-min-space: 56px !default;

On desktop, the following rule is applied (when width >= 1280px, sidenav is 400px, else it's ) :

 @media screen and (min-width: $layout-breakpoint-xs) {
   md-sidenav {
     max-width: $sidenav-desktop-width;
   }
 }

Depending on mobile phone width (eg: iphone 4, i got 264px), the sidenav is calculated dynamically via width - $sidenav-min-space. I like your solution, but i need to find a way to use breakpoints with it (without modifying the original css file).

Closing this issue as the requested outcome can be reproduce with the current api.
If i got it wrong please comment and i will reopen this issue.

@EladBezalel Please reopen.

The proposed solution is a hack and is inconsistent with $mdSidenav service. There is no animation for example, and it effectively disables the open/close API.

See also #3027.

@omeid there's an animation
This feature request is the same as duplicate md-is-locked-open attribute and rename it.

@ThomasBurleson @topherfangio thoughts?

edit: nvm my comment, out of scope.

+1 for reopening.

I've used md-is-locked-open attribute to handle the for lock and unlock scenario. My layout looks like this
screen shot 2016-01-31 at 8 57 58 pm

Using thetoggle() function works, but there is a glitch there. When the right sidenav closes, there is a flicker on the screen. Here is the snippet.

dash.toggleSidenav = function (menuId) {
      console.log("Toggle")
      $mdSidenav(menuId).toggle();
      if(menuId == 'right')
      dash.openInfo = !dash.openInfo;
   };

      <md-sidenav class="md-sidenav-right md-whiteframe-z2" md-component-id="right" md-is-locked-open="dash.openInfo">

The flicker is caused due to md-backdrop coming up for a small time before the sidenav is closed when the value of md-is-locked-open is toggled.

So I used open and close independently to avoid having that flicker.

dash.openSideNav = function(){
  dash.openInfo = !dash.openInfo;
  $mdSidenav('right').open();
};

dash.closeSideNav = function(){
  $mdSidenav('right').close().then(function(){
    dash.openInfo = !dash.openInfo;
  });
};

But using the above code, there is a considerable delay after pressing the close button and the sidenav closing.

One more method I used was to add ng-hide attribute to the sidenav itself and use dash.openInfo to toggle the sidenav. But that basically doesn't animate the open/close.

I think this is also related #3027. We should be able to toggle the sidenav independent of md-is-locked-open attribute, and without messing around with css values of md-backdrop.

@EladBezalel Sorry for the delayed response, I do feel like this is a valid request because we do not currently implement any animation for this, and as users are saying, it is difficult to achieve.

That said, we should definitely put some thought into how to best support all scenarios. It seems like we want the following use cases, and the ability to switch between them easily:

  1. Always Visible - In-layout/on screen.
  2. "Pinned" - Able to hide/reveal and cover content.
  3. "Drawer" - Able to hide/reveal and push content.

I am going to reopen so that we can continue the discussion on how to support this.

+1 reopen

In an ideal world, i would like the possibility to mix the behaviors, as you said @topherfangio "pinned" on smaller screens, then "drawer" on bigger ones.

With an option to show or hide the sidenav when the page first loading happens, but not necessarily locked.
Thx for your work guys.

This issue is closed as part of our 鈥楽urge Focus on Material 2' efforts.
For details, see our forum posting @ http://bit.ly/1UhZyWs.

There is an issue with md-is-locked-open, it prevents toggle when clicked outside somewhere else on the screen.

Was this page helpful?
0 / 5 - 0 ratings