Responsive Retrofit: Kitchen Daily
One of our flagship AOL client sites, KitchenDaily.com, decided that they wanted Ashe Avenue to implement a responsive solution. We’ve been rolling out more responsive sites lately (including AsheAve 2.5), so we were excited to get this excellent site working smoothly on devices of unusual sizes.
Challenges
When the designs landed, we were slightly taken aback – the AOL design team had gone for an aggressively “app-like” look and feel, including menu reorganization, re-flow of some pages, adding new icons and much more. That said, since it was a really beautiful design, the challenge would be well worth it. After some discussion about timelines, we decided to break the responsive build in two, saving all of the user-based elements for Phase 2 (As of late-July, it’s a work in progress).
In addition, the designs had the unusual feature of being smartphone-only. The client was happy with the modest scaling that took place on tablets, so they only wanted this to work on sub-620px devices. This isn’t unreasonable – the site is a static 940px, so that translates to 2/3 scaling, and we’ve found the site to be quite useful at those dimensions.
Solutions
Smartphones Only!
Since setting a viewport meta tag is a requirement for starting a responsive build, we’ll begin there. In this case we were lucky – one of our previous clients had a similar smartphone-only build requirement, so we revisited the code used there. At first, it looked to be a drop-in solution, but Kitchen Daily is far more complex, and the extensive JavaScript and image loading meant that the code would have to be rewritten.
The basic problem is this: responsive designs rely on the use of the viewport meta tag:
<meta id="viewport" name="viewport" content="width=device-width initial-scale=1">
This tag tells the mobile device, “Do not scale this website – use the actual width.” As mentioned before, that’s 940px for Kitchen Daily. The problem is, if we add this tag to the header, it stops scaling for all devices, and the client wants scaling to work on tablets.
Luckily, it’s possible to insert this tag into the head using JavaScript. All we have to do is detect the width of the device and if it’s below a certain size (say 600px, to account for scrollbars and such), insert the tag. The first attempt, using a mix of screen and browser window detection worked fine – until the user rotated the device! At that point we needed to use the height dimension. Luckily, there’s an “orientation” property we can use to figure that out.
The final script worked pretty well, but the client’s QA team spotted a bug – there was a momentary flash of the full-sized site, scaled down, before the page loaded properly. This was caused by the fact that we had been firing the script in our main JS file, which loads after the document does, for specific reasons. Since the Kitchen Daily site is very large, it becomes noticeable.
The solution, as suggested by JS/CSS wizard Rachel Nabors (spouse of the author), was to strip out the jQuery in my original solution and move the vanilla js into the header. This turned out to be so useful, we decided to break it out as a standalone script, tidy up the code, and make a minified version for direct use in the header (thus removing an http call). This has been published to Github as setviewport.js.
Media-queries
Once we had the viewport issues worked out, we could start using Media Queries to selectively edit the layout. Since we knew that we wanted 600px to be our magic number, the first media query was basic:
@media screen and (max-width: 600px) {}
Any browser smaller than 600px wide would now have special styles applied. The first style is the simplest:
display: none !important;
This allows us to hide any element that the client design deems non-essential for the mobile experience. The current tally for this is 56 items, and includes the right rail (sidebar) and many other elements. Some may balk at the !important argument, but in this case it’s a huge timesaver, since it effectively hides elements that would be displayed via JavaScript, inline CSS (think 3rd-party code like ads), and CSS with higher specificity.
Next, we start shrinking things down to the page width. By resizing the browser to 400px, we get a scrollbar on the bottom of the page. If we then scroll all the way to the right and “select all,” we can see the items that are too wide. Using the Chrome inspector tool, we then go down the page modifying elements to width: 100%; and height: auto; until the scrollbar on the bottom of the browser goes away. This process normally takes a few hours – on Kitchen Daily it took three days!
After that, the meticulous work of reviewing the designs and replicating the look and feel begins. We like to start with the most-used elements first, such as the header and footer. Once those are done, the site starts to really feel like a mobile site. Eventually, we reach a point in the build where we had to rearrange some page elements. Enter JavaScript.
JavaScript-Foo
The main Kitchen Daily site uses a lot of JavaScript to enable drop-downs such as the Search. Because the site relies on JavaScript, there’s no real penalty for manipulating page elements with it. We use the jQuery JS library as well, so adding the new ‘Browse All Recipes’ page element was relatively simple. Our setviewport.js code above sets two global variables: objectWidth and triggerWidth. In our main JS file we just add the following:
var isMobile = false;
if ( objectWidth <= triggerWidth ) { isMobile = true; }
This allows us to trigger code only in the mobile view, such as this:
$('#carousel-homepage').after('<div class="mobile-recipe-link"><a href="/recipes">Browse All Recipes</a></div>');
Thus inserting the ’Browse All Recipes’ element into the page. Luckily, this homepage-unique element was to be inserted right after a homepage-unique carousel. We wound up with about a dozen of these kinds of manipulations.
Retina Image Magic
For the main site, we’ve previously only used a retina-based logo, which is fairly easy to implement using pixel-density meta-tags. With the rising tide of high-pixel-density mobile displays, all of the site elements need to have high-res versions. Enter the retina sprite! Again, we we blessed by the AOL design team sending over a comp (.PSD) that was double-sized, so the process of creating and updating the mobile/retina sprite was:
- Create 800px wide image
- Add full-sized (retina) image sprites
- Save (mobile-sprite-retina.psd)
- Save for web (mobile-sprite-retina.png)
- Reduce mobile-sprite-retina.psd by 50%
- Save for web (mobile-sprite.png)
- Step backward, save.
We use the mobile-sprite.png in the main media query section. For retina, we combine the max-width: 600px media query with the pixel-density detection to make this beast of a media query:
@media only screen and (-webkit-min-device-pixel-ratio: 1.5) and (max-width: 600px), only screen and (-o-min-device-pixel-ratio: 3/2) and (max-width: 600px), only screen and (min--moz-device-pixel-ratio: 1.5) and (max-width: 600px), only screen and (min-device-pixel-ratio: 1.5) and (max-width: 600px) {}
Inside of that we put the relevant CSS selectors (anything that used mobile-sprite.png) and use this:
background-image: url('../img/mobile-sprite-retina.png');
background-size: 400px;
This has the effect of sizing the retina sprite to the container in the right proportions, which on retina devices render using the higher pixel density. Magical!
Conclusion
The Phase 1 responsive build took over three weeks of coding, testing, debugging and polishing, but was certainly worth it. It gives you the ability to look up a great recipe when you see a sale in the market, send friends a link when you’re having lunch, or follow a recipe when you’re standing at the grill. Getting some releasable code such as setviewport.js was a nice bonus.
Onward to Phase 2 – user elements!