diff --git a/src/components/sidenav/sidenav.js b/src/components/sidenav/sidenav.js index 1e85230d38..dc0f3925fd 100644 --- a/src/components/sidenav/sidenav.js +++ b/src/components/sidenav/sidenav.js @@ -247,6 +247,7 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, var lastParentOverFlow; var backdrop; var triggeringElement = null; + var previousContainerStyles; var promise = $q.when(true); var isLockedOpenParsed = $parse(attr.mdIsLockedOpen); var isLocked = function() { @@ -315,6 +316,8 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, parent[isOpen ? 'on' : 'off']('keydown', onKeyDown); if (backdrop) backdrop[isOpen ? 'on' : 'off']('click', close); + var restorePositioning = updateContainerPositions(parent, isOpen); + if ( isOpen ) { // Capture upon opening.. triggeringElement = $document[0].activeElement; @@ -323,16 +326,60 @@ function SidenavDirective($mdMedia, $mdUtil, $mdConstant, $mdTheming, $animate, disableParentScroll(isOpen); return promise = $q.all([ - isOpen && backdrop ? $animate.enter(backdrop, parent) : - backdrop ? $animate.leave(backdrop) : $q.when(true), - $animate[isOpen ? 'removeClass' : 'addClass'](element, '_md-closed') - ]) - .then(function() { - // Perform focus when animations are ALL done... - if (scope.isOpen) { - focusEl && focusEl.focus(); - } - }); + isOpen && backdrop ? $animate.enter(backdrop, parent) : backdrop ? + $animate.leave(backdrop) : $q.when(true), + $animate[isOpen ? 'removeClass' : 'addClass'](element, '_md-closed') + ]).then(function() { + // Perform focus when animations are ALL done... + if (scope.isOpen) { + focusEl && focusEl.focus(); + } + + // Restores the positioning on the sidenav and backdrop. + restorePositioning && restorePositioning(); + }); + } + + function updateContainerPositions(parent, willOpen) { + var drawerEl = element[0]; + var scrollTop = parent[0].scrollTop; + + if (willOpen && scrollTop) { + previousContainerStyles = { + top: drawerEl.style.top, + bottom: drawerEl.style.bottom, + height: drawerEl.style.height + }; + + // When the parent is scrolled down, then we want to be able to show the sidenav at the current scroll + // position. We're moving the sidenav down to the correct scroll position and apply the height of the + // parent, to increase the performance. Using 100% as height, will impact the performance heavily. + var positionStyle = { + top: scrollTop + 'px', + bottom: 'initial', + height: parent[0].clientHeight + 'px' + }; + + // Apply the new position styles to the sidenav and backdrop. + element.css(positionStyle); + backdrop.css(positionStyle); + } + + // When the sidenav is closing and we have previous defined container styles, + // then we return a restore function, which resets the sidenav and backdrop. + if (!willOpen && previousContainerStyles) { + return function() { + drawerEl.style.top = previousContainerStyles.top; + drawerEl.style.bottom = previousContainerStyles.bottom; + drawerEl.style.height = previousContainerStyles.height; + + backdrop[0].style.top = null; + backdrop[0].style.bottom = null; + backdrop[0].style.height = null; + + previousContainerStyles = null; + } + } } /**