7

When using the fixed top navigation of bootstrap 3, I noticed that when users use the native zoom on mobile, the top navigation also becomes very large. This leads to a pretty poor user experience, where the navigation obscures much of the content and ends up broken itself, as the following example shows:

fixed top navigation blows up when native zoom is used in the mobile browser

The issue can be seen in the wild on http://www.exploretrade.info/ and also seems to affect many other sites using this kind of navigation; a common solution is to disable user zoom, but this hurts accessibility of the site.

My question is: how do I keep the displayed size of the fixed top navigation constant when a user is zooming the contents on mobile

  • Using JavaScript, one can calculate the current device zoom applied, and dynamically update the css transform: scale directive 2
  • However, this appears not to work for position: fixed element, which end up somehow centered in the screen after scaling down
flexponsive
  • 6,060
  • 8
  • 26
  • 41
  • A closely related problem: http://stackoverflow.com/questions/13169593/mobile-fixed-topbar-on-zoom-in-out?rq=1, however also not solved – flexponsive Jan 16 '15 at 17:20

2 Answers2

2

Keeping Bootstrap's navbar-top-fixed from zooming on mobiles

The final result: using css transform to keep fixed top header at constant size after zoom

On mobile devices only, is possible to calculate the zoom factor as the ratio of window.innerWidth and the screen width, as shown in [2]. When the user toggles zoom, the resize event is triggered; moreover, when a page is reloaded that was previously zoomed, the zoom factor is maintained. Thus, one use jQuery to dynamically update CSS transforms that keep the header in shape. Note that, with position: fixed, a transformation of the origin is also required. Applying class device-fixed-height to the bootstrap nav and device-fixed-width to brand logo and hamburger icon then produce very close to the desired result.

  • Bug: As the page is zoomed, the hamburger icons still moves a bit to the left. Any suggestions how to fix it are appreciated!
  • Tested on: Android 4.4

Live example: http://www.exploretrade.info/other/example-fixed-nav-after-zoom.html

Source code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <link rel="icon" href="../../favicon.ico">

    <title>Bootstrap zoom-proof fixed top nav</title>

    <!-- Bootstrap core CSS -->
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">

    <!-- Custom styles for this template -->
    <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
    <style>
    body {
     padding-top: 50px;
    }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top device-fixed-height">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed device-fixed-width" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
             <i class="fa fa-bars"></i>
          </button>
          <a class="navbar-brand device-fixed-width" href="#">Example</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse device-fixed-width">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#about">About</a></li>
            <li><a href="#contact">Contact</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>
    <div class="container">
      <div class="starter-template">
        <h1>Bootstrap starter template</h1>
        <p class="lead">Use this document as a way to quickly start any new project.<br> All you get is this text and a mostly barebones HTML document.</p>

        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In in metus eget nisi imperdiet dictum ac eu metus. Morbi consequat sodales porta. Nam convallis sed dolor in ullamcorper. Vestibulum ut tortor porttitor, venenatis nulla iaculis, sollicitudin metus. Mauris ut hendrerit purus, sed ultricies lacus. Proin imperdiet, lectus vel efficitur hendrerit, quam tortor efficitur sapien, vehicula viverra magna ipsum vitae lacus. Sed faucibus elit vel massa placerat, in porttitor est suscipit. Pellentesque consequat condimentum elit, at sagittis erat euismod nec. Fusce consequat purus quis turpis volutpat, vel luctus tortor consectetur. Sed in lectus vitae enim fringilla faucibus. Mauris vitae risus ut ex convallis luctus. Interdum et malesuada fames ac ante ipsum primis in faucibus. Etiam tempor ante augue, sed iaculis nisi porta quis.</p>
      </div>

    </div><!-- /.container -->


    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
    <script>

// from https://signalvnoise.com/posts/2407-device-scale-user-interface-elements-in-ios-mobile-safari
function getDeviceScale() {
    var deviceWidth, landscape = Math.abs(window.orientation) == 90;
    if (landscape) {
      // iPhone OS < 3.2 reports a screen height of 396px
      deviceWidth = Math.max(480, screen.height);
    } else {
      deviceWidth = screen.width;
    }
    return window.innerWidth / deviceWidth;
}

