1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
|
---
title: 响应式设计的基础
slug: Web/Progressive_web_apps/Responsive/responsive_design_building_blocks
translation_of: Web/Progressive_web_apps/Responsive/responsive_design_building_blocks
---
<div class="summary">
<p>在本文中,我们将讨论响应式设计的主要基本组成部分,并在必要时提供一些指向更多信息的链接。</p>
</div>
<p>For Web developers, it is now fairly common to be called upon to create a Web site or app that changes its user interface depending on the browser or device accessing the site to provide an optimized experience. One approach to this is to create different versions of your site/app for different platforms or browsers and serve them appropriately after detecting which browser or platform is looking at your site. But this is increasingly inefficient: browser sniffing is inherently error prone, and maintaining multiple copies of your code can turn out to be a nightmare.</p>
<p>It is usually much better to create a single version of your code which doesn't care about what browser or platform is accessing the site, but instead uses feature tests to find out what code features the browser supports or what the values of certain browser features are, and then adjusts the code appropriately. This tends to be termed <strong>responsive design</strong> or <strong>adaptive design</strong>, two related but different approaches. For a discussion on the differences between the two, read <a href="/en-US/docs/Web/Apps/app_layout/Responsive_design_versus_adaptive_design" title="/en-US/docs/Web/Apps/app_layout/Responsive_design_versus_adaptive_design">Responsive design versus adaptive design</a>.</p>
<p>This is much more reliable, more maintainable, and more future proof. You don't get caught in the situation of having to bring out more new site versions as more new browsers and platforms come out, and adjust code as feature support in existing browsers changes.</p>
<p>There are disadvantages to this approach as well. If the content, layout, and functionality need to change greatly for different devices, it may not be such a good approach. Also, taking an existing site and adding responsiveness to it, to make it mobile/tablet friendly, can be a lot more effort than just creating a separate mobile site or app, especially if it is a sprawling enterprise site. Read more about <a href="/en-US/docs/Web_Development/Mobile/Responsive_design" title="/en-US/docs/Web_Development/Mobile/Responsive_design">responsive design advantages and disadvantages</a>.</p>
<div class="note">
<p>You can also read our discussion on the basics of <a href="/en-US/docs/Web_Development/Mobile/Responsive_design">responsive design</a>, if you need some more background information and basics.</p>
</div>
<h2 id="Fluid_grids">Fluid grids</h2>
<p>The best place to start is with fluid measurements for our application layout — essentially, this means using a combination of percentages and ems/rems to size your containers and text, not fixed widths such as pixels. This has a lot of advantages in that the layout will adapt to different viewport dimensions. Let's look at an example.</p>
<p>We've written a simple-but-fun prototype for an application called Snapshot, which takes a video stream from your webcam (using {{domxref("navigator.getUserMedia", "getUserMedia()")}}) then allows you to capture stills from that video stream (using HTML5 {{HTMLElement("canvas")}}), and save them to a gallery. You can then view previously-captured images and delete them. Other articles will discuss the functionality in more detail, but here we're interested in the layout.</p>
<div class="note">
<p><strong>Note:</strong> You can find the <a href="https://github.com/chrisdavidmills/snapshot">Snapshot app on Github</a>; check out the code and help improve it. You can also see <a href="https://chrisdavidmills.github.io/snapshot/">Snapshot running live</a>. Note that <code>getUserMedia()</code> is an experimental technology, which currently only works in Google Chrome and Firefox desktop. More functionality and a clean up of the styling of Snapshot are planned for a future date.</p>
</div>
<p>Our desktop layout for Snapshot is three columns, containing the camera viewer, image capture view, and gallery, respectively.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5917/desktop-layout.png" style="display: block; height: 184px; margin: 0px auto; width: 600px;"></p>
<p>The markup is very simple:</p>
<pre class="brush: html notranslate"><x-deck selected-index="0">
<x-card>
…
</x-card>
<x-card>
…
</x-card>
<x-card>
…
</x-card>
</x-deck></pre>
<div class="note">
<p><strong>Note:</strong> These weird x- elements may be unfamiliar; they are part of <a href="http://mozbrick.github.io/">Brick</a>, Mozilla's UI element library for mobile web apps. We have used Brick to create the mobile layout for Snapshot, which you will read more about below.</p>
</div>
<p>To get these sitting side-by-side we have used the following rules:</p>
<pre class="brush: css notranslate">x-card {
width: 100%;
}
x-card:nth-child(1), x-card:nth-child(2) {
width: 30%;
float: left;
padding: 2rem;
}
x-card:nth-child(3) {
width: 40%;
float: left;
height: 100%;
overflow: auto;
padding: 2rem;
}</pre>
<p>So we're giving the first two columns a {{cssxref("width")}} of <code>30%</code>, and the third a <code>width</code> of <code>40%</code>, floating the columns all left. This way they end up side-by-side, and their proportions remain the same as the browser window size varies. This is just a simple grid example, but you can apply this principle to more complex grid layouts as required.</p>
<h3 id="border-box_sizing">border-box sizing</h3>
<p>The padding does not affect the overall width and height of the containers because we have set the {{cssxref("box-sizing")}} of all elements to <code>border-box</code>:</p>
<pre class="brush: css notranslate">*, *:before, *:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}</pre>
<p>This basically means that {{cssxref("width")}} and {{cssxref("height")}} will now set the dimensions of an element all the way up to and including the border, not just the content. So if you set <code>width: 40%</code>, the box width will always be <code>40%</code> of its parent, and any {{cssxref("padding")}} and {{cssxref("border")}} widths set on the box will be subtracted from the content width, not added to it. Very useful! Read more about this at <a href="http://www.paulirish.com/2012/box-sizing-border-box-ftw/">* { Box-sizing: Border-box } FTW</a>, by Paul Irish.</p>
<h2 id="Flexible_replaced_elements">Flexible replaced elements</h2>
<p>Things are working fairly well now, but there are still some issues just waiting to present themselves. For a start, let's have a look at what happens when we include the {{HTMLElement("video")}} and {{HTMLElement("img")}} elements inside our first two columns, naked and unstyled.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5913/broken-images.png" style="display: block; height: 316px; margin: 0px auto; width: 480px;"></p>
<p>Because the size of replaced elements is dictated by the size of the media inserted into them, and the media is a fixed size, they explode out of their containing elements and make a mess of the layout. This is pretty horrible, but generally this kind of problem is easily fixed with some simple CSS:</p>
<pre class="brush: css notranslate">img, video {
max-width: 100%;
}</pre>
<p>This tells the replaced elements to remain constrained inside their container's widths, no matter what. However, if they aren't as wide as their containers, they will not stretch to fill them. In the snapshot example, we ended up with slightly different code:</p>
<pre class="brush: css notranslate">x-card:nth-child(1) video, x-card:nth-child(2) img {
width: 100%;
…
}</pre>
<p>This is because in our case, we do in fact want the video and image to stretch to always fill their containers no matter what — a subtle but important difference from {{cssxref("max-width")}} — and therefore always be the same size. The video always resizes dynamically, but the screen captures taken from it do not, so upon resizing the screen it was possible to end up with a messy layout with different sized elements when using <code>max-width: 100%</code>, such as:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5915/broken-max-width-layout.png" style="display: block; height: 220px; margin: 0px auto; width: 480px;"></p>
<h2 id="Media_queries">Media queries</h2>
<p>Fluid grids are a great start, but you'll notice that at certain points (known as breakpoints) the layout starts to break down. At these points you'll want to change the layout to rectify the layout problem, and this can be done using media queries.</p>
<div class="note">
<p><strong>Note:</strong> Media queries are a CSS3 feature that allow you to selectively apply CSS depending on the results of media feature tests — for more on the basics, read <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries">Media queries</a>.</p>
</div>
<h3 id="Typical_desktop_layout">Typical desktop layout</h3>
<p>In our example, we have a desktop layout, as we've already seen. This is created using the CSS rules included at the top of the stylesheet, before any media queries are encountered.<br>
<br>
<img alt="" src="https://mdn.mozillademos.org/files/5917/desktop-layout.png" style="display: block; height: 184px; margin: 0px auto; width: 600px;"></p>
<h3 id="Mid-width_layout">Mid-width layout</h3>
<p>We also have a mid-width layout, which is aimed at working well on tablets and narrow laptop screens. This is created by all of the CSS inside the first media query:</p>
<pre class="brush: css notranslate">@media all and (max-width: 1024px) {
x-card:nth-child(1), x-card:nth-child(2) {
width: 50%;
}
x-card:nth-child(3) {
width: 100%;
clear: left;
}
x-card:nth-child(3) img {
width: 20%;
}
}</pre>
<p>So here we're altering the widths of the columns and removing the float of the third column (and adding clearing to guard against any float funny business). We've also altered the width of the images inside the third container (no longer a column — this is the gallery) so that now you get five per line (it was previously three per line).</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5919/middle-layout.png" style="display: block; height: 390px; margin: 0px auto; width: 480px;"></p>
<h3 id="Narrow_screenmobile_layout">Narrow screen/mobile layout</h3>
<p>We then have a narrow screen layout, designed to fit the bill for a mobile app/open Web app experience. This is created in multiple parts. First of all, as expected, there is a media query in our main CSS, which is quite weighty, so we'll go through it in parts:</p>
<pre class="brush: css notranslate">@media all and (max-width: 480px) {
x-card:nth-child(1), x-card:nth-child(2), x-card:nth-child(3) {
width: 100%;
float: none;
padding: 0;
}
button {
margin-top: 0;
border-radius: 0;
}
x-card:nth-child(1) video, x-card:nth-child(2) img {
border-radius: 0px;
border: none;
padding: 0;
background-color: 0;
}</pre>
<p>This first block resets a number of different things from the widescreen layouts that were't required for the mobile app.</p>
<pre class="brush: css notranslate"> x-card:nth-child(1) video, x-card:nth-child(2) img, x-card:nth-child(3) {
margin-top: 17.5vw;
}
x-card:nth-child(1) button, x-card:nth-child(2) button {
position: absolute;
bottom: 0;
}
x-card:nth-child(2) button:nth-of-type(2) {
bottom: 5.9rem;
}
x-card:nth-child(1) button {
font-size: 7vw;
}
x-card:nth-child(2) button {
font-size: 7vw;
}</pre>
<p>The next rules do some sizing on the buttons inside the first two cards, and give all card contents a top margin so that their content won't be lost under the navigation buttons (see below). This was necessary because Mozilla Brick (also see below) forces its components to be 100% of the screen width and height. We have used <code>vw</code> (viewport width) units for these — <code>1vw</code> is equivalent to 1% of the viewport width. This makes the dimensions scale up and down nicely along with the viewport width. Last for this section, we absolutely positioned all buttons at the bottom of the cards they are in, so the layout looks OK at different viewport size variations. We then add a rule that positions the second button in any card a button's width higher up the card. When you click on an image in the gallery it brings up options to delete or cancel deletion of the card, and you don't want two buttons on top of one another.</p>
<pre class="brush: css notranslate">x-card:nth-child(3) img {
width: 50%;
}</pre>
<p>This rule simply changes the width of the gallery images so now there are two per line.</p>
<pre class="brush: css notranslate"> nav {
width: 100%;
position: absolute;
z-index: 1000;
display: -webkit-flex;
display: -moz-flex;
display: -ms-flexbox;
display: flex;
}
nav button {
font-size: 6.8vw;
-webkit-flex: 1;
-moz-flex: 1;
-ms-flex: 1;
flex: 1;
border-left: 1px solid rgba(100,100,100,0.4);
}
nav button:first-child {
border-left: 0;
}
}</pre>
<p>In this last set of rules, we change the display value of the {{HTMLElement("nav")}} to <code>flex</code> to make it show (it was set to <code>none</code> in the default CSS at the top of the stylesheet, as it wasn't needed for the other views.) We then use absolute positioning and {{cssxref("z-index")}} to make it take up no space in the document flow, and sit on top of the x-cards (this is why we gave the x-cards that top-margin earlier).</p>
<p>Next up, the <code>font-size</code> of the buttons is set to <code>6.8vw</code>. Why? Because the top-margin of the x-cards was set to <code>17vw</code> earlier on. All buttons in the app have been set to have a <code>line-height</code> of 2.5, in the default CSS at the top of the stylesheet (check if you don't believe me.) And 6.8 x 2.5 = 17.</p>
<p>Last, we have used <code>flex: 1;</code> to make the buttons always take up the same proportion of space on the line. Let's have a look at the mobile layout, in the below image.</p>
<p><img alt="single column layout for mobile app view, with three buttons to navigate between cards, an image viewer, and a Save Picture button at the button." src="https://mdn.mozillademos.org/files/5939/mobile-layout.png" style="float: left; height: 417px; margin-right: 2rem; width: 304px;">But there are more tricks up our sleeves for this mobile app layout! As mentioned above, we used <a href="http://mozilla.github.io/brick/">Mozilla Brick</a>, a collection of ready-rolled mobile UI components, in the making of the mobile app layout. In particular, we used the <a href="http://mozilla.github.io/brick/docs.html#deck">deck</a> component for the nice transition effect between cards when the buttons are pressed. For more on using Brick, read <a href="/en-US/docs/Web/Apps/app_layout/Mozilla_Brick_ready_made_UI_components" title="/en-US/docs/Web/Apps/app_layout/Mozilla_Brick_ready_made_UI_components">Mozilla Brick: ready made UI components</a>.</p>
<p>What's more relevant to this article is that we didn't want the Brick CSS and JavaScript files being applied to the markup unless we were looking at the mobile app view. To achieve this, we applied the Brick CSS to the page using a separate {{HTMLElement("link")}} element with a <code>media</code> attribute:</p>
<pre class="brush: html notranslate"><link href="dist/brick.css" type="text/css" rel="stylesheet" media="all and (max-width: 480px)"></pre>
<p>This says that the whole stylesheet will not be linked to the HTML unless the viewport width is 480px or less. Moving on to the JavaScript, {{HTMLElement("script")}} elements don't accept <code>media</code> attributes, so I had to do this a different way. Fortunately there is a JavaScript construct called {{domxref("window.matchMedia()")}}, which can conditionally run JavaScript constructs depending on whether a media query returns <code>true</code> or not. We opened up the <code>brick.js</code> file and wrapped the whole lot in the following:</p>
<pre class="brush: js notranslate">if (window.matchMedia("(max-width: 480px)").matches) {
// The whole of brick.js goes here!
}</pre>
<p>This causes nothing inside the <code>brick.js</code> file to be run unless the viewport width is 480px or less. Problem solved.</p>
<h3 id="Really_wide_screens">Really wide screens</h3>
<p>One thing you might notice is that when the viewport gets very wide (such as on a cinema display), the layout stops getting wider, and just centers in the space available. This is pretty simple to achieve. You could use a <code>min-width</code> media query to fix the {{HTMLElement("body")}} width at a certain point:</p>
<pre class="brush: css notranslate">@media all and (min-width: 1400px) {
body {
width: 1400px;
margin: 0 auto;
}
}</pre>
<p>But it's actually easier to just set the following rule instead, and get rid of the media query altogether:</p>
<pre class="brush: css notranslate">body {
max-width: 1400px;
margin: 0 auto;
}</pre>
<h3 id="Orientation_fail">Orientation fail</h3>
<p>We also came across some problems with orientation: the mobile-app layout of our example app is designed for portrait orientation, and looks terrible when viewed on a device in landscape orientation. To fix this, we added in a media query that only applies its contents to the markup when device is viewed in landscape orientation:</p>
<pre class="brush: css notranslate">@media all and (max-width: 480px) and (orientation: landscape) {
nav {
width: auto;
-webkit-flex-direction: column;
-moz-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
nav button {
font-size: 6.8vh;
}
nav button {
border-left: 0;
}
x-card:nth-child(1) video, x-card:nth-child(2) img, x-card:nth-child(3) {
margin-top: 0;
}
x-card:nth-child(1) button, x-card:nth-child(2) button {
font-size: 2rem;
}
}</pre>
<p>This does the following:</p>
<ul>
<li>Adjusts the nav buttons, changing the direction the flexbox is laid out in, and altering the font size and borders so they sit vertically instead of horizontally.</li>
<li>Removes the top margin from the x-card contents so you don't end up with an unsightly gap at the top of the screen in landscape mode.</li>
<li>Changes the sizing of the control buttons (e.g. <em>Take Picture</em>, <em>Delete Photo</em>) so they don't look too big and sit properly on the screen.</li>
</ul>
<p>This results in the following layout:</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5923/viewport-fail-fixed.png" style="display: block; height: 320px; margin: 0px auto; width: 479px;"></p>
<div class="note">
<p><strong>Note</strong>: Another solution with respect to orientation might be to just lock the orientation of your app, to portrait or landscape. If you are working on an installed app, you can easily do this with the <a href="https://developer.mozilla.org/en-US/Apps/Build/Manifest#orientation">orientation manifest field</a>. If you want a solution that works across general web apps, you could use the <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Managing_screen_orientation#Locking_the_screen_orientation">Screen orientation API</a>, and/or provide a message asking the user to rotate their screen if they are using the wrong orientation (for example, if <code>window.innerWidth</code> is larger than <code>window.innerHeight</code>, assume the<br>
game is landscape mode and show a "please rotate" message.)</p>
</div>
<h2 id="Viewport">Viewport</h2>
<p>One last problem to mention for our example app is concerned with mobile browsers and media queries. If we viewed my example in a mobile browser in its current state, we wouldn't see our nice mobile layout. Instead, we'd see the below image.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/5925/viewport-fail.png" style="float: left; height: 569px; margin-right: 2rem; width: 320px;">I'm sure you'll agree that this really isn't what we wanted — why is this happening? In short, mobile browsers lie. They don't render web pages at their true viewport width. Instead, they render pages at a higher assumed viewport width (something approaching a laptop screen), and then shrink the result down to fit inside the mobile screen. This is a sensible defensive mechanism — most old school sites that don't have media queries would look terrible when rendered at say, 320px or 480px wide. But this doesn't help us responsible web developers, who have written small screen layouts into our CSS using media queries and want mobile devices to display those!</p>
<p>There is a way to override this mobile rendering behavior — viewport, which is inserted into our HTML pages in the form of a {{HTMLElement("meta")}} tag. In my example, let's add the following into our HTML {{HTMLElement("head")}}:</p>
<pre class="notranslate"><meta name="viewport" content="width=480"></pre>
<p>This causes our browser to render our mobile app layout properly — <code>width=480</code> tells the browser <em>"render this markup at 480 pixels wide"</em>, hence the media queries kick in appropriately. There are many more options available in the viewport meta tag, which you can read about in <a href="/en-US/docs/Mozilla/Mobile/Viewport_meta_tag" title="/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">Using the viewport meta tag to control layout on mobile browsers</a>.</p>
<div class="note">
<p><strong>Note:</strong> There is a spec called <a href="http://dev.w3.org/csswg/css-device-adapt/">device adaptation</a>, which defines the same functionality but in CSS, using a <code>@viewport</code> at-rule. This is probably a more logical place to put such information, but the spec is not as well supported as the viewport meta tag, therefore you should stick with that for now.</p>
</div>
<h2 class="cleared" id="Responsive_imagesvideo">Responsive images/video</h2>
<p>Another problem that comes up more and more these days is making image/video weight (size in KB) responsive as well as the dimensions of the image on screen. Yes, you want the images to be contained inside the app UI whether you are using it on desktop or mobile, but you should also consider that mobile apps have much smaller viewport dimensions available than desktop apps, so you should try to give mobile devices a smaller image to download. Mobiles in general (more commonly in some parts of the world than others) are on lower bandwidth connections and have less memory available than desktop devices, so yes, those extra kilobytes really do count.</p>
<p>Another challenge is dealing with high resolution screens — raster graphics designed for low resolutions are in danger of appearing tiny when displayed on a high resolution screen, so devices often apply a default zoom factor to rendered pages to avoid this. The trouble with this, then, is that raster images are zoomed in and as a result can start to look pixellated.</p>
<h3 id="CSS_background_images">CSS background images</h3>
<p>For CSS background images this is a fairly easy problem to solve. If you use the <a href="/en-US/docs/Web/Apps/app_layout/Mobile_first" title="/en-US/docs/Web/Apps/app_layout/Mobile_first">mobile first</a> methodology, you will be creating your mobile layout inside your default CSS, before any media queries have been applied. The media queries then supply CSS that is only applied to the markup when the viewport is <strong>above</strong> a certain width. Let's look at a quick example:</p>
<pre class="brush: css notranslate">header {
height: 300px;
width: 100%;
background: url(images/small-header.jpg) center;
}
@media all and (min-width: 480px) {
header {
background: url(images/large-header.jpg) center;
}
}</pre>
<p>This means that mobile browsers only download the mobile background image asset — not the desktop mobile assets — because they fail the media query tests and therefore ignore the media queries. You can also serve a larger graphic to a higher resolution device using a resolution media query, like so:</p>
<pre class="prettyprint prettyprinted notranslate"><code><span class="brush: css">button {
background: url(images/low-res-header.jpg) 1rem center ;
}
@media</span><span class="pln"> only screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">min</span><span class="pun">-</span><span class="pln">device</span><span class="pun">-</span><span class="pln">pixel</span><span class="pun">-</span><span class="pln">ratio</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">),</span><span class="pln">
only screen </span><span class="kwd">and</span><span class="pln"> </span><span>(</span><span class="pln"> min</span><span class="pun">-</span><span class="pln">resolution</span><span class="pun">:</span><span class="pln"> </span><span class="lit">192dpi</span><span class="pun">),</span><span class="pln">
only screen </span><span class="kwd">and</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> min</span><span class="pun">-</span><span class="pln">resolution</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2dppx</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
<code><span class="lit"> button {
background: url(images/high-res-header.jpg) 1rem center ;
}</span></code> </span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>This looks rather complicated, but really it's not — we are providing a number of media query options, as at this time different browsers support different resolution media query types and even units. Brett Jankord has a good explanation at <a href="http://www.brettjankord.com/2012/11/28/cross-browser-retina-high-resolution-media-queries/">Cross Browser Retina/High Resolution Media Queries</a>.</p>
<h3 id="<video>"><video></h3>
<p>HTML5 video is fairly well catered for in terms of responsive capabilities. If you wish, you can point to multiple video files via {{HTMLElement("source")}} attributes, each with their own source and MIME type:</p>
<pre class="brush: html notranslate"><video controls>
<source src="videos/720/crystal720.mp4" type="video/mp4">
<source src="videos/720/crystal720.webm" type="video/webm">
</video></pre>
<p>But you can go one step further. You can include <code>media</code> attributes on the <code><source></code> element containing media queries — the video loaded in the browser will depend on both the format the browser supports, and the results of the media tests. So for example:</p>
<pre class="brush: html notranslate"><video controls>
<source src="videos/320/crystal320.mp4" type="video/mp4" media="all and (max-width: 480px)">
<source src="videos/320/crystal320.webm" type="video/webm" media="all and (max-width: 480px)">
<source src="videos/720/crystal720.mp4" type="video/mp4" media="all and (min-width: 481px)">
<source src="videos/720/crystal720.webm" type="video/webm" media="all and (min-width: 481px)">
</video></pre>
<p>This allows your site to serve different video files based on the available space, in order to optimize the user's experience.</p>
<h3 id="<img>"><img></h3>
<p>HTML images are a more difficult proposition. There is no mechanism inherent in HTML images for serving different image files dependent on viewport size, and, due to a number of irksome browser behavior realities, solutions are more difficult to hack together than you would imagine. There are currently some standards proposals in the works that would provide this — the W3C <a href="http://www.w3.org/community/respimg/" title="http://www.w3.org/community/respimg/">responsive images community group</a> discussed this problem for ages and arrived at the <a href="http://www.w3.org/TR/html-picture-element/"><picture></a> element, which provides a similar markup structure to {{HTMLElement("video")}}<a href="/en-US/docs/Web/HTML/Element/video" title="/en-US/docs/Web/HTML/Element/video">,</a> with {{HTMLElement("source")}} alternatives selectable via media query results. Another proposal, <a href="http://www.w3.org/html/wg/drafts/srcset/w3c-srcset/">srcset</a>, was put forward by Apple and takes a slightly different approach, instead providing a new <code>srcset</code> attribute for {{HTMLElement("img")}} inside which image references are placed along with "hints" that the browser can use to work out which image is most suitable to display given its viewport size, resolution, etc. These are not intended to be mutually exclusive.</p>
<p>This all sounds good. But those solutions are definitely not ready for production yet — both are in a very early stage of standardization, and have no support across browsers. Currently we have to rely on various polyfills and other solutions, none of which are perfect for all situations, so you need to decide which one is right for your particular situation. Some available solutions are as follows:</p>
<dl>
<dt><a href="https://github.com/teleject/hisrc">HiSRC</a></dt>
<dd>A <a href="http://jquery.com">jQuery</a> plugin that allows you to create small, medium, and large versions of an image, and then serves the appropriate one according to the browser's resolution and available network speed.</dd>
<dt><a href="http://www.mobify.com/mobifyjs/v2/docs/capturing/">Mobify.js capturing</a></dt>
<dd>A very clever technique from Mozilla that allows you to capture the source of the page before it's parsed. This way, you can swap out image <code>src</code> values with JavaScript depending on browser features, circumventing browser preloading issues. This is promising, but doesn't work very well across older browsers.</dd>
<dt><a href="https://github.com/scottjehl/picturefill">Picturefill</a></dt>
<dd>A JavaScript-based polyfill for <code><picture></code>, which works nicely, but it does require a lot of custom markup.</dd>
<dt><a href="http://adaptive-images.com/">Adaptive images</a></dt>
<dd>A server-side solution, which records the viewport size in a cookie, then resizes images via a combination of PHP and <code>.htaccess</code> to a more appropriate size, if appropriate. This doesn't require markup or scripting, but has a number of limitations.</dd>
</dl>
<h3 id="SVG_and_other_vector_graphics">SVG and other vector graphics</h3>
<p>For some image requirements (not photographs, but icons and user interface elements are a good fit), a good solution is to use vector graphics. Because vector images are calculated based on mathematical algorithms rather than containing separate data on every pixel in the image, they tend to be smaller in file size, and are infinitely scalable when zoomed or viewed on high resolution devices (at least, in theory). Some ideas follow, which also help to keep the number of HTTP requests down — another key factor in mobile app performance:</p>
<ul>
<li>You should try to use <a href="/en-US/docs/Web/CSS/CSS3" title="/en-US/docs/Web/CSS/CSS3">CSS3</a> features to programmatically generate graphical effects where possible, rather than relying on image files. these include rounded corners, gradients, and drop shadows. These scale as the resolution changes or the browser zooms. Although they are not supported very well on older browsers such as Internet Explorer 6-8, this is not too much of a concern when you are creating an interface aimed at modern devices, and they also tend to gracefully degrade.</li>
<li>You could also try using <a href="/en-US/docs/Web/SVG" title="/en-US/docs/Web/SVG">SVG</a> to create interface elements. SVG produces vector graphics and is supported well across modern browsers, with polyfills available for older browser support.</li>
<li>Using <a href="/en-US/docs/Web/CSS/@font-face" title="/en-US/docs/Web/CSS/@font-face">Web fonts</a> for displaying icons is an effective technique for keeping file size and HTTP requests down, and this is supported well across modern and older browsers.</li>
</ul>
<h2 id="See_also">See also</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web_Development" title="https://developer.mozilla.org/en-US/docs/Web_Development">Web development</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Mobile" title="https://developer.mozilla.org/en-US/docs/Web/Guide/Mobile">Mobile Web development</a></li>
</ul>
|