Over the next few pages, we'll be exploring how we can make good use of media queries; we'll be constructing two demos that illustrate some of the ways we can use queries. The demos themselves may not look complicated, but this is not a bad thing; making code complex only serves to make it more fragile, prone to breaking, and harder to support.
Let's take a look at our first demo, which adds responsive support to a basic portfolio template page.
Making it real—what a title! There is a good reason for it. When exploring new concepts, one of my pet hates is exploring a demo that is so minimalistic as to not include anything that gives a true picture of the functionality that I want to begin using in my development.
Creating media queries should not be an exception. In our previous example, we created some test queries to see how three boxes would interact when the browser window is resized. To put this into context though, requires something a little more in-depth; one could do worse than explore how we might add similar queries to a portfolio page that might be part of a new or existing site. For our second demo, we're going to create a simple web page template, then begin to add and develop queries that allow it to be used on mobile devices.
There is an important point here. The keen-eyed among you will notice that this is not a mobile-first approach, which we advocated earlier in the book. Yes, mobile-first is absolutely the preferred approach, but we live in a world where this may not be possible, and we may have to add query support to an existing site. Even though we are doing this in what is not our preferred order, the principles around the media queries used in the next demo will still apply.
Let's make a start:
responsive.html
, the two coffeebeans.png
images (normal and small size) and the video
folder, to the root of our project area. Move the two images into the img
folder within this folder.responsive.css
within the css
folder of our project area. The first block of styles create the main text area and overall container for our demo:#wrapper { width: 96%; max-width: 45rem; margin: auto; padding: 2%; border: 1px solid #000; margin-top: 3rem; border-radius: 0.2rem; margin-bottom: 3rem; } #wrapper > header > img { display: none; } #main { width: 60%; margin-right: 5%; float: left; }
Skip to...
at the top of the mobile view; it's hidden for now, but will be visible when the media query is activated:#skipTo { display: none; } #skipTo li { background: #197a8a; } #skipTo a { color: #fff; font-size: 0.8rem; }
#video-wrapper { padding-bottom: 2rem; } #video-wrapper video { max-width: 100%; } #banner { float: left; margin-bottom: 0.9375rem; width: 100%; } #banner { height: 15rem; width: 44.5rem; background-image: url('../img/coffeebeans.png'), max-width: 100%; }
aside { width: 35%; float: right; }
a { text-decoration: none; text-transform: uppercase; } a, img { border: medium none; color: #000; font-weight: bold; outline: medium none; }
header { font-family: 'Droid Sans', sans-serif; } header h1 { height: 70px; float: left; display: block; font-weight: 700; font-size: 2rem; } header nav { float: right; margin-top: 2.5rem; height: 1.375rem; border-radius: 0.25rem; } header nav li { display: inline; margin-left: 0.9375rem; } header nav ul { font-weight: 400; font-size: 1.1rem; } header nav a { padding: 0.3125rem 0.3125rem 0.3125rem 0.3125rem; } header nav a:hover { background-color: #8e5f57; color: #fff; border-radius: 0.25rem; }
footer { border-top: 0.0625rem solid #ccc; clear: both; height: 1.875rem; padding-top: 0.3125rem; }
@media screen and (max-width: 414px) and (orientation: portrait) { #header { background-color: #8e5f57; } #wrapper { min-width: 15.63rem; border: none; margin-top: 0; } #wrapper > header > img { float: right; display: block; } #skipTo { display: none; } #skipTo a { padding: 0.625rem; text-align: center; height: 1.25rem; background-color: #8e5f57; } #main {float: left; clear: left; margin: 0 0 0.625rem; width: 100%; margin-top: 10rem; } #banner { display: none; } aside {float: left; clear: left;margin: 0 0 0.625rem; width: 100%; } header h1 {margin-top: 1.25rem; height: 2.1875rem; } header nav {float: left; clear: left; margin: 0 0 0.625rem; width: 100%; border-radius: none; } header nav li {margin: 0; background: #efefef; display: block; margin-bottom: 0.1875rem; height: 2.5rem; } header nav a {display: block; padding: 0.625rem; text-align: center; } header nav a:hover { border-radius: none; } }
@media screen and (max-width: 736px) and (orientation: landscape) { #header { background-color: #8e5f57; } #wrapper { min-width: 15.63rem; border: none; margin-top: 0; } #wrapper > header > img { float: right; display: block; } #skipTo { display: none; } #skipTo a { padding: 0.625rem; text-align: center; height: 1.25rem; background-color: #8e5f57; } #main {float: left; clear: left; margin: 0 0 0.625rem; width: 100%; margin-top: 10rem; } #banner { display: none; } aside {float: left; clear: left;margin: 0 0 0.625rem; width: 100%; } header h1 {margin-top: 1.25rem; height: 2.188rem; } header nav {float: left; clear: left; margin: 0 0 0.625rem; width: 100%; border-radius: none; } header nav li { margin: 0; background: #efefef; display: block; margin-bottom: 0.1875rem; height: 2.5rem; } header nav a { display: block; padding: 0.625rem; text-align: center; } header nav a:hover { border-radius: none; } }
A perfectly presentable page, I hope you will agree. It shows off two of my favorite things perfectly: my love of coffee and the Scrabble board game! I always say coffee must be the secret tool in many developers' armories, but I digress…
Try resizing the screen; for argument's sake, let's resize it to 414 x 736, or the equivalent required for an iPhone 6 Plus:
We can use Chrome's device mode to switch the orientation to landscape:
We can see that the site realigns itself:
It's a simple, clean design. The key here is that we can use this as a basis for adding more queries that support other devices. There are some important concepts that we should explore in more detail, so let's take five for a moment, and see how media queries play their part in our demo.
Many of the styles used in this example cater for styling our page; the key rules for us start on lines 33 and 50, where we style for an iPhone 6 Plus in portrait and landscape modes, respectively. Let's take a look at these two rules in more detail:
@media screen and (max-width: 414px) and (orientation: portrait) { ... }
This rule states that the screen width must have a max-width
of 414px
or less; if it is bigger and still showing in portrait mode, then the rule will not apply.
Within this rule, we've taken styles already used in the main block and applied changes that allow us to maintain the desired effect when viewing the site on an iPhone. A perfect example is the #banner
block; in the main set of styles, we set a number of attributes to position it on screen:
#banner { float: left; margin-bottom: 0.9375rem; width: 100%; } #banner { height: 15rem; width: 44.5rem; background-image: url('../img/coffeebeans.png'), max-width: 100%; }
However, that won't suit being displayed on an iPhone, leaving aside how big the image is at 717px by 214px. It also weighs in at a hefty 102KB! Clearly, we don't want to keep downloading such a large image on a mobile device (where Internet access is likely to be metered), so we need to do something else.
Instead, we have a smaller version in use, in the form of coffeebeans-small.png
. This one is a more palatable 33KB, and sits in the top-right corner of our page when viewed on a mobile in portrait mode. We hide the original as it is not needed:
@media screen and (max-width: 414px) and (orientation: portrait) { ... #wrapper > header > img { float: right; display: block; } ... #banner { display: none; } }
As soon as we flip to using it in landscape mode, this rule kicks in:
@media screen and (max-width: 736px) and (orientation: landscape) { ... #wrapper > header > img { float: right; display: block; } ... #banner { display: none; } }
Notice though we don't need to change the rule. The image stays the same size and is already set to float to the right, so the rule can simply be reused. We have to specify it here too; otherwise, it won't display at all. To see the difference, try setting the demo using Google Chrome to emulate iPad mode:
We can see that even though the base code uses coffeebeans-small.png
in the #banner
<div>
, our media queries have replaced it with coffeebeans.png
.
We've purposely kept the rules in our demo simple; they illustrate how, with little effort, we can get our page to display properly in both desktop, iPhone 6 portrait and iPhone 6 landscape modes perfectly. We can then reuse the same principles to extend support to cover other devices; the trick is to make sure that we use a breakpoint that covers enough devices so that we don't have to add more than is necessary to our site.
Let's change tack now, but stay with the Apple theme. No, I'm not thinking of food! How many of you are lucky enough to own an iPad? If the answer is yes, then this next demo will be of interest. For many standard devices, we are limited in terms of what resolution we can use when displaying images.
Enter a great trick. How about the ability to display higher-resolution images? We don't need to download anything to help with this. Most modern browsers can do this out of the box; all we need is the appropriate media query to tell browsers when to use them.
The advent (and some may say meteoric rise) of mobile devices has introduced an opportunity, supporting higher resolution images.
Most users can't distinguish individual pixels on standard PCs. When viewed at typical distances, some websites would appear too small to use! Instead, the PC will revert to a more realistic resolution, such as 1,440px.
To give a smoother view, some devices pack in extra pixels; this has the effect of making individual pixels harder to view, and images super crisp in appearance. This was started by Apple, who marketed them as Retina displays; others have begun to follow suit and create devices capable of supporting high-res images.
Thankfully, we don't need expensive iPhones or iPads to add support. We can do this with a media query and use Chrome's Device tool to simulate testing it. To see how, let's create a simple demo that switches between two images of a Phalaenopsis or Moth orchid plant. To tell which image is displayed, each will show the resolution in the top right corner of the image:
min-resolution.css
:<!DOCType html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="css/min-resolution.css"> </head> <body> <div id="orchid"></div> </body> </html>
css
. In it, save the following code as min-resolution.css
:#orchid { background-image: url('../img/mothorchid.png'), height: 24.31rem; width: 36.5rem; } @media (min-resolution: 120dpi) { #orchid { background-image: url('../img/[email protected]'), height: 24.31rem; width: 36.5rem; } }
img
at the same level as the css
folder.mothorchid.png
and [email protected]
, then save them into the img
folder. Don't change their names!
There are two points of note here—one is the setting on the left (Responsive), while the other is DPR or device pixel ratio. To trigger displaying the higher resolution image, try changing the setting on the left to iPhone 6 Plus:
Notice how the DPR setting has jumped to 3.0
, and that our image has changed:
Hopefully, you will agree that this is a simple way to add support. Using Chrome, we can get a good representation of how a high-res image will appear; it is worth noting that it should still be tested on a proper device, as even Google can't entirely emulate specific devices from within their browser!
At this point, I am sure you will be asking how this all works. It's a simple trick. The key to it is the naming convention we used for the images at the beginning of the demo.
Remember how I said they should be saved as they are from the code download, and to not change the names? The reason for this is that we make use of this in our demo. Apple devices (since iOS4) expect to see the @2x
in the filenames to denote a high-res image:
We then make use of that with our media query, which is only set to display the higher resolution image, if our min-resolution
was detected to be 120dpi
or greater.
The power of media queries means we can tailor support for higher resolution images to those devices that can support them; if the device is not able to do so, then standard resolution images can be displayed instead.
Okay, let's change tack now. Although writing media queries is a straightforward task, there may be instances where even the best developer doesn't get it quite right! This could be anything from missing the viewport tag to inadvertently writing queries that clash with each other. Let's take a moment to explore some of the more common points where we might trip up, and take a look at a few pointers to help get us back on track.