8

How to Create a Portrait Mode Only Mobile First Web App

 3 years ago
source link: https://spin.atomicobject.com/2021/07/22/portrait-mode-web-app/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

How to Create a Portrait Mode Only Mobile-First Web App

Not all native apps or mobile-first web apps are designed to work in both portrait and landscape orientations on mobile phones. While it would be nice to lock the screen orientation, there are no great ways to do that in a web app.

If you are developing a native app, this is easy. Check out this article.

Unfortunately, it is not so easy for mobile-first web apps. With the various screen sizes, device aspect ratios, and keyboard behaviors across platforms and browsers, you can spend hours pulling your hair out trying to get this to work. Believe me, I have.

Let me save you the tears and angry noises.

This post explores how to achieve a sane “X orientation mode only” solution for a mobile-first React web app. There are many ways to do this, and this method is not perfect.

Javascript or CSS?

There are some built in Javascript utilities for locking the screen orientation, such as screen.orientation.lock(orientation).

However, these are limited by both browser support and the need to operate in full-screen mode. Since we need iOS Safari as well as Android browsers, JavaScript solutions are too limited.

CSS it is!

CSS Media Queries

The @media (orientation:portrait) media query checks that the height of the screen is greater than or equal to the width. (See more details here: Media Queries Level 4)

Similarly, the `aspect-ratio` media query is the ratio of width to height of the media feature. The orientation media query is essentially an alias for @media screen and (min-aspect-ratio: 1/1) when checking for landscape mode.

Great! Except, not always. The problem you might run into when using either feature is that the height and width are of the viewport, not the device screen per se. So, when the soft keyboard is opened, for example, the height might be shorter that the width, which would evaluate to “landscape” mode. This problem also occurs when using a `aspect-ratio` media query.

After some research and looking around the internet, it looked like the better media query for detecting orientation barring differing soft keyboard and browser-specific Javascript behavior would be:
@media screen and (min-aspect-ratio: 13/9) { /* landscape mode */ }
@media screen and (max-aspect-ratio: 13/9) { /* portrait mode */ }

This worked for many of the standard phones. However, as device dimensions continue to drift, there are always exceptions. We call those the Problem Phones.

A Mostly Working Solution

Our exploratory tester, Phil Kirkham, takes great delight in hammering on our code from a desk full of phones of all shapes and sizes. He will tell you that we had Problem Phone after Problem Phone while getting this to work.

When the keyboard is opened on one of the Problem Phones, the viewport is 360×348, which is roughly an aspect ratio of 30/29. Because we are checking for a minimum aspect ratio on 13/9, this throws the app into landscape mode via the orientation query. To get around this, we want to say only compare the height and width if the width of the viewport is greater than 800px. This is an arbitrary number that is roughly greater than the majority of phone widths when held in portrait mode.

import {Grid, makeStyles, Typography} from "@material-ui/core";
import React from "react";

export const PortraitModeOnly: React.FC = props => {
  const classes = useStyles();
  return (
    <>
      <div className={classes.portraitMode}>{props.children}<div>
      <div className={classes.landscapeMode}>
        hey, flip your phone to portrait mode please!
      </div>
    </>
  );
};

const useStyles = makeStyles({
  portraitMode: {
    display: "none",
    "@media screen and (max-aspect-ratio: 13/9)": {
      height: "100%",
      width: "100%",
      display: "block",
    },
  },
  landscapeMode: {
    display: "none",
    "@media (max-width: 800px) and (min-aspect-ratio: 13/9)": {
      height: "100%",
      display: "block",
    },
  },
});

Achieving Portrait Mode

Now all you have to do is wrap your app with this component and choose what you want to display when the user is on the wrong screen orientation.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK