Published: February 28, 2014
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:
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.
Use responsive design
Responsive design 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,
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.
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), 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) 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, 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 | 96dpi |
1dppx |
1.5x | HDPI | 144dpi |
1.5dppx |
2 | XHDPI | 192dpi |
2dppx |
The generalized screen density buckets are defined by Android and are used in other places to express screen density (for example, https://screensiz.es).
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
2ddpx
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.