Android WebView Scaling

Just as it’s important for an Android developer to understand how to support multiple screen sizes, so too is it important to understand how the Android framework handles the scaling of the content in a WebView.

To demonstrate the scaling that takes place within a webview, I’m going to use a basic example of a webview that displays a local image and some text underneath it – as some additional information, the device used in this example is a Galaxy Nexus with an xhdpi screen (320 dpi) and resolution of 1280×720. Below is the HTML and CSS used and the result of the app run on the said device:

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="sample.css" />
    </head>
    <body>
        <img src="localImage.png"/>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit<br>
            bla bla bla
        </p>
   </body>
</html>

the CSS…

img
{
    display: block;
    margin-left: auto;
    margin-right: auto;
}

p
{
	background-color: #E4E4E4;
	padding:1em;
	margin:0.5em;
	border-radius: 15px;
	font-size: 1em;
}

and finally the result…

Web content with default scaling.

Web content with default scaling.

Immediately it becomes obvious that the 300×200 local image has been scaled up considering the resolution of the device. Essentially what the Android framework is doing is assuming that the web content is targeted at an mdpi density (which Android treats as the base density), and as a result scales the content up accordingly for the xhdpi test device so that the drawn elements match the physical size they would appear on an mdpi display. Unless you explicitly specify the density you are targeting, Android will scale up/down accordingly.

To adjust the scaling performed by the Android framework, one can use the viewport meta tag to specify properties regarding screen density support:

<meta name="viewport" content="target-densitydpi=device-dpi" />

The Android docs explain the target-densitydpi property as follows:

You can use this to specify the target density for which the web page is designed, using the following values:

  • device-dpi – Use the device’s native dpi as the target dpi. Default scaling never occurs.
  • high-dpi – Use hdpi as the target dpi. Medium and low density screens scale down as appropriate.
  • medium-dpi – Use mdpi as the target dpi. High density screens scale up and low density screens scale down. This is also the default behavior.
  • low-dpi – Use ldpi as the target dpi. Medium and high density screens scale up as appropriate.
  •  – Specify a dpi value to use as the target dpi (accepted values are 70-400).

So if we use this information and modify our HTML to prevent default scaling:

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="sample.css" />
        <meta name="viewport" content="target-densitydpi=device-dpi" />
    </head>
    <body>
        <img src="localImage.png"/>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit<br>
            bla bla bla
        </p>
   </body>
</html>

and run the test app again, we get:

Web content with no scaling

Web content with no scaling

One can now see that no scaling has taken place; the image is displayed as one would expect a 300×200 image on such a device, and the text is significantly smaller. Without the scaling it becomes obvious that the graphic and styles used are not suitable for the xhdpi device, so these would ultimately need to change yet still cater for other densities.

In many simple cases like our example, all we want is to be able to develop and test the web content against a specific test device to ensure that it looks correct, and then allow Android to scale up/down from there. To achieve this, one can declare the specific target density (or even the exact dpi) for which your content is being designed. The following demonstrates this using our example designed for the Galaxy Nexus (320 dpi):

<html>
    <head>
        <link rel="stylesheet" type="text/css" href="sample.css" />
        <meta name="viewport" content="target-densitydpi=320" />
    </head>
    <body>
        <img src="localImage.png"/>
        <p>
            Lorem ipsum dolor sit amet, consectetur adipisicing elit<br>
            bla bla bla
        </p>
   </body>
</html>

 

img
{
    display: block;
    margin-left: auto;
    margin-right: auto;
}

p
{
	background-color: #E4E4E4;
	padding:1em;
	margin:0.5em;
	border-radius: 15px;
	font-size: 2em;
}

With the CSS modified a bit for the higher density and a new higher resolution graphic, we see the following result:

Web content targeted at xhdpi

Web content targeted at xhdpi

We are now happy with the look of the web content on our device, and because we have told the Android framework the specific density we are targeting it will automatically scale up or down for devices with higher or lower densities respectively. The following is a screenshot of the same HTML/CSS and graphic on a lower density emulator:

Web content on an hdpi emulator

Web content on an hdpi emulator

Having said all of this, YMMV with this basic approach. Allowing Android to perform scaling like this may have undesirable results with certain aspects, such as image quality. A more in-depth method for dealing with web content and multiple screen sizes and densities is to provide specific styles/graphics for different densities using the CSS media feature; more information about this can be seen here.

Advertisements

1 thought on “Android WebView Scaling

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s