25
votes

I have a fixed button for a CTA (call to action) at the bottom of my web page. Scrolling down the page on newer version of iOS, mobile Safari hides the bottom navigation bar (with back, forward, share, bookmark, and new tab buttons). If you click on the CTA button, instead of executing that action, mobile Safari shows the bottom nav bar.

As a solution, I was looking to alway force-show the bottom nav bar. Is there a way of doing this? Both Jack Threads when viewed on mobile, and Thread Flip's mobile site are able to pull this off when viewing an individual item.

I'm unable to reverse engineer this so far. Does anyone know how the force-show is accomplished?

Related to: Buttons aligned to bottom of page conflict with mobile Safari's menu bar and Prevent Mobile Safari from presenting toolbar when bottom of viewport is tapped

6

6 Answers

20
votes

I think I may have found an answer. Setting your content to have the following styles:

  • height: 100% (allows content to fill the viewport and go beyond the bottom)
  • overflow-y: scroll (allows you to scroll below the viewport; the default value is visible)
  • -webkit-overflow-scrolling: touch (to smooth any scroll behavior)

appears to force the iOS menu in Safari to always appear. That way, button clicks will actually work instead of opening up the Safari menu.

Unfortunately, you have to pair this CSS with JavaScript browser detection because it messes up the scrolling on iOS Chrome (also webkit). There's no way to target all versions of iOS Safari only using only CSS.

4
votes

My answer is, don't try.

Whilst Jon Catmull's answer technically does force the browser to retain the bottom toolbar. In trials I've experienced a massive performance drop following that setup.

An example of this is with https://www.contiki.com/uk/en, the toolbar appears permanently but the performance loss is noticeable between Chrome and Safari.

After investigating other websites it seems that the world has just accepted that this double-click is a necessary evil.

https://www.bbc.co.uk/news, breaking news appears at the bottom of the browser, if the ui is minimised, the first click returns the bottom toolbar, the second click goes through to the article.

amazon, ebay etc the toolbar is minimised as per the browser defaults. Any clicks to links in the bottom ~30 pixels enable the toolbar.

Whilst there are technical solutions in other answers here, I don't think the double click compares to the performance loss

3
votes

I'm pasting in a solution mentioned at https://benfrain.com/the-ios-safari-menu-bar-is-hostile-to-web-apps-discuss/#comment-119538 in relation to how this is done for https://app.ft.com:

The trick was adding height: 100% to html, and body, and anywhere in the css where it was using 100vh. No js browser detection needed as it causes no quirks in iOS Chrome, Safari fullscreen, or on Android browsers.

2
votes

I'm having this same issue. We're working to implement a bottom navigation on our site and safari is giving us problems because tapping the bottom of the screen opens Safari's bottom nav, forcing users to click twice. The best solution we've come up with has been to add a 44px space below the navigation which looks really bad. It would be nice if I could force safari's navigation to stay open so it could fill that space instead of an essentially useless empty block.

2
votes

I believe the height: 100% is the way to go. It seems this seems to make Safari think that it might as well show the bar as no content is trying to go behind it, and then you add scroll within you 100% height element.

My issue was different as my button was in a fixed position modal, I didn't want the Safari bottom nav to show all the time but when my mobile filter nav opened it needed to be shown.

Essentially applying the code below (e.g. on menu-open class). and then positioning menu as position: fixed and height: 100%

html.menu-open {
    height: 100%;

    body {
        position: fixed;
        width: 100%;
        top: 0px;
        overflow: hidden;
    }
}

.menu {
    position: fixed;
    height: 100%;
    width: 100%;
    overflow: auto;
}

working example here:

https://www.electronicsadvisor.com/products/51/washing-machines-tumble-dryers

  1. Open link
  2. scroll down to hide safari bottom nav
  3. click the filters button near the top of screen

The Filter menu will open and force the safari nav open.

Screenshots from example:

Before the filter button clicked:

nav closed pre filter open Then when opening nav with js I apply styles above and the nav is forced open nav forced open

2
votes

Theres a better solution to this problem(i think). I check the windows's innerHeight on pageload. On scroll, if the height increases at least 50px, i can raise the button 25px. 25px appears to be the sweet-spot for this, you need to touch the very bottom of the button to show the toolbar. Here is a live demo and the code: https://visztpeter.me/demos/ios.html

<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Fix tap for button at the bottom in iOS Safari when the toolbar is gone</title>
    <style type="text/css">
      div {
        margin:20px;
        height:2000px;
        background:gray
      }

      button {
        position:fixed;
        bottom:0;
        left:0;
        right:0;
        height:48px;
        background:blue;
        border:none;
        transition: all ease 0.2s;
      }
      
      .ios-toolbar-gone button {
        transform: translateY(-25px);
      }
    </style>
  </head>
  <body>
    <div></div>
    <button></button>
    <script>
      var baseWindowHeight = Math.max(window.innerHeight);
      var classAdded = false;
      var documentBody = document.body;
      document.addEventListener('scroll', function(e){
        var newWindowHeight = Math.max(window.innerHeight);
        if(newWindowHeight-50 > baseWindowHeight) {
          if (! documentBody.classList.contains("ios-toolbar-gone")) {
            documentBody.classList.add("ios-toolbar-gone");
          }
        } else {
          if (documentBody.classList.contains("ios-toolbar-gone")) {
            documentBody.classList.remove("ios-toolbar-gone");
          }
        }
      });
    </script>
  </body>
</html>