// mobile only - keep the position:fixed header at constant size when page is zoomed
if (navigator.userAgent.match(/Mobi/)) {
    $(window).on('load scroll', function() {
        var ds = getDeviceScale();
        $('.device-fixed-height').css('transform','scale(1,' + ds + ')')
            .css('transform-origin', '0 0');
        $('.device-fixed-width').css('transform', 'scale(' + ds + ',1)')
            .css('transform-origin', '0 0');
        })
}

  </script>
    </script>
  </body>
</html>
flexponsive
  • 6,060
  • 8
  • 26
  • 41
  • 1
    And if you want to keep the navbar with and position "fixed", you can add in the following line of code into your `$(window).on('load scroll')` function: `$('.device-fixed-height').css({'left':$('body').scrollLeft()+'px','width':window.innerWidth+'px'});` and you will get a fixed navbar that really stays fixed (including size) – Troy Morehouse Jun 14 '15 at 17:47
  • @TroyMorehouse how does that help? if I insert the code block, it merely leads to the header moving off to the right (was not a problem before). Android 4.4 / Chrome – flexponsive Jun 16 '15 at 18:18
  • For me (Android 4.4, Chrome browser), it keeps the fixed top navbar looking almost identical as if the screen was not zoomed (although there are some scaling issues on the dropdown navigation widths). This Basically keeps the width of the navbar at 100% of the visible viewport width. – Troy Morehouse Jun 18 '15 at 00:53
  • 1
    I tried the above code with my Android 6.0.1, and it doesn't work. Zooming the page, it zooms the navbar too... – Fabio Marzocca Jul 03 '17 at 09:45
  • @user3096626 Could you add a runnable code snippet in the answer, so that we can easily run it / test it on various devices? Thanks in advance. – Basj Feb 20 '18 at 15:45
  • @FabioMarzocca Have you finally found a solution (I haven't). – Basj Feb 20 '18 at 15:45
  • I tried the full HTML code given here on Chrome / Android. The UI is not very good: during zoom-pinching on mobile devices, the top navbar resizes, **then** when I stop pinching it restores the normal size. But the navbar doesn't stay sticky at the top of the viewport. Not really usable (at least for me). Interesting and difficult question though! – Basj Feb 20 '18 at 15:53
-1

The problem that you're seeing is because of the interaction between the header on the content div. The header is overlapping the content panel so when you zoom the header gets bigger and overlaps more content. If you separate the nav from the content it will probably solve your problem. The baseline bootstrap nav should be setup that way where the nave is above the main content container.

Remove the fixed position from the nav. Delete this:

position:fixed;

Remove the margin on the bottom of the nav:

margin-bottom: 27px;

Now your nav and content don't overlap and things zoom in a cleaner fashion. You also may want to add the img-responsive class to your logo which will help it scale correctly so it doesn't overlap the menu button on mobile.

Joe W
  • 2,773
  • 15
  • 35
  • It is possible to prevent dialogs from zooming, e.g. http://stackoverflow.com/questions/15233076/prevent-that-a-fixed-element-resizes-when-zooming-on-touchscreen - so there is hope for the header ;) and thanks for the help. however, the ``nav`` is outside the main container and ``img-responsive`` class did not help. the search continues.. – flexponsive Jan 16 '15 at 17:12
  • I may be missing something but it looks to me like the div with an id of "home" overlaps the nav bar. Inspecting in chrome that home div does overlap the nav. The padding on there is pushing your content down but it looks like they are occupying the same space. Throw a z-index-1 on your nav and it dissapears behind home. That wouldn't happen if they didn't overlap. – Joe W Jan 16 '15 at 17:28
  • See edited answer for a more detailed attempt based on your html. – Joe W Jan 16 '15 at 17:34
  • thanks for the update, but I want to keep ``position:fixed`` for the header - merely prevent it from becoming bigger when the rest of the page is zoomed. I had some success with CSS transform and will post my current partial solution separately. – flexponsive Jan 16 '15 at 18:56
  • Can you provide a runnable code snippet? Thanks a lot in advance @JoeW. – Basj Feb 20 '18 at 15:43