Javascript – How to fit to screen after changing viewport width on orientation change

androidiosjavascriptmobiletablet

I need the viewport width for a page to be 950px in landscape and 630px in portrait. These pixel widths are unfortunately inflexible.

I'm adjusting the width of the DOM content based on orientation using CSS media queries.

I'm listening for orientation change events in JS to resize the viewport on orientation change.

Everything looks good on initial page load (portrait or landscape).

However, after an orientation change, Mobile Safari preserves the previous scale setting, instead of fitting the viewport to the screen. A double-tap or two straightens it out. But I need that to be automatic.

I've attached the source below, and uploaded it to a demo URL.

Below are screen captures taken after orientation changes: from landscape to portrait, and from portrait to landscape.

How can I force Safari to automatically set the viewport width to the screen width? Or am I going about this all wrong?

Changing the various scale settings in the viewport have not helped. Setting maximum-scale=1.0 or initial-scale=1.0 appears to override my width, setting width to device-width (i.e. 1024 or 768 on my iPad 2), leaving dead margin space. Setting minimum-scale=1.0 appears to do nothing.

From landscape to portrait

From portrait to landscape

<!DOCTYPE html>
<html>
    <head>
      <title>iPad orientation</title>

      <meta name="viewport" content="user-scalable=yes">

      <script src="jquery-1.4.2.min.js" type="text/javascript"></script>

      <script type="text/javascript" charset="utf-8">;
        /**
        * update viewport width on orientation change
        */
        function adapt_to_orientation() {
          // determine new screen_width
          var screen_width;
          if (window.orientation == 0 || window.orientation == 180) {
            // portrait
            screen_width = 630;
          } else if (window.orientation == 90 || window.orientation == -90) {
            // landscape
            screen_width = 950;
          }

          // resize meta viewport
          $('meta[name=viewport]').attr('content', 'width='+screen_width);
        }

        $(document).ready(function() {

          // bind to handler
          $('body').bind('orientationchange', adapt_to_orientation);

          // call now
          adapt_to_orientation();
        });

      </script>
      <style type="text/css" media="screen">
        body {
          margin: 0;
        }
        #block {
          background-color: #333;
          color: #fff;
          font-size: 128px;

          /* landscape */
          width: 950px;
        }
        #block .right {
          float: right
        }
        @media only screen and (orientation:portrait) {
          #block {
            width: 630px;
          }
        }
      </style>
    </head>
    <body>
      <div id="block">
        <div class="right">&rarr;</div>
        <div class="left">&larr;</div>
      </div>
    </body>
</html>

Best Answer

I had this problem and wrote some JavaScript to fix it. I put it on Github here:

https://github.com/incompl/ios-reorient

Here is the code for your convenience:

window.document.addEventListener('orientationchange', function() {
  var iOS = navigator.userAgent.match(/(iPad|iPhone|iPod)/g);
  var viewportmeta = document.querySelector('meta[name="viewport"]');
  if (iOS && viewportmeta) {
    if (viewportmeta.content.match(/width=device-width/)) {
      viewportmeta.content = viewportmeta.content.replace(/width=[^,]+/, 'width=1');
    }
    viewportmeta.content = viewportmeta.content.replace(/width=[^,]+/, 'width=' + window.innerWidth);
  }
  // If you want to hide the address bar on orientation change, uncomment the next line
  // window.scrollTo(0, 0);
}, false);