Published: February 28, 2014

<br />

There are a number of options you can use to create the perfect interface for
your WebView.

## Set the viewport meta tag

The viewport meta tag is of the most important tags to add to your web app.
Without it, the WebView may act as if your site is designed for desktop
browsers. This causes your web page to be given a larger width (typically 980px)
and scales it to fit the WebView width. In most cases, this results in a tiny
overview version of the page that requires the user to pan and zoom to actually
read content.

If you want the width of your site to be 100% of the WebView's width,
set the viewport meta tag:

    <meta name="viewport" content="width=device-width, initial-scale=1">

Set width to the special value device-width to gain more control over the page
layout.

By default, the WebView sets the viewport to device-width, rather than
defaulting to a desktop viewport. However, for reliable and controlled behavior,
it's good practice to include the viewport meta tag.

### Display desktop sites

In some cases, you may need to display content that isn't designed for mobile
devices. For example, you may display content you don't control. In this case,
you can force the WebView to use a desktop-size viewport:

- [setUseWideViewPort(true)](https://developer.android.com/reference/android/webkit/WebSettings.html#setUseWideViewPort(boolean))
- [setLoadWithOverviewMode(true)](https://developer.android.com/reference/android/webkit/WebSettings.html#setLoadWithOverviewMode(boolean))

If these methods are not set *and* no viewport is specified, the WebView attempts to set the
viewport width based on the content size.

In addition, you may want to use the layout algorithm `TEXT_AUTOSIZING`, which
increases the font size to make it more readable on a mobile device. See
[setLayoutAlgorithm](https://developer.android.com/reference/android/webkit/WebSettings.html#setLayoutAlgorithm(android.webkit.WebSettings.LayoutAlgorithm)).

## Use responsive design

[Responsive design](https://web.dev/learn/design/intro) is an approach to
designing an interface which changes based on screen size.

There are a number of ways to implement responsive design. One of the most
common is [`@media` queries](https://web.dev/learn/design/media-queries),
which applies CSS to elements based on a device's characteristics.

For example, suppose you wanted to go from a vertical layout to a horizontal
layout based on orientation. Set CSS properties to default to portrait:

    .page-container {
        display: -webkit-box;
        display: flex;

        -webkit-box-orient: vertical;
        flex-direction: column;

        padding: 20px;
        box-sizing: border-box;
    }

To switch to a horizontal layout, switch the flex-direction property based on
the orientation:

    @media screen and (orientation: landscape) {
      .page-container.notification-opened {
        -webkit-box-orient: horizontal;
        flex-direction: row;
      }

      .page-container.notification-opened > .notification-arrow {
        margin-right: 20px;
      }
    }

You can also change the layout based on screen width.

For example, adjusting the size of the button width from 100% to something
smaller as the physical screen size gets larger.

    button {
      display: block;
      width: 100%;
      ...
    }

    @media screen and (min-width: 500px) {
      button {
        width: 60%;
      }
    }

    @media screen and (min-width: 750px) {
      button {
        width: 40%;
        max-width: 400px;
      }
    }

These are minor changes, but depending on your UI, media queries can help you to
make much larger changes to appearance of your application, while keeping the
same HTML.

> [!TIP]
> **Tip:** Try to change the interface based on width as a component starts to look out of place, rather than focusing on device sizes. This helps your app look great on a range of devices, not just the ones you test on. You can test this in [DevToolsDevice Mode](https://developer.chrome.com/docs/devtools/device-mode).

## Crisp and clear images

The variety of screens sizes and densities also presents challenges for images.
Smaller images require less memory and are faster to load, but blur if you scale
them up.

Here are a few tips and tricks to make sure your images look crisp and clear
on any screen:

- Use CSS for scalable effects.
- Use vector graphics.
- Provide high-resolution photos.

### Use CSS for scalable effects

Use CSS whenever you can, instead of images. It's possible some
combinations of CSS properties can be expensive to render. Always test the
specific combinations you're using.

Learn more about [First Contentful Paint (FCP)](https://web.dev/articles/fcp), which measures the time from
when the user first navigated to the page to when any part of the page's content
is rendered on the screen. "Content" refers to text, images (including
background images), `<svg>` elements, and non-white `<canvas>` elements.

### Use vector graphics

[Scalable Vector Graphics (SVGs)](https://web.dev/articles/svg-mobile-fundamentals) are a great way to provide a scalable
image. For images that are well-suited to vector graphics, SVG provides
high-quality images with very small file sizes.

### Provide high-resolution photos

Use a photo suitable for a high-DPI device and scale the image using CSS. This
way, the image can render in a high quality across devices. If you use high
compression (low quality setting) when generating the image, you may be able to
achieve good visual results with a reasonable file size.

This approach has a couple of potential downsides: highly-compressed images may
show some visual artifacts, so you need to experiment to determine what level
of compression you find acceptable. And resizing the image in CSS can be an
expensive operation.

If high compression is not suitable for your needs, try the [WebP format](https://developers.google.com/speed/webp/),
which gives a high quality image with relatively small file size. Remember to
provide a fallback for versions of Android where WebP isn't supported.

### Fine-grained control

In many cases, you can't use a single image for all devices. In this case, you
can select different images based on the screen size and density. Use
media queries to select background images by screen size and density.

You can use JavaScript to control how images load, but this adds complexity.

#### Media queries and screen density

To select an image based on the screen density, you need to use `dpi` or `dppx`
units in your media query. The `dpi` unit represents dots per CSS inch, and
`dppx` represents dots per CSS pixel.

In the following table, you can see the relation between `dpi` and `dppx`.

| Device pixel ratio | Generalized screen density | Dots per CSS inch (`dpi`) | Dots per CSS pixel (`dppx`) |
|---|---|---|---|
| 1x | MDPI | 96`dpi` | 1`dppx` |
| 1.5x | HDPI | 144`dpi` | 1.5`dppx` |
| 2 | XHDPI | 192`dpi` | 2`dppx` |

The generalized screen density buckets are defined by Android and are used in
other places to express screen density (for example, [https://screensiz.es](https://screensiz.es/phone)).

#### Background images

You can use media queries to assign background images to elements. For example,
if you have a logo image with 256px by 256px size on a device with a pixel ratio
of 1.0, you might use the following CSS rules:

    .welcome-header > h1 {
      flex: 1;

      width: 100%;

      max-height: 256px;
      max-width: 256px;

      background-image: url('../images/html5_256x256.png');
      background-repeat: no-repeat;
      background-position: center;
      background-size: contain;
    }

To swap this out for a larger image on devices with device pixel ratio of 1.5
(hdpi) and 2.0 (xhdpi), you can add the following rules:

    @media screen and (min-resolution: 1.5dppx) {
      .welcome-header > h1{
        background-image: url('../images/html5_384x384.png');
      }
    }

    @media screen and (min-resolution: 2dppx) {
      .welcome-header > h1{
        background-image: url('../images/html5_512x512.png');
      }
    }

You can then merge this technique with other media queries, such as `min-width`,
which is useful as you account for different form factors.

    @media screen and (min-resolution: 2dppx) {
      .welcome-header > h1{
        background-image: url('../images/html5_512x512.png');
      }
    }

    @media screen and (min-resolution: 2dppx) and (min-width: 1000px) {
      .welcome-header > h1{
        background-image: url('../images/html5_1024x1024.png');

        max-height: 512px;
        max-width: 512px;
      }
    }

You might notice that the `max-height` and `max-width` are set to 512px for
2`ddpx` resolution, with an image of 1024x1024px. this is because a CSS "pixel"
actually takes into account the device pixel ratio (512px \* 2 = 1024px).

#### What about `<img/>`?

The web today doesn't have a solution for this. There are some proposals, but they
aren't available in current browsers or in the WebView.

In the meantime, if you generate your DOM in JavaScript, you can create multiple
image resources in a thoughtful directory structure:

    images/
      mdpi/
        imagename.png
      hdpi/
        imagename.png
      xhdpi/
        imagename.png

Then use the pixel ratio to try and pull the most appropriate image:

    function getDensityDirectoryName() {
      if(!window.devicePixelRatio) {
        return 'mdpi';
      }

      if(window.devicePixelRatio > 1.5) {
        return 'xhdpi';
      } else if(window.devicePixelRatio > 1.0) {
        return 'hdpi';
      }

      return 'mdpi';
    }

Alternatively, you can alter the base URL of the page to define the relative
URLs for images.

    <!doctype html>
    <html class="no-js">
    <head>
      <script>
        function getDensityDirectoryName() {
          if(!window.devicePixelRatio) {
              return 'mdpi';
          }

          if(window.devicePixelRatio > 1.5) {
              return 'xhdpi';
          } else if(window.devicePixelRatio > 1.0) {
              return 'hdpi';
          }

          return 'mdpi';
        }

        var baseUrl =
            'file:///android_asset/www/img-js-diff/ratiores/'+getDensityDirectoryName()+'/';
        document.write('<base href="'+baseUrl+'">');
      </script>

        ...
    </head>
    <body>
        ...
    </body>
    </html>

This approach blocks page load and forces use of absolute paths for all
resources, such as images, scripts, and CSS files, as the base URL points to a
density-specific directory.