Victoria & Albert Museum
I worked on the Victoria & Albert site between 2007 and 2012 providing advice and guidance around the CMS configuration of the site and the way to get the most out of the product. During that time I worked with two brilliant developers in Richard Barret Small and Richard Morgan.
The latest iteration of the site is quite stunning. The focus on the bold typography and headlines backed with the strong use of photography around the subject makes the site a pleasure to navigate… almost stroll through as if you were at the museum itself.
The stunning homepage image at first looks like a header image, but once you begin to scroll down the page you realise that it’s a fixed background image on the page itself which is a consistent approach to each of the pages. Rather than have to update the CSS file every time that a new homepage feature is required, or when a new exhibition is open, the background image is set within a <style> tag inline on the page itself. The site uses a series of media queries in this to ensure that the background image is perfect for the particular viewport being used as you can see in the code snippet below (note that each of the media queries contain the same rules as the first, but I removed some code for brevity sake):
.banner {
background-image: url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/56/7c7429ba-7161-4957-ba1e-ef8b6c838940/320.jpg');
background-image: -webkit-linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, .5)),
url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/56/7c7429ba-7161-4957-ba1e-ef8b6c838940/320.jpg');
background-image: -moz-linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, .5)),
url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/56/7c7429ba-7161-4957-ba1e-ef8b6c838940/320.jpg');
background-image: linear-gradient(rgba(0, 0, 0, .5), rgba(0, 0, 0, .5)),
url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/56/7c7429ba-7161-4957-ba1e-ef8b6c838940/320.jpg');
}
@media (-webkit-min-device-pixel-ratio: 2),
(min--moz-device-pixel-ratio: 2),
(min-resolution: 2dppx),
(min-resolution: 192dpi) {
.banner {
background-image: url('/d03e6682-0d2c-462f-a72f-ce4a7bbe846e/640.jpg');
}
}
@media (min-width: 321px) {
.banner {
background-image: url('/d03e6682-0d2c-462f-a72f-ce4a7bbe846e/640.jpg');
}
}
@media (min-width: 321px) and (-webkit-min-device-pixel-ratio: 2),
(min-width: 321px) and (min--moz-device-pixel-ratio: 2),
(min-width: 321px) and (min-resolution: 2dppx),
(min-width: 321px) and (min-resolution: 192dpi) {
.banner {
background-image: url('/4a644af9-107c-4731-bff2-79869f6f50b5/1280.jpg');
}
}
@media (min-width: 641px) {
.banner {
background-image: url('/12b9b826-39e7-4e6b-8f16-263e6282cc9d/960.jpg');
}
}
@media (min-width: 641px) and (-webkit-min-device-pixel-ratio: 2),
(min-width: 641px) and (min--moz-device-pixel-ratio: 2),
(min-width: 641px) and (min-resolution: 2dppx),
(min-width: 641px) and (min-resolution: 192dpi) {
.banner {
background-image: url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/57/89d283db-7fbb-432c-aec5-34b11d207708/1920.jpg');
}
}
@media (min-width: 961px) {
.banner {
background-image: url('/4a644af9-107c-4731-bff2-79869f6f50b5/1280.jpg');
}
}
@media (min-width: 1281px) {
.banner {
background-image: url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/57/89d283db-7fbb-432c-aec5-34b11d207708/1920.jpg');
}
}
@media (min-width: 1921px) {
.banner {
background-image: url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/57/ca62bc42-971d-4adb-9a23-d8ac3e435876/2560.jpg');
}
}
@media (min-width: 961px) and (-webkit-min-device-pixel-ratio: 2),
(min-width: 961px) and (min--moz-device-pixel-ratio: 2),
(min-width: 961px) and (min-resolution: 2dppx),
(min-width: 961px) and (min-resolution: 192dpi) {
.banner {
background-image: url('https://vanda-production-assets.s3.amazonaws.com/2017/03/06/15/12/57/ca62bc42-971d-4adb-9a23-d8ac3e435876/2560.jpg');
}
}
A few of these media queries have duplicate declarations on the viewport width, and the additional query is for devices that have a higher DPI. At the moment this is the best approach however it would be great if more browsers picked up support for image-set
which would allow for the DPI declarations to happen within the media query and the background-image
declaration rather than as separate queries, see an example below
background-image: image-set( "foo.png" 1x,
"foo-2x.png" 2x,
"foo-print.png" 600dpi );
Prefetching
It is good to see the use of prefetching on the site, shown below, however the declaration for this in the markup comes after all of the background image declarations we discussed above meaning that the handshake for that domain would have been completed before this part of the HTML had been parsed…. or at least I would have originally thought so. It turns out it doesn’t matter where you make the declaration as long as it’s in the <head> and the dns-prefetch
will work as expected.
<link rel="dns-prefetch" href="//vanda-production-assets.s3.amazonaws.com" />
If you’d like a bit more detail on that you can read more on preconnect and dns-prefetch priority.
SVGs
The site makes use of SVG for vector files which is great to see, and they’re doing it in a sprite kind of way. This means that all of the SVG images can be included in a single file that gets served, and then the particular image they want can be called through use
, see the example below.
<svg class="logo__icon themed--color"><use xlink:href="/assets/logo-3f6413d52e112293368dfac61e136433cc1d294462134f16505c8cf3e4036e9b.svg#logo"></use></svg>
The file contains vectors for Logo, logo unclipped, tab-icon, facebook, twitter, pinterest, instagram, tumblr, calendar etc. For a more detailed overview of SVG use check out SVG Use, take 2 from Chris Coyier at CSS Tricks.
Responsive Images
The V&A site uses srcset
for their images on the site. The image widths that they use are 320, 640, 960, 1280, and 2560 which are then targeted three possible viewports of more than 992px, between 500px and 992px, and 0px up to 500px. The space for which those images will take up are defined by using calc to declare the viewport width the image will take up, minus the padding/margin that surrounds it.
<img
srcset="/01a67413-3cca-454a-ab54-c56b4b62afbb/lockwood-kipling-hero.jpg 320w,
/2fbe283e-4485-48ee-b791-3bc5a2b3b4d5/lockwood-kipling-hero.jpg 640w,
/5a1774c6-c5c6-428c-ac07-a99a11b01dfe/lockwood-kipling-hero.jpg 960w,
/7cb36069-083f-499c-8b95-489a5666871f/lockwood-kipling-hero.jpg 1280w,
/d9c09fee-81a7-42bb-8881-8cf5931ea4b3/lockwood-kipling-hero.jpg 1920w,
/d3d19f32-bbd6-47bc-9cae-2cf8f94ae316/lockwood-kipling-hero.jpg 2560w"
sizes="(min-width: 992px) calc(33.333vw - 147px),
(min-width: 500px) calc(50vw - 28px),
calc(100vw - 24px)"
class="events__media-image"
src="/01a67413-3cca-454a-ab54-c56b4b62afbb/lockwood-kipling-hero.jpg"
alt="Lockwood kipling hero" />
The media queries that are being used can be seen below, but they can be seen a tonne of times littered throughout the CSS file which is common when using @include breakpoints in a CSS preprocessor (although it’s incredibly unlikely that anyone is writing CSS for a site this size without a preprocessor).
There are a few tools that are used on the site that I could find that aren’t part of this sites list (see those from further below) but include
- Seadragon – An open-source, web-based viewer for high-resolution zoomable images, implemented in pure JavaScript, for desktop and mobile.
- Pikaday – A refreshing JavaScript Datepicker — lightweight, no dependencies, modular CSS
- SVG4Everybody – SVG for Everybody adds external sprite maps support to otherwise SVG-capable browsers. (add this to the site)
Victoria & Albert Museum Technical Details
Site Meta Tag
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1">
Media Queries
@media (min-width: 768px){ }
@media print{ }
@media (min-width: 992px) { }
@media print and (min-width: 768px) { }
@media (min-width: 750px){ }
@media (min-width: 992px){ }
@media (min-width: 575px) { }
@media (max-width: 286px) { }
@media (max-width: 574px) { }
@media (min-width: 860px) { }
@media (min-width: 900px) { }
@media (min-width: 768px) and (max-width: 992px){ }
@media (min-width: 500px) { }
@media (max-width: 1199px){ }
@media (min-width: 1200px){ }
@media (min-width: 500px) and (max-width: 768px){ }
@media (max-width: 768px){ }