A picture paints a thousand words...
A key element of any website is a visual content; after all, text will become very repetitive and dull, without adding some form of color!
Adding media not only gives color to a site, but can serve as a vital tool to show potential customers what a product looks like or how we should use it. In fact, sales can go up based purely on being able to see a product being demonstrated. With the advent of mobile devices, it is more important that we not only add media, but also ensure it works well on a range of different devices.
Throughout the course of this chapter, we will explore different ways of adding media to our pages, and see how easy it is to make it respond to any changes in available screen size. In this chapter, we will cover the following topics:
<picture>
Curious? Let's get cracking!
Our journey through the basics of adding responsive capabilities to a site has so far touched on how we make our layouts respond automatically to changes; it's time for us to do the same to media!
If your first thought is that we need lots of additional functionality to make media responsive, then I am sorry to disappoint; it's much easier, and requires zero additional software to do it! Yes, all we need is just a text editor and a browser; I'll be using my favorite editor, Sublime Text, but you can use whatever works for you.
Over the course of this chapter, we will take a look in turn at images, videos, audio, and text, and we'll see how with some simple changes, we can make each of them responsive. Let's kick off our journey, first with a look at making image content responsive.
It is often said that images speak a thousand words. We can express a lot more with media than we can using words. This is particularly true for websites selling products; a clear, crisp image clearly paints a better picture than a poor quality one!
When constructing responsive sites, we need our images to adjust in size automatically. To see why this is important, go ahead and extract coffee.html
from a copy of the code download that accompanies this book and run it in a browser. Try resizing the window. We should see something akin to this:
It doesn't look great, does it? Leaving aside my predilection for nature's finest bean drink, we can't have images that don't resize properly, so let's take a look at what is involved to make this happen:
coffee.html
and save it to our project area.img
folder; save a copy to the img
folder in our project area.coffee.css
:img { max-width: 100%; height: auto; }
coffee.html
. You will see line 6 is currently commented out; remove the comment tags.This time around, our image grows or shrinks automatically, depending on the size of our browser window:
Although our image does indeed fit better, there are a couple of points we should be aware of when using this method:
!important
set as a property against the height
attribute when working with responsive images; this isn't necessary, unless you're setting sizes in a site where image sizes may be overridden at a later datemax-width
to 100%
as a minimum; you may need to set a width
value too, to be sure that your images do not become too big and break your layoutThis is an easy technique to use, although there is a downside that can trip us up—spot what it is? If we use a high-quality image, its file size will be hefty—we can't expect users of mobile devices to download it, can we?
Don't worry though - there is a great alternative that has quickly gained popularity among browsers; we can use the <picture>
element to control what is displayed, depending on the size of the available window. Let's dive in and take a look.
In a nutshell, responsive images are images that are displayed their optimal form on a page, depending on the device your website is being viewed from. This can mean several things:
Traditionally, we might have used simple scripting to achieve this, but it is at the risk of potentially downloading multiple images or none at all, if the script loads after images have loaded, or if we don't specify any image in our HTML and want the script to take care of loading images.
We clearly need a better way to manage responsive images! A relatively new tag for HTML5 is perfect for this job: <picture>
. We can use this in one of three different ways, depending on whether we want to resize an existing image, display a larger one, or show a high-resolution version of the image. The recommended way to approach this is:
srcset
attributesizes
attributepicture
elementWe'll explore all three in detail; let's start with implementing the srcset
attribute in a standard <img>
tag, before moving on to using the <picture>
element.
A key benefit of using the <picture>
element is using the srcset attribute to select any one of several images, based on whether we want to display higher resolution versions or different sizes of the same image in different viewports.
Support for this in browsers is very good, with only Opera Mini and up to IE11 not wanting to join the party:
To make use of this srcset
attribute, we need to avail ourselves of sufficient different images, then specify what should be displayed at the appropriate trigger point, as shown in this example, based on defining the device-pixel
ratio:
<img src="small-image.png" srcset="small-img.png 1x, med-img.png 2x, lrg-img.png 3x">
Here, the src
attribute acts as fallback image for those browsers that do not support srcset
(although support is now very good!). The srcset
attribute allows us to specify different images to use, either based on the device-pixel ratio or the available viewport:
<img src="default.png" srcset="small.png 256w, med.jpg 511w, large.jpg 640w">
In this case, our fallback is default.png
; however, if the browser being used supports srcset
, then it will display small.png
at 256w
or med.png
at 511w
. If, however, we wanted to change the size and use different images based on the available viewport, then we would have to add an extra attribute—sizes
. It's easy enough to configure, so let's pause for a moment to see what this means in practice.
When adding pictures as part of the content on a responsive site, the images may each take up 100% of the element width, but the content itself doesn't always take 100% of the width of the window! For example, we might set each image element to 100% width (so they fill their parent containers), but that the overall content on screen only fills 50% of the available screen width.
To overcome this, we need to know the URLs for the various images to use, along with the width of each image resource; we can't get this from standard markup in the page layout, as images start downloading before CSS is applied.
Instead, we can simply set suitable widths within our HTML code using the srcset
attribute and suitable width descriptors. This is a little controversial for some, as it starts to blur the divide between HTML markup and the CSS presentation layer. This aside, let's take a look at an example of how we can set up the code:
<img src="img/orchid.jpg" sizes="50vw" srcset="img/orchid.jpg 200w, img/orchid-2x.jpg 400w, img/orchid-hd.jpg 600w">
In this excerpt, we set a default of 50% or half of the viewport width; the browser can then select the appropriate image to display, depending on the available width.
We've covered two key parts of making images responsive, but to bring it all together, we can use the HTML5 <picture>
element, which has garnered good support in most browsers:
The <picture>
element uses this syntax:
<picture> <source media="(min-width: 60rem)" sizes="(max-width: 500px) 50vw, 10vw" src="high-res-image-2x.png 145w "> <source media="(min-width: 35rem)" src="med-res-image.png"> <source src="low-res-image.png"> <img src="fallback-image.png" alt="Non-supported browser."> <p>Text to display</p> </picture>
In this extract, we've tied together all of the various attributes we can use with the <picture>
element; in this case, we've specified media queries (one of 60rem
and another of 35rem
), and that if our viewport is only 50% or less (indicated by the 50vw
value in the code), we display the normal images; if it is higher, then we display the high-definition images (as specified by using the 100vw
value).
Now that we've seen all three elements in use, let's pull them together and create a simple demo that automatically adjusts which image to use, based on the available viewport. For simplicity, we will concentrate just on the image, but there is nothing stopping us from developing this further into a full-sized page!
Let's make a start. For this demo, I would strongly recommend using Google Chrome if you have it installed; its device mode is perfect for this task!
img
folder at the root of our project area.<!DOCTYPE html> <html> <head> <title>Adding responsive images with the <picture> element</title> </head> <body> <picture> <source media="(min-width: 800px)" sizes="(max-width: 1000px) 100vw" srcset="img/high-res-image.png 738w"> <source media="(max-width: 799px)" sizes="(max-width: 600px) 100vw" srcset="img/med-res-image.png 738w"> <img src="img/fallback-image.png" alt="Human"> </picture> </body> </html>
pictureelement.html
at the root of our project folder.If all is well, we should see the image flip between two similar versions; to identify which is which, I've added the words High Resolution Image on one, and Medium Resolution Image on the other image used:
This is the same image, but this time using the medium resolution version:
Although this demo may look simple at face value, it is deceptive. We have the power to construct some complex statements, which can automatically select an image based on a number of criteria! It's important to understand how this demo works, as a basis for using it for complex examples. Let's take a moment to explore it in more detail.
If we take a look through our picture element demo, the code used may initially look complex, but is simpler than it looks! The key to it is understanding each part the <source>
statements and how they interact with each other. Let's tackle the first one:
<picture> <source media="(min-width: 800px)" sizes="(max-width: 1000px) 100vw" srcset="img/high-res-image.png 738w"> ... </picture>
In this one, we're specifying high-res-image.png
as our source image; this will only be displayed when our browser window is showing a minimum width of 800px
. The size of the image will either go to a maximum of 1000px
or 100vw
—the latter equivalent to 100% width of the available viewport space. The 738w
against the image is just the width of the image specified in the code (1w unit is equal to 1px, so our image is 738px wide).
Moving onto the second source statement, we find it shows a similar set up, but this time the media query is limited to a maximum width of 799px
, and that the size of the image will go to 600px
or the full width of the viewport, depending on its current size:
<picture> ... <source media="(max-width: 799px)" sizes="(max-width: 600px) 100vw" srcset="img/med-res-image.png 738w"> <img src="img/fallback-image.png" alt="Human"> </picture>
To finish off the <picture>
element, we specify fallback-image.png
as our fallback for those browsers that have yet to support this element in HTML5.
We've only scratched the surface of what is possible with the <picture>
element; for more details, take a look at the site maintained by the Responsive Images Community Group, hosted at https://responsiveimages.org/.
We've explored the theory behind making images responsive with a couple of useful techniques; it's time we got practical! The basis for our next demo is going to look at making a responsive map using Google Maps.
Responsive maps, I hear you ask? Surely this should come automatically, right? Well no, it doesn't, which makes its use a little awkward on mobile devices. Fortunately, we can easily fix this; the great thing about it is that it only requires a little additional CSS:
<iframe src=...
.googlemaps.html
in your favorite text editor, and add the <iframe>
code in between the google-maps div tags.googlemaps.css
:#container { margin: 0 auto; padding: 5px; max-width: 40rem; } .google-maps { position: relative; padding-bottom: 60%;overflow: hidden; } .google-maps iframe { position: absolute; top: 0; left: 0; width: 100% !important; height: 100% !important; }
If all is well, we will see a Google Maps image of Birmingham, with Packt's office marked accordingly:
At this point, try resizing the browser window. You will see that the map resizes automatically; the CSS styling that we've added has overridden the standard styles used within Google Maps to make our map responsive and accessible from any device we care to use.
Throughout the course of this chapter, we've followed the principle of using just a browser and text editor to construct our code. This, of course, included not downloading anything that was core to creating our examples (save for media and content).
There will be times though when this approach is not sufficient, we may find we need to avail ourselves of additional support to get a job done. Our overriding question should always be to check that we really need it, and that we're not just being lazy! If when answering that question, we do find that need additional help is needed, then there are a number of sources you can try out, to help take things further:
<picture>
demo, but it's worth pointing it out again. It's a useful compendium of material to help understand and use the <picture>
element.<picture>
, to extend support to those browsers that do not support it natively; you can download it from https://scottjehl.github.io/picturefill/.<picture>
element, it shows off a nice trick:<picture> <source type="image/webp" srcset="retina-image.webp 2x, image.webp 1x" /> <img srcset="retina-image.jpg 2x" src="image.jpg" alt="an image" /> </picture>
There are certainly things we can do, once we've become accustomed to working with responsive images, and want to graduate away from just using HTML5 and CSS3. It is important to note though, that there are a number of projects operating online that aren't listed here.
The main reason for this is age—support for responsive images was patchy for a while, which meant a number of projects appeared to help provide support for responsive images. Support for the <picture>
and associated elements is getting better all of the time, which reduces some of the attraction of these older projects; it is worth considering whether it is sensible to use them, or if the impact of not using them can be mitigated by changes to the user experience.
Okay, let's move on; time to get a little animated, I think! Alright, that was a terrible lead in to our next topic, given that we're going to explore making videos responsive. Over the next few pages, we'll see that although some of the same principles apply here, there are some bumps along the way, which might impact our journey.