What do The New York Times' developers get wrong about the hamburger menu, and what do Disney's and Wikipedia's get right?
As far as I know, I've found only one way to style the hamburger menu's open state that supports iOS Safari. (Presumably, you want a mobile view to work on iPhones!)
It's all about how the hamburger menu is positioned.
The Problem with Many Hamburger Menus
If your hamburger menu has no need for scroll... Congratulations! The CSS solution you're thinking of now will probably work just fine: position the sidebar absolutely out of and into the viewport when the user clicks on the menu icon.
If your menu has more items than the viewport can display at once, this is what happens when your hamburger menu is positioned absolutely:
If you don't want to watch the video, I'll try and describe it in words.
Scrolling within the
position: absolute
menu is unpleasant: it does not scroll smoothly, and when it reaches the end of scroll, it does not bounce in that satisfying, patented rubber-band way. Try the hamburger menus on New York Times, or PitchforkIf you overscroll in the hamburger menu, iOS Safari will scroll the body instead. Try the sidebar on Viki
If you tap beyond the menu, like scrolling on the sliver of main content exposed besides the sidebar, you will lose the ability to scroll within the menu. Try the hamburger menus on Grab
Notice how sometimes iOS scrolls the menu, sometimes it scrolls the body behind the menu? Frustrating!
And FWIW, you can break the scroll on Apple.com too. An easy way to trigger the scroll on the hamburger menu is to use your phone in horizontal.
The Solution
Basically, the key thing you must remember about the Menuβs final, open state is this: instead of positioning the menu absolutely, it will be the main content that is positioned once the sidebar is opened. In other words, instead of positioning the menu, position everything else!
Here is that in code, alongside explanatory comments:
<html>
<head></head>
<body>
<div class="sidebar">Hamburger menu links go here</div>
<div class="main-content"><button class="hamburger-menu-icon" onClick="toggleSidebar()">π</button></div>
</body>
</html>
/* Arbitrary CSS variable values for explanatory purposes */
:root {
--sidebar-width: 100px;
--sidebar-bg-colour: blue;
}
.sidebar {
display: none;
position: relative;
width: var(--sidebar-width);
}
@media (max-width: 767px) {
html.sidebar-is-open .sidebar {
display: block;
/*
The sidebar is just rendered in default position,
as it appears in the document flow
*/
}
html.sidebar-is-open .main-content {
position: fixed;
/*
It is the main content that is positioned.
This is the crux of the implementation. The rest is all sugar.
Cons: the body will scroll to the top, losing your user's scroll position
*/
/* prevents resizing from its original full-screen width */
bottom: 0;
left: 0;
right: 0;
top: 0;
width: 100%;
overflow: hidden;
}
/* Optional enhancement:
make the overscroll on iPhone the same colour as the sidebar */
html.sidebar-is-open body {
background-color: var(--sidebar-bg-colour);
}
.sidebar {
background-color: var(--sidebar-bg-colour);
}
}
const documentElement = document.querySelector("html");
const contentElement = document.querySelector(".main-content");
const sidebarElement = document.querySelector(".sidebar");
const sidebarIsOpen = () => documentElement.classList.contains("sidebar-is-open");
const openSidebar = () => {
/* How you trigger the change is up to you */
documentElement.classList.add("sidebar-is-open");
};
const closeSidebar = () => {
documentElement.classList.remove("sidebar-is-open");
};
const toggleSidebar = () => {
sidebarIsOpen() ? closeSidebar() : openSidebar();
};
Conclusion
So far I've found two big players who get it right: Wikipedia and Disney USA
Try their hamburger menus on iOS and see what a great experience the scrolling is!
Hopefully you can spread the word, and fix hamburger menus from now on.
(Side note: Or maybe we can just kill them altogether as a UI solution, since it hasn't bothered enough people to be worth fixing. Is anyone even using these things? Consider tab bars instead, see spotify's example)
If you're more of a beginner, you can find an explanation of what a hamburger menu is and how to build a hamburger menu from scratch on my blog.
Top comments (13)
I just use this to lock the body on mobile:
github.com/willmcpo/body-scroll-lock
and the css
overscroll-behavior: contain;
to prevent overscrollIt's probably worth noting overscroll is still in the draft phase even if support is surprisingly good.
There are a lot of "drafts" already implemented. They do it for mainly two reasons:
My view: in a lot of cases you could get rid of the navigation altogether.
If your page has good UX and leads you through journeys effectively then in theory your user would never need to open up a menu to find something. If they do need to then search should be sufficient.
We were toying with the idea of a conversational UI in a recent project where the user would only have access to a search bar which would filter the content on the page. Never got to test this idea but it definitely solves the burger problem!
Apple should fix their scroll issues. iOS and scrolling is a nightmare to work with.
Safari in general is a nightmare, both on desktop and mobile
So many obscure bugs.. It does have good js and css support though, so it's a double edged sword.
Safari: It just works! Until one day, the screen turns white for no apparent reason and you have to do something completely nonsensical to fix it.
Had to put in a crazy hack the other day as Safari doesn't calculate the scroll height correctly when images spend some time loading and the resulting scroll height is less than 100vh (100vh doesn't take the address bar into account). This hid some necessary navigation and rendered the app unusable in this very specific edge case.
To fix it I used a capturing load event listener and set position fixed before resetting the positioning. Nasty business.
I was expecting the answer to be "implementing a hamburger menu to start with".
There are some good alternatives available.
Working fine on Android :)
NYT and Gab both have issues in Chrome on Android.
For NYT, the page content scrolls when the hamburger menu over scrolls.
For Gab I was sometimes able to scroll in the sliver of content on the right. After that, menu scrolling was broken and I was even able to scroll horizontally with the menu open, which was weird.
Given that iOS is the lesser-used mobile operating system, I'd say it's up to them to fix their bugs, not up to all the web developers to work around Apples behavior.
It's also worth noting that you're on an iPhone and it's common sense to add a class to see the body to fixed whilst the menu is open.
iOS momentum scrolling.
-webkit-overflow-scrolling: touch;