foundation / foundation-sites

The most advanced responsive front-end framework in the world. Quickly create prototypes and production code for sites that work on any kind of device.
https://get.foundation
MIT License
29.66k stars 5.49k forks source link

Sticky menu looses it's stickiness when off-canvas menu opened (Foundation 6.3) #9629

Closed flummer closed 3 years ago

flummer commented 7 years ago

The combination of a sticky menu bar and off-canvas menu seems to have a bug in that the menu looses it's stickiness when the off-canvas menu is opened.

How to reproduce this bug:

  1. Scroll down a little
  2. Open off-canvas menu
  3. Top menu disappears (moves up to the top of the page, instead of top of the window)

What should happen:

I think the sticky top menu should stay sticky at the top of the window, but move out to the side as it rightfully does with the rest of the main content

What happened instead:

It moves out to the side with the rest of the main content, but attaches to the top of the page instead of staying at the top of the window.

Test case:

Notes:

In a previous version (6.2.4) the page scrolled up to the top, when the off-canvas menu was opened, but that is not ideal if you want to use the off-canvas menu for tools etc.

I like that the main content stays where it is, but the sticky top menu should too.

I'm fairly new to Foundation, so there might be a setting that I have missed, if so, please let me know.

ncoden commented 7 years ago

@brettsmason Is the new Off-canvas related to this bug ?

brettsmason commented 7 years ago

@ncoden I can confirm its a bug, but I'm pretty sure its to do with sticky rather than off canvas. @kball will know more I'm sure.

brettsmason commented 7 years ago

So I looked into this some more. It looks like this is an issue with position: fixed (set on the .sticky element) along with css transform.

The only workaround I can find is using JS to set the top position to the current scroll offset. See http://stackoverflow.com/questions/15194313/transform3d-not-working-with-position-fixed-children for an explanation

Also see this CodePen with the suggestion added: http://codepen.io/brettsmason/pen/ygXJYK (edited)

@kball I'm not sure what the best way to fix this would be. We could change the off canvas behaviour to not use translateX/Y and use another method, but I chose that as it gives the best performance across devices.

colin-marshall commented 7 years ago

@brettsmason I was thinking we could add an option to sticky for when it is being used with an off-canvas component and make it so that sticky behaves as you have it in your codepen only when that option is enabled. The option would be disabled by default. Thoughts?

brettsmason commented 7 years ago

@colin-marshall That sounds like a good solution. I guess maybe we don't name it specific for off canvas (or do we?) as it applies to any element that transforms, but maybe mention it in the description (and maybe a callout on the docs on both places).

I also noticed if you scroll fast on my CodePen the performance isn't the best - don't know if there's a better way to do it?

colin-marshall commented 7 years ago

@brettsmason I agree a more universal name like absoluteMode, transformMode, or stickyAbsolute would be better. Have you tested the new off canvas with non-menu sticky components to see if there is any bugs in other use cases?

What device and browser were you seeing poor scroll performance with?

brettsmason commented 7 years ago

@colin-marshall Would it somehow be possible to check if a parent container is transformed? And then if so set the position using JS, otherwise fall back to the CSS only. This would avoid any confusion with people not being able to get it to work, and we only want the JS positioning when off canvas (or a transformed container) is open.

I haven't tested with any other types of sticky use case, but I'll get some pens setup so we can check.

It was in Chrome for Windows - with fast scrolling it didn't seem to stick to the top quite like position: fixed did - sort of "bobbed" up and down a bit very slightly.

colin-marshall commented 7 years ago

@brettsmason you can check if the parent is transformed by just getting the CSS transform values for x and y and seeing if they are set to anything other than zero. The problem is that when off-canvas is opened and closed the menu is not actually becoming "unstuck" it just changes where it think it's supposed to be stuck at. So I'm not sure how it would know when to check if the parent is transformed.

This might be a good situation for the new mutation observers, but I need to learn how they work first. I have been meaning to get familiar with them so this poses a good opportunity for me to dig in to them.

colin-marshall commented 7 years ago

@brettsmason it looks like if you add -webkit-transform: translateZ(0) to the sticky element it might get rid of the weird behavior you see in Chrome. The SO post you linked had a link to another post (http://stackoverflow.com/questions/11258877/fixed-element-disappears-in-chrome) where the accepted answer talks about adding that to a position: fixed element to fix some wonky behavior. One of the comments says it worked for absolute positioning as well. I can't reproduce on Mac or else I would test.

Comment regarding absolute positioning: http://stackoverflow.com/questions/11258877/fixed-element-disappears-in-chrome#comment34523987_18764086

brettsmason commented 7 years ago

@colin-marshall When you have a bit of time can we discuss how we can get this into the next patch? 😄 👍

colin-marshall commented 7 years ago

@brettsmason I can actually see the "buggy" scroll behavior now. I think it's happening because it has to keep setting it to position absolute with every scroll event and it can't keep up with scrolling. I think first we need to see if this even fixable before we go dive into the rest of it. I'll work on it a bit today and see if I can come up with anything.

kball commented 7 years ago

@colin-marshall @brettsmason Would it be possible to change the positioning to use transform rather than x/y offset on absolute? That would prevent the browser from having to repaint every change and make it much easier to keep up.

colin-marshall commented 7 years ago

@kball that's a good idea but it still doesn't keep up very well. The plus side to this solution is that it only can't keep up when the menu is opened while with absolute positioning it was always an issue.

Example: http://codepen.io/colin-marshall/pen/apEaJR

When you close the menu there's a second where it goes off screen due to not having separate events for before and after the off-canvas is closed.

Another possible solution is to move the sticky menu outside of the off-canvas container and then translateX on the sticky menu in sync with the off-canvas menu. That would require the sticky plugin to know the value of $offcanvas-size beforehand. I tested this out a couple weeks ago and it worked good except the sticky element was not clickable when off-canvas was open so you had to click below the title-bar to get it to close. Maybe that's just a z-index issue?

kball commented 7 years ago

In your codepen I'm still seeing the top bar repaint as I scroll... if I add

.sticky {
   will-change: transform;
}

I can get rid of that. (see https://www.fourkitchens.com/blog/article/fix-scrolling-performance-css-will-change-property)

this doesn't help IE & Edge or old android (see http://caniuse.com/#feat=will-change) but may help for just about everything else... even turning on 'low-end device' level throttling in chrome devtools it appears to still keep up.

colin-marshall commented 7 years ago

@kball you meant it was only repainting when the off-canvas was open, correct?

I tried the will-change property and don't see a difference in Chrome. It's still repainting (or looks like it is) when off-canvas is opened.

kball commented 7 years ago

yes, it was repainting when the off-canvas was open... Can you verify if the repaint is happening using the dev tools? https://developer.chrome.com/devtools/docs/rendering-settings

colin-marshall commented 7 years ago

Repaint only happens when it hits the top of the page. If I scroll using the keyboard it stays perfectly in place like it does with position: fixed but scrolling with the Trackpad makes it choppy.

colin-marshall commented 7 years ago

@kball I was able to isolate the problem to my 2015 15" Retina MacBook Pro with a discrete AMD Radeon R9 M370X graphics card. When I hook it up to an external monitor it works great but on the laptop screen it's choppy. Forcing it to use integrated graphics or discrete graphics doesn't make a difference either. So I guess this is an issue with my MacBook model more than anything else.

colin-marshall commented 7 years ago

@kball @brettsmason I started trying to add an event to trigger after the off-canvas menu close animation completes and I think we might need to add something like the timer that Orbit uses to detect when a slide is done transitioning in order to achieve this.

Or there might be some way to use a variable that tracks the translationX value of off-canvas content and triggers the event when it hits 0. Maybe mutation observers could do this? (calling @coreysyms)

What do you guys think?

kball commented 7 years ago

@colin-marshall have you tried using Foundation.transitionend?

colin-marshall commented 7 years ago

@kball that is exactly what I needed! I have it working pretty much flawless in Firefox and Safari. In Chrome, however, the burger icon jerks when the menu opens and you're not scrolled to the top of the page. When you close the off canvas in Chrome the title bar doesn't translate horizontally with the rest of the page content. It stays to the left and then snaps to the right when the transition finishes.

It was doing that before I added Foundation.transitionend it was just harder to notice because it jumped to the top first. I recorded a video of the behavior for you to see: https://www.dropbox.com/s/en5knqkwo453yoi/Sticky%20Off%20Canvas.mp4?dl=0

Chrome is the last one in the video.

dungle-scrubs commented 6 years ago

Hi, wondering if there's a solution to this issue yet?

sezarsaman commented 5 years ago

hi guys I can see that the bug is still alive!!!

WrapTheCode commented 5 years ago

Hi,

I have got a solution:

Move sticky/fixed div outside "off-canvas-content".

<div class="off-canvas-wrapper">
 <div class="off-canvas position-left" data-off-canvas id="offCanvasL">
   <!-- LEFT MENU -->
 </div>
 <div class="off-canvas position-right" data-off-canvas id="offCanvasR">
   <!-- RIGHT MENU -->
 </div>
 <div class="fixed_div">
   <div class="menu_left" data-toggle="offCanvasL"><!-- OPEN LEFT MENU  --></div>
   <div class="menu_right" data-toggle="offCanvasR"><!-- OPEN RIGHT MENU --></div>
 </div>
 <div class="off-canvas-content" data-off-canvas-content>
  <!-- YOUR CONTENT-->
 </div>
</div>

Then we need some CSS rules:

.fixed_div {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 10;
  transform: none;
  transition: transform .5s ease;
  backface-visibility: hidden;
}

.fixed_div.is-open-right.has-transition-push {
    transform: translateX(-250px);
}

.fixed_div.is-open-left.has-transition-push {
    transform: translateX(250px);
}

Last think that we need to do is add some JQUERY to ours app.js:

$('.menu_left').click(function() {
    $('.fixed_div').toggleClass('is-open-right has-transition-push has-position-right');
});
$('.menu_right').click(function() {
    $('.fixed_div').toggleClass('is-open-left has-transition-push has-position-left');
});
$('.close-button, .js-off-canvas-overlay').click(function() {
    $('.fixed_div').removeClass('is-open-right is-open-left has-transition-push has-position-right has-position-left');
});

and that is all :)

zeroblaz3 commented 5 years ago

WrapTheCode nailed it. Fixed this issue for me

rbrisita commented 5 years ago

I had a similar issue with Reveal and when scrolled down and activated data-open the top-bar would disappear. Quick fix:

<path to data-sticky element > {
    position: fixed !important;
    width: 100%
}