angular/components

(sidenav) elements with `position: fixed` inside `md-sidenav-layout`

fxck opened this issue Β· 49 comments

fxck commented

Because of transform: translate3d(0, 0, 0) on md-sidenav-layout any element with position: fixed inside it will act as if it had position: absolute or static instead. It's an expected behaviour, but it's annoying nevertheless.

Could we either remove that transform from md-sidenav-layout(it's only there because of performance I suppose), or add more examples to Portal and mention it as a workaround in docs, since portal could probably solve this by basically putting the element that needs to be fixed next to the md-sidenav-layout in the dom tree.

cc @hansl @jelbourn

fxck commented

https://gist.github.com/fxck/b668f7fec77d7b28d8c7ce6b706601f7

here's a component that takes whatever is inside it and puts it to the body using material2 overlay

fxck commented

@jelbourn this is still a thing, can you label it please?

We need to discuss whether we consider this a bug or not.

In my opinion this is a bug insofar as it is the equivalent of putting a ban on fixed elements. I am now trying to create a fab button on the bottom right corner of the screen. Because of this issue I'm unable to do so unless I use solution provided by @fxck

Is the workaround from @fxck still working?
I am getting EXCEPTION: Must provide a portal to attach...

I recommend just absolutely positioning the fab outside the scrollable region: http://plnkr.co/edit/VItn3Y2AaTzpzIykTTyH?p=preview

that's clever @mmalerba but it wouldn't work in my case. My button is inside a router outlet as the fab is not always needed. Your solution would work great for cases where fixed elements should be visible in every view though.

Also, it would mean a lot of boilerplate to pass events to other components within the scrollable area

@bergben it is. I'm using material alpha 10 and it still works. It took me a bit to get it working though. Could you post what you have?

@cortopy
It was kinda late yesterday, the problem was that I simply forgot to import the Directive as well πŸ˜„
Got some other problem now though that the sidebar is not opening / visible / whatever...
What I got now is this:

<md-sidenav-layout [ngClass]="{'administration' : isLoggedIn}">
    <md-sidenav #sideNav mode="push" [hidden]="!isLoggedIn" opened="true">
        <noe-admin-sidenav>
        </noe-admin-sidenav>
    </md-sidenav>
    <fnls-displacer [sideNav]="sideNav">
            <noe-admin-topnav [sideNav]="sideNav" *ngIf="isLoggedIn">
            </noe-admin-topnav>
            <div class="content-wrapper">
                <router-outlet></router-outlet>
                <noe-footer></noe-footer>
            </div
    </fnls-displacer>
</md-sidenav-layout>

How exactly do I have to wrap the content with the displacer to get it to work?
I also had to add this css to make the fixed content work:

.md-overlay-pane{
    width:100%;
}
.md-overlay-container{
    position:absolute !important;
}

Still couldn't resolve this. Seems like this wasn't a problem with the angular 1 version of the sidenav...
Problem is, I don't only have one button that is fixed but the whole content is fixed for a certain time as I am using https://github.com/bergben/ng2-scrollimate to apply animations on the fly during scroll. So if I displace that all then there is nothing left anymore in md-sidenav-content and the sidenav itself doesn't work anymore...

#1966 adds a sidenav with fab example

fxck commented

@mmalerba Having a scroll inside content rather than on body brings a lot problems with UX and with fixed elements(various cases when fixed element is actually overlaying the scrollbar, or regions that appear part of scrollable areas but are not, so you are scrolling on them and the page doesn't scroll), also there are potential problems / extra set up on phones for smooth scrolling required, potential double scrollbars... meh. All this because of an unnecessary transform: translate3d(0, 0, 0). πŸ‘

Take my directive, name it something better, make it a structural directive for easier use and add it to the core. It just puts everything inside it in a Overlay, nothing more, doesn't break binding in any way. Problem solved. Usable on many other places.

I do think separate scrolling areas should be the recommended solution for this. If I have a lot of content in my sidenav I probably want it to scroll independently from my content area. However I do think it currently requires a bit too much work to set up, I would like to make it easier if possible. I'm also not opposed to removing the translate3d if it really is superfluous (I need to investigate) so that people can use the fixed positioning solution if they prefer.

@jelbourn Do you have any opinions on this?

@mmalerba This solution only works if you have relatively simple fixed content, if you have it spanning over the whole page or stuff like that it just gets too complicated. What I find interesting though is that this problem didn't seem to come up in the Angular 1 version of the sidenav - as I was searching through the issues there.
The translate3d could be replaced with a simple animation and basic distance property to fix this problem for good...
I don't know though why the translate3d breaks a css position in the first place, this is surely a misbehavior of CSS in the first place IMO, but that's another topic.

I am using angular 2 material design, pls give a solution base on angular 2 material design and not material 1

@bergben I'm not sure I understand your template.

Simplifying a lot this is what I have in app.component.html:

<md-sidenav-layout>
    <md-sidenav #start mode="side">
      <my-sidenav></my-sidenav>
    </md-sidenav>

    <router-outlet></router-outlet>
 </md-sidenav-layout>

And then in a template for a component that gets loaded by the router I have:

<fnls-displacer>
      <button></button>
</fnls-displacer>
fxck commented

Yeah you got that right @cortopy there are no inputs on displacer itself, it's literally just "take whatever is inside me and append it to body". It doesn't break bindings or anything, so it's as if you were wrapping it in a div. What I think he's doing is wrapping the whole router-outlet inside it, which I'm not surprised at all that doesn't work. It's really intended for buttons/modals/whatever you need appended to body from inside the router outlet.

cc @bergben

@johnl242 don't forget to style your button!! The displacer doesn't do anything in terms of styling or positioning. This is what I have

  bottom: 1rem
  position: fixed
  right: 1rem
  transform: translateZ(0)

@johnl242 I think it would be better if you post some code to see what you have so that people can actually help you.

@cortopy @fxck Thanks but I realized the displacer is no solution for me as the content is only fixed during a certain period of time and the rest of the time it is normally positioned inside some other content. As said I am using ng2-scrollimate to create some scrolling effects which also include having an element fixed for a certain period of scroll only. Porting that element to the body does not offer a solution as it breaks the whole layout. So I guess I'll have to wait for a solution that does not use transform: translate3d

pretty please remove transform: translate3d from the .md-sidenav-content class?

So, what's the solution?

.mat-tab-body-content of md-tab-body has transform: translate3d(0px, 0px, 0px); as well. Thus trying to add a FAB inside of tab container is also a problem.

Any update on this? I would need to have a FAB button floating while user scrolls down the page.

CSS transform on .mat-sidenav-content creates a new local coordinate system.
For now I use this workaround.

.mat-sidenav-content {
    transform: none !important;
}

Currently having to override globally

.mat-sidenav-container, .mat-sidenav-content {
    transform: none !important;
    transition: none !important;
}

@Defmetalhead removing the transition screws up the sidebar content animation when you toggle the menu. In my case using just

.mat-sidenav-container, .mat-sidenav-content {
    transform: none !important;
}

was all I needed to get the position: fixed to work. Just a heads up to anyone who just copy/pastes this without noticing the side effect.

@radoslavpetranov I do not experience the issue with the sidebar animation, but you are correct in the fact that only "transform" needs to be overwritten.

Just a note this is also causing change in behavior in other libraries as well. http://wijmo.com/topic/how-to-prevent-window-scroll-to-top-on-wijmo-flexgrid-click-event/

It is actually breaking bindings, a form submit type=submit button.

If I manually submit through a (click) it works, but the submit itself, it gets it out of context.

I use a third party charting library in the content and the transform breaks all their mouseover tooltips in certain container structures.. It also causes full page flickers in IE 11 when their tooltips are active. Turning off the 3d transform fixes all these things. What does it do? Is it necessary?

using transform will (on some devices) trigger to use hardware acceleration.. feels like a good incentive to keep it.. ?

With the latest release the component @fxck built no longer works due to the TemplatePortal changes. Can we get an updated version as a patch until this is resolved. Also, just removing transforms via CSS no longer seems to be a valid work around.

the transform fix still works for me but they changed the class names from .mat-sidenav-* to .mat-drawer-* so you probably have to update your css

Yeah looks like I missed one of the .mat-drawer classes. Working now. Thanks!

Im surprised we still have to do workaround at this point.
this is like a year old bug

@CDDelta nice! now just have to wait for the approval

@CDDelta Excellent!

aaaah maaaaan.. just I did this like 3 weeks ago! πŸ˜†
But still.. Great work πŸ‘Š πŸ˜„

Great that it'll be fixed soon.
Meanwhile after updating to 2.0.0-beta.10:

.mat-sidenav-content,
.mat-sidenav-container,
.mat-drawer-content {
    transform: none !important;
}

I given this
.mat-sidenav-content,
.mat-sidenav-container,
.mat-drawer-content {
transform: none !important;
}

But side-nav "push" is not working now

@sijithc40 It won't because "push" mode uses transform.

Material design light with version v1.0.1

After long searching and trying , problem solved by following code

.mat-sidenav-container,
md-sidenav-container div[style],
.mat-sidenav-content{
transform: none !important;
-webkit-transform: none !important;
}

I am using angular 2, so what should I do for this issue.....

Simply define width margin at mat-sidenav-content in styles.css file:

mat-sidenav-content {
    width: 100vw;
}

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.