162
votes

I'm building a iPhone Web Application and want to lock the orientation to portrait mode. is this possible? Are there any web-kit extensions to do this?

Please note this is an application written in HTML and JavaScript for Mobile Safari, it is NOT a native application written in Objective-C.

14
The whole reason for building a web application and not a native app is so it can be cross platform, why would you build an iPhone specific web app, are you looking at writing extra code to lock out other phones???user903601
I'm interested in a solution that is for "small-screens" and not just for things that are 320px and made by apple.sheriffderek

14 Answers

71
votes

You can specify CSS styles based on viewport orientation: Target the browser with body[orient="landscape"] or body[orient="portrait"]

http://www.evotech.net/blog/2007/07/web-development-for-the-iphone/

However...

Apple's approach to this issue is to allow the developer to change the CSS based on the orientation change but not to prevent re-orientation completely. I found a similar question elsewhere:

http://ask.metafilter.com/99784/How-can-I-lock-iPhone-orientation-in-Mobile-Safari

97
votes

This is a pretty hacky solution, but it's at least something(?). The idea is to use a CSS transform to rotate the contents of your page to quasi-portrait mode. Here's JavaScript (expressed in jQuery) code to get you started:

$(document).ready(function () {
  function reorient(e) {
    var portrait = (window.orientation % 180 == 0);
    $("body > div").css("-webkit-transform", !portrait ? "rotate(-90deg)" : "");
  }
  window.onorientationchange = reorient;
  window.setTimeout(reorient, 0);
});

The code expects the entire contents of your page to live inside a div just inside the body element. It rotates that div 90 degrees in landscape mode - back to portrait.

Left as an exercise to the reader: the div rotates around its centerpoint, so its position will probably need to be adjusted unless it's perfectly square.

Also, there's an unappealing visual problem. When you change orientation, Safari rotates slowly, then the top-level div snaps to 90degrees different. For even more fun, add

body > div { -webkit-transition: all 1s ease-in-out; }

to your CSS. When the device rotates, then Safari does, then the content of your page does. Beguiling!

40
votes

This answer is not yet possible, but I am posting it for "future generations". Hopefully, some day we will be able to do this via the CSS @viewport rule:

@viewport {
    orientation: portrait;
}

Here is the "Can I Use" page (as of 2019 only IE and Edge):
https://caniuse.com/#feat=mdn-css_at-rules_viewport_orientation

Spec(in process):
https://drafts.csswg.org/css-device-adapt/#orientation-desc

MDN:
https://developer.mozilla.org/en-US/docs/Web/CSS/@viewport/orientation

Based on the MDN browser compatibility table and the following article, looks like there is some support in certain versions of IE and Opera:
http://menacingcloud.com/?c=cssViewportOrMetaTag

This JS API Spec also looks relevant:
https://w3c.github.io/screen-orientation/

I had assumed that because it was possible with the proposed @viewport rule, that it would be possible by setting orientation in the viewport settings in a meta tag, but I have had no success with this thus far.

Feel free to update this answer as things improve.

19
votes

The following code was used in our html5 game.

$(document).ready(function () {
     $(window)    
          .bind('orientationchange', function(){
               if (window.orientation % 180 == 0){
                   $(document.body).css("-webkit-transform-origin", "")
                       .css("-webkit-transform", "");               
               } 
               else {                   
                   if ( window.orientation > 0) { //clockwise
                     $(document.body).css("-webkit-transform-origin", "200px 190px")
                       .css("-webkit-transform",  "rotate(-90deg)");  
                   }
                   else {
                     $(document.body).css("-webkit-transform-origin", "280px 190px")
                       .css("-webkit-transform",  "rotate(90deg)"); 
                   }
               }
           })
          .trigger('orientationchange'); 
});
6
votes

I came up with this CSS only method of rotating the screen using media queries. The queries are based on screen sizes that I found here. 480px seemed to be a good as no/few devices had more than 480px width or less than 480px height.

@media (max-height: 480px) and (min-width: 480px) and (max-width: 600px) { 
    html{
        -webkit-transform: rotate(-90deg);
           -moz-transform: rotate(-90deg);
            -ms-transform: rotate(-90deg);
             -o-transform: rotate(-90deg);
                transform: rotate(-90deg);
        -webkit-transform-origin: left top;
           -moz-transform-origin: left top;
            -ms-transform-origin: left top;
             -o-transform-origin: left top;
                transform-origin: left top;
        width: 320px; /*this is the iPhone screen width.*/
        position: absolute;
        top: 100%;
            left: 0
    }
}
5
votes

Screen.lockOrientation() solves this problem, though support is less than universal at the time (April 2017):

https://www.w3.org/TR/screen-orientation/

https://developer.mozilla.org/en-US/docs/Web/API/Screen.lockOrientation

3
votes

I like the idea of telling the user to put his phone back into portrait mode. Like it's mentioned here: http://tech.sarathdr.com/featured/prevent-landscape-orientation-of-iphone-web-apps/ ...but utilising CSS instead of JavaScript.

2
votes

Maybe in a new future it will have an out-of-the-box soludion...

As for May 2015,

there is an experimental functionality that does that.

But it only works on Firefox 18+, IE11+, and Chrome 38+.

However, it does not work on Opera or Safari yet.

https://developer.mozilla.org/en-US/docs/Web/API/Screen/lockOrientation#Browser_compatibility

Here is the current code for the compatible browsers:

var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation;

lockOrientation("landscape-primary");
1
votes

While you cannot prevent orientation change from taking effect you can emulate no change as stated in other answers.

First detect device orientation or reorientation and, using JavaScript, add a class name to your wrapping element (in this example I use the body tag).

function deviceOrientation() {
  var body = document.body;
  switch(window.orientation) {
    case 90:
      body.classList = '';
      body.classList.add('rotation90');
      break;
    case -90:
      body.classList = '';
      body.classList.add('rotation-90');
      break;
    default:
      body.classList = '';
      body.classList.add('portrait');
      break;
  }
}
window.addEventListener('orientationchange', deviceOrientation);
deviceOrientation();

Then if the device is landscape, use CSS to set the body width to the viewport height and the body height to the viewport width. And let’s set the transform origin while we’re at it.

@media screen and (orientation: landscape) {
  body {
    width: 100vh;
    height: 100vw;
    transform-origin: 0 0;
  }
}

Now, reorient the body element and slide (translate) it into position.

body.rotation-90 {
  transform: rotate(90deg) translateY(-100%);
}
body.rotation90 {
  transform: rotate(-90deg) translateX(-100%);
}
0
votes
// CSS hack to prevent layout breaking in landscape
// e.g. screens larger than 320px  
html {
  width: 320px;
  overflow-x: hidden;
}

This, or a similar CSS solution, will at least preserve your layout if that is what you are after.

The root solution is accounting for device's capabilities rather than attempting to limit them. If the device doesn't allow you the appropriate limitation than a simple hack is your best bet since the design is essentially incomplete. The simpler the better.

0
votes

In coffee if anyone needs it.

    $(window).bind 'orientationchange', ->
        if window.orientation % 180 == 0
            $(document.body).css
                "-webkit-transform-origin" : ''
                "-webkit-transform" : ''
        else
            if window.orientation > 0
                $(document.body).css
                    "-webkit-transform-origin" : "200px 190px"
                    "-webkit-transform" : "rotate(-90deg)"
            else
                $(document.body).css
                    "-webkit-transform-origin" : "280px 190px"
                    "-webkit-transform" : "rotate(90deg)"
0
votes

Inspired from @Grumdrig's answer, and because some of the used instructions would not work, I suggest the following script if needed by someone else:

    $(document).ready(function () {

      function reorient(e) {
        var orientation = window.screen.orientation.type;
        $("body > div").css("-webkit-transform", (orientation == 'landscape-primary' || orientation == 'landscape-secondary') ? "rotate(-90deg)" : "");
      }
    $(window).on("orientationchange",function(){
        reorient();
    });
      window.setTimeout(reorient, 0);
    });
0
votes

I have a similar issue, but to make landscape... I believe the code below should do the trick:

//This code consider you are using the fullscreen portrait mode
function processOrientation(forceOrientation) {
  var orientation = window.orientation;
  if (forceOrientation != undefined)
    orientation = forceOrientation;
  var domElement = document.getElementById('fullscreen-element-div');
  switch(orientation) {
    case 90:
      var width = window.innerHeight;
      var height = window.innerWidth;
      domElement.style.width = "100vh";
      domElement.style.height = "100vw";
      domElement.style.transformOrigin="50% 50%";
      domElement.style.transform="translate("+(window.innerWidth/2-width/2)+"px, "+(window.innerHeight/2-height/2)+"px) rotate(-90deg)";
      break;
    case -90:
      var width = window.innerHeight;
      var height = window.innerWidth;
      domElement.style.width = "100vh";
      domElement.style.height = "100vw";
      domElement.style.transformOrigin="50% 50%";
      domElement.style.transform="translate("+(window.innerWidth/2-width/2)+"px, "+(window.innerHeight/2-height/2)+"px) rotate(90deg)";
      break;
    default:
      domElement.style.width = "100vw";
      domElement.style.height = "100vh";
      domElement.style.transformOrigin="";
      domElement.style.transform="";
      break;
  }
}
window.addEventListener('orientationchange', processOrientation);
processOrientation();
<html>
<head></head>
<body style="margin:0;padding:0;overflow: hidden;">
  <div id="fullscreen-element-div" style="background-color:#00ff00;width:100vw;height:100vh;margin:0;padding:0"> Test
  <br>
  <input type="button" value="force 90" onclick="processOrientation(90);" /><br>
  <input type="button" value="force -90" onclick="processOrientation(-90);" /><br>
  <input type="button" value="back to normal" onclick="processOrientation();" />
  </div>
</body>
</html>
-3
votes

Click here for a tutorial and working example from my website.

You no longer need to use hacks just to look jQuery Mobile Screen Orientation nor should you use PhoneGap anymore, unless you're actually using PhoneGap.

To make this work in the year 2015 we need:

  • Cordova (any version though anything above 4.0 is better)
  • PhoneGap (you can even use PhoneGap, plugins are compatible)

And one of these plugins depending on your Cordova version:

  • net.yoik.cordova.plugins.screenorientation (Cordova < 4)

cordova plugin add net.yoik.cordova.plugins.screenorientation

  • cordova plugin add cordova-plugin-screen-orientation (Cordova >= 4)

cordova plugin add cordova-plugin-screen-orientation

And to lock screen orientation just use this function:

screen.lockOrientation('landscape');

To unlock it:

screen.unlockOrientation();

Possible orientations:

  • portrait-primary The orientation is in the primary portrait mode.

  • portrait-secondary The orientation is in the secondary portrait mode.

  • landscape-primary The orientation is in the primary landscape mode.

  • landscape-secondary The orientation is in the secondary landscape mode.

  • portrait The orientation is either portrait-primary or portrait-secondary (sensor).

  • landscape The orientation is either landscape-primary or landscape-secondary (sensor).