{"rowid": 219, "title": "Speed Up Your Site with Delayed Content", "contents": "Speed remains one of the most important factors influencing the success of any website, and the first rule of performance (according to Yahoo!) is reducing the number of HTTP requests. Over the last few years we\u2019ve seen techniques like sprites and combo CSS/JavaScript files used to reduce the number of HTTP requests. But there\u2019s one area where large numbers of HTTP requests are still a fact of life: the small avatars attached to the comments on articles like this one.\n\nAvatars\n\nMany sites like 24 ways use a fantastic service called Gravatar to provide user images. As a user, you can sign up to Gravatar, give them your e-mail address, and upload an image to represent you. Sites can then include your image by generating a one way hash of your e-mail address and using that to build an image URL. For example, the markup for the comments on this page looks something like this:\n\n
\n\t

\n\t\t\"\"\n Drew McLellan\n\t

\n\t

This is a great article!

\n
\n\nThe Gravatar URL contains two parts. 100 is the size in pixels of the image we want. 13734b0cb20708f79e730809c29c3c48 is an MD5 digest of Drew\u2019s e-mail address. Using MD5 means we can request an image for a user without sharing their e-mail address with anyone who views the source of the page.\n\nSo what\u2019s wrong with avatars?\n\nThe problem is that a popular article can easily get hundreds of comments, and every one of them means another image has to be individually requested from Gravatar\u2019s servers. Each request is small and the Gravatar servers are fast but, when you add them up, it can easily add seconds to the rendering time of a page. Worse, they can delay the loading of more important assets like the CSS required to render the main content of the page.\n\nThese images aren\u2019t critical to the page, and don\u2019t need to be loaded up front. Let\u2019s see if we can delay loading them until everything else is done. That way we can give the impression that our site has loaded quickly even if some requests are still happening in the background.\n\nDelaying image loading\n\nThe first problem we find is that there\u2019s no way to prevent Internet Explorer, Chrome or Safari from loading an image without removing it from the HTML itself. Tricks like removing the images on the fly with JavaScript don\u2019t work, as the browser has usually started requesting the images before we get a chance to stop it.\n\nRemoving the images from the HTML means that people without JavaScript enabled in their browser won\u2019t see avatars. As Drew mentioned at the start of the month, this can affect a large number of people, and we can\u2019t completely ignore them. But most sites already have a textual name attached to each comment and the avatars are just a visual enhancement. In most cases it\u2019s OK if some of our users don\u2019t see them, especially if it speeds up the experience for the other 98%.\n\nRemoving the images from the source of our page also means we\u2019ll need to put them back at some point, so we need to keep a record of which images need to be requested. All Gravatar images have the same URL format; the only thing that changes is the e-mail hash. Storing this is a great use of HTML5 data attributes.\n\nHTML5 data what?\n\nData attributes are a new feature in HTML5. The latest version of the spec says:\n\n\n\tA custom data attribute is an attribute in no namespace whose name starts with the string \u201cdata-\u201d, has at least one character after the hyphen, is XML-compatible, and contains no characters in the range U+0041 to U+005A (LATIN CAPITAL LETTER A to LATIN CAPITAL LETTER Z).\n[\u2026]\nCustom data attributes are intended to store custom data private to the page or application, for which there are no more appropriate attributes or elements. These attributes are not intended for use by software that is independent of the site that uses the attributes.\n\n\nIn other words, they\u2019re attributes of an HTML element that start with \u201cdata-\u201d which you can use to share data with scripts running on your site. They\u2019re great for adding small bits of metadata that don\u2019t fit into an existing markup pattern the way microformats do.\n\nLet\u2019s see this in action\n\nTake a look at the markup for comments again:\n\n
\n\t

\n\t\t\"\"\n Drew McLellan\n\t

\n\t

This is a great article!

\n
\n\nLet\u2019s replace the element with a data-gravatar-hash attribute on the element:\n\n
\n\t

\n Drew McLellan\n\t

\n\t

This is a great article!

\n
\n\nOnce we\u2019ve done this, we\u2019ll need a small bit of JavaScript to find all these attributes, and replace them with images after the page has loaded. Here\u2019s an example using jQuery:\n\n$(window).load(function() {\n\t$('a[data-gravatar-hash]').prepend(function(index){\n\t\tvar hash = $(this).attr('data-gravatar-hash')\n\t\treturn '\"\"'\n\t})\n})\n\nThis code waits until everything on the page is loaded, then uses jQuery.prepend to insert an image into every link containing a data-gravatar-hash attribute. It\u2019s short and relatively simple, but in tests it reduced the rendering time of a sample page from over three seconds to well under one.\n\nFinishing touches\n\nWe still need to consider the appearance of the page before the avatars have loaded. When our script adds extra content to the page it will cause a browser reflow, which is visually annoying. We can avoid this by using CSS to reserve some space for each image before it\u2019s inserted into the HTML:\n\n#comments div {\n\tpadding-left: 110px;\n\tmin-height: 100px;\n\tposition: relative;\n}\n#comments div h4 img {\n\tdisplay: block;\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n}\n\nIn a real world example, we\u2019ll also find that the HTML for a comment is more varied as many users don\u2019t provide a web page link. We can make small changes to our JavaScript and CSS to handle this case.\n\nPut this all together and you get this example.\n\nTaking this idea further\n\nThere\u2019s no reason to limit this technique to sites using Gravatar; we can use similar code to delay loading any images that don\u2019t need to be present immediately. For example, this year\u2019s redesigned Flickr photo page uses a \u201cdata-defer-src\u201d attribute to describe any image that doesn\u2019t need to be loaded straight away, including avatars and map tiles.\n\nYou also don\u2019t have to limit yourself to loading the extra resources once the page loads. You can get further bandwidth savings by waiting until the user takes an action before downloading extra assets. Amazon has taken this tactic to the extreme on its product pages \u2013 extra content is loaded as you scroll down the page.\n\nSo next time you\u2019re building a page, take a few minutes to think about which elements are peripheral and could be delayed to allow more important content to appear as quickly as possible.", "year": "2010", "author": "Paul Hammond", "author_slug": "paulhammond", "published": "2010-12-18T00:00:00+00:00", "url": "https://24ways.org/2010/speed-up-your-site-with-delayed-content/", "topic": "ux"} {"rowid": 280, "title": "Conditional Loading for Responsive Designs", "contents": "On the eighteenth day of last year\u2019s 24 ways, Paul Hammond wrote a great article called Speed Up Your Site with Delayed Content. He outlined a technique for loading some content \u2014 like profile avatars \u2014 after the initial page load. This gives you a nice performance boost.\n\nThere\u2019s another situation where this kind of delayed loading could be really handy: mobile-first responsive design.\n\nResponsive design combines three techniques:\n\n\n\ta fluid grid\n\tflexible images\n\tmedia queries\n\n\nAt first, responsive design was applied to existing desktop-centric websites to allow the layout to adapt to smaller screen sizes. But more recently it has been combined with another innovative approach called mobile first.\n\nRather then starting with the big, bloated desktop site and then scaling down for smaller devices, it makes more sense to start with the constraints of the small screen and then scale up for larger viewports. Using this approach, your layout grid, your large images and your media queries are applied on top of the pre-existing small-screen design. It\u2019s taking progressive enhancement to the next level.\n\nOne of the great advantages of the mobile-first approach is that it forces you to really focus on the core content of your page. It might be more accurate to think of this as a content-first approach. You don\u2019t have the luxury of sidebars or multiple columns to fill up with content that\u2019s just nice to have rather than essential.\n\nBut what happens when you apply your media queries for larger viewports and you do have sidebars and multiple columns? Well, you can load in that nice-to-have content using the same kind of Ajax functionality that Paul described in his article last year. The difference is that you first run a quick test to see if the viewport is wide enough to accommodate the subsidiary content. This is conditional delayed loading.\n\nConsider this situation: I\u2019ve published an article about cats and I\u2019d like to include relevant cat-related news items in the sidebar \u2026but only if there\u2019s enough room on the screen for a sidebar.\n\nI\u2019m going to use Google\u2019s News API to return the search results. This is the ideal time to use delayed loading: I don\u2019t want a third-party service slowing down the rendering of my page so I\u2019m going to fire off the request after my document has loaded.\n\nHere\u2019s an example of the kind of Ajax function that I would write:\n\nvar searchNews = function(searchterm) {\n\tvar elem = document.createElement('script');\n\telem.src = 'http://ajax.googleapis.com/ajax/services/search/news?v=1.0&q='+searchterm+'&callback=displayNews';\n\tdocument.getElementsByTagName('head')[0].appendChild(elem);\n};\n\nI\u2019ve provided a callback function called displayNews that takes the JSON result of that Ajax request and adds it an element on the page with the ID newsresults:\n\nvar displayNews = function(news) {\n\tvar html = '',\n\titems = news.responseData.results,\n\ttotal = items.length;\n\tif (total>0) {\n\t\tfor (var i=0; i';\n\t\t\thtml+= '';\n\t\t\thtml+= '

'+item.titleNoFormatting+'

';\n\t\t\thtml+= '
';\n\t\t\thtml+= '

';\n\t\t\thtml+= item.content;\n\t\t\thtml+= '

';\n\t\t\thtml+= '';\n\t\t}\n\t\tdocument.getElementById('newsresults').innerHTML = html;\n\t}\n};\n\nNow, I can call that function at the bottom of my document:\n\n\n\nIf I only want to run that search when there\u2019s room for a sidebar, I can wrap it in an if statement:\n\n\n\nIf the browser is wider than 640 pixels, that will fire off a search for news stories about cats and put the results into the newsresults element in my markup:\n\n
\n \n
\n\nThis works pretty well but I\u2019m making an assumption that people with small-screen devices wouldn\u2019t be interested in seeing that nice-to-have content. You know what they say about assumptions: they make an ass out of you and umptions. I should really try to give everyone at least the option to get to that extra content:\n\n
\n Search Google News\n
\n\nSee the result\n\nVisitors with small-screen devices will see that link to the search results; visitors with larger screens will get the search results directly.\n\nI\u2019ve been concentrating on HTML and JavaScript, but this technique has consequences for content strategy and information architecture. Instead of thinking about possible page content in a binary way as either \u2018on the page\u2019 or \u2018not on the page\u2019, conditional loading introduces a third \u2018it\u2019s complicated\u2019 option.\n\nThis was just a simple example but I hope it illustrates that conditional loading could become an important part of the content-first responsive design approach.", "year": "2011", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2011-12-02T00:00:00+00:00", "url": "https://24ways.org/2011/conditional-loading-for-responsive-designs/", "topic": "ux"} {"rowid": 284, "title": "Subliminal User Experience", "contents": "The term \u2018user experience\u2019 is often used vaguely to quantify common elements of the interaction design process: wireframing, sitemapping and so on. UX undoubtedly involves all of these principles to some degree, but there really is a lot more to it than that.\n\nGood UX is characterized by providing the user with constant feedback as they step through your interface. It means thinking about and providing fallbacks and error resolutions in even the rarest of scenarios. It\u2019s about omitting clutter to make way for the necessary, and using the most fundamental of design tools to influence a user\u2019s path. It means making no assumptions, designing right down to the most distinct details and going one step further every single time. In many cases, good UX is completely subliminal.\n\nThere are simple tools and subtleties we can build into our products to enhance the overall experience but, in order to do so, we really have to step beyond where we usually draw the line on what to design.\n\nThe purpose of this article is not to provide technical how-tos, as the functionality is, in most cases, quite simple and could be implemented in a myriad of ways. Rather, it will present a handful of ideas for enhancing the experience of an interface at a deeper level of design without relying on the container.\n\nWe\u2019ll cover three elements that should get you thinking in the right mindset:\n\n\n\tprogress activity and post-active states\n\tpseudo-class preloading\n\tbuttons and their (mis)behaviour\n\n\nProgress activity and the post-active state\n\nWe\u2019ve long established that we can\u2019t control the devices our products are viewed on, which browser they\u2019ll run in or what connection speed will be used to access them. We accept this all as factual, so why is it so often left to the browser to provide feedback to the user when an event is triggered or an error encountered? The browser isn\u2019t part of the interface \u2014 it\u2019s merely a container. A simple, visual recognition of your users\u2019 activity may be all it takes to make or break the product.\n\nLet\u2019s begin with a commonly overlooked case: progress activity.\n\nA user moves their cursor over a hyperlink or button, which is clearly defined as one by the visual language of your content. Upon doing so, they trigger the :hover state to confirm this element is indeed interactive. So far, so good. What happens next is where it starts to fall apart: the user hits this link, presumably triggering an :active state, which is then returned to the normal state upon release. And then what?\n\n\n\nFrom this point on, your user is in limbo. The link has fallen back to either its regular or :visited state. You\u2019ve effectively abandoned them and are relying entirely on the browser they\u2019re using to communicate that something is happening. This poses quite a few problems:\n\n\n\tThe user may lose focus of what they were doing.\n\tThere is little consistency between progress indication in browsers.\n\tThe user may not even notice that their action has been acknowledged.\n\n\nHow many times have one or more of these events happened to you due to a lack of communication from the interface?\n\nThink about the differences between Safari and Chrome in this area \u2014 two browsers that, when compared to each other, are relatively similar in nature, though this basic feature differs in execution.\n\n\n\nLike all aspects of designing the user experience, there is no one true way to fix this problem, but we can introduce details that many users will unconsciously appreciate.\n\nConsider the basic loading indicator. It\u2019s nothing new \u2014 in fact, some would argue it\u2019s quite a clich\u00e9. However, whether using a spinning wheel or a progress bar, a gif or JavaScript, or something more sophisticated, these simple tools create an illusion of movement, progress and activity. Depending on the implementation, progress indication graphics can significantly increase a user\u2019s perception of the speed in which an event is taking place. Combine this with a cursor change and a lock over the element to prevent double-clicking or reloading, and your chances of keeping your user\u2019s valuable attention have significantly increased.\n\nDemo: Progress activity and the post-active state\n\nThis same logic applies to all aspects of defaulting in a browser, from micro-elements like this up to something as simple as a 404 page. The difference in a user\u2019s reaction to hitting the default Apache 404 and a hand-crafted, branded page are phenomenal and there are no prizes for guessing which one they\u2019re more likely to exit from.\n\nPseudo-class preloading\n\nAnother detail that it pays well to look after is the use and abuse of the :hover element and, more importantly, the content revealed by it. Chances are you\u2019re using the :hover pseudo-class somewhere in almost every screen you create. If content is being revealed on :hover and that content takes some time to load, there will inevitably be a delay the first time it is initiated. It appears tacky and half-finished when a tooltip or drop-down loads instantly, only to have its background or supporting elements follow through a second or two later. So, let\u2019s preload the elements we know we\u2019ll need.\n\nA very simple application of this would be to load each file into the default state of a visible element and offset them by a large number. This ensures our elements have loaded and are ready if and when they need to be displayed.\n\nelement {\n background: url(path/to/image.jpg) -9999em -9999em no-repeat;\n }\nelement .tooltip {\n display: none;\n }\nelement:hover .tooltip {\n display: block;\n background: url(path/to/image.jpg) 0 0;\n }\n\nBackground images are just one example. Of course, the same logic can apply to any form of revealed content. Using a sprite graphic can also be a clever \u2014 albeit tedious \u2014 method for achieving the same goal, so if you\u2019re using a sprite, preloading in this way may not be necessary\n\nThe differences between preloading and not can only be visualized properly with an actual demonstration.\n\nDemo: Preloading revealed content\n\nButtons and their (mis)behaviour\n\nAlmost all of the time, a button serves just one purpose: to be clicked (or tapped). When a button\u2019s pressed, therefore, if anything other than triggering the desired event occurs, a user naturally becomes frustrated. I often get funny looks when talking about this, but designing the details of a button is something I consider essential.\n\nIt goes without saying that a button should always visually recognise :hover and :active states. We can take that one step further and disable some actions that get in the way of pressing the button.\n\nIt\u2019s rare that a user would ever want to select and use the text on a button, so let\u2019s cleanly disable it:\n\nelement {\n -moz-user-select: -moz-none;\n -webkit-user-select: none;\n user-select: none;\n }\n\nIf the button is image-based or contains an image, we could also disable user dragging to make sure the image element stays locked to the button:\n\nelement {\n -moz-user-drag: -moz-none;\n -webkit-user-drag: none;\n user-drag: none;\n }\n\nDemo: A more usable button\n\nDisabling global features like this should be done with utmost caution as it\u2019s very easy to cross the line between enhancement and friction. Cases where this is acceptable are very rare, but it\u2019s a good trick to keep in mind nevertheless. Both Apple\u2019s iCloud and Metalab\u2019s Flow applications use these tools appropriately and to great extent.\n\nYou could argue that the visual feedback of having the text selected or image dragged when a user mis-hits the button is actually a positive effect, informing the user that their desired action did not work. However, covering for human error should be a designer\u2019s job, not that of our users. We can (almost) ensure it does work for them by accommodating for errors like this in most cases.\n\nFinal thoughts\n\nDesigning to this level of detail can seem obsessive, but as a designer and user of many interfaces and applications, I believe it can be the difference between a good user experience and a great one.\n\nThe samples you\u2019ve just seen are only a fraction of the detail we can design for. Keep in mind that the demonstrations, code and methods above outline just one way to do this. You may not agree with all of these processes or have the time and desire to consider them, but one fact remains: it\u2019s not the technology, or the way it\u2019s done that\u2019s important \u2014 it\u2019s the logic and the concept of designing everything.", "year": "2011", "author": "Chris Sealey", "author_slug": "chrissealey", "published": "2011-12-03T00:00:00+00:00", "url": "https://24ways.org/2011/subliminal-user-experience/", "topic": "ux"} {"rowid": 274, "title": "Adaptive Images for Responsive Designs", "contents": "So you\u2019ve been building some responsive designs and you\u2019ve been working through your checklist of things to do:\n\n\n\tYou started with the content and designed around it, with mobile in mind first.\n\tYou\u2019ve gone liquid and there\u2019s nary a px value in sight; % is your weapon of choice now.\n\tYou\u2019ve baked in a few media queries to adapt your layout and tweak your design at different window widths.\n\tYou\u2019ve made your images scale to the container width using the fluid Image technique.\n\tYou\u2019ve even done the same for your videos using a nifty bit of JavaScript.\n\n\nYou\u2019ve done a good job so pat yourself on the back. But there\u2019s still a problem and it\u2019s as tricky as it is important: image resolutions.\n\nHTML has an problem\n\nCSS is great at adapting a website design to different window sizes \u2013 it allows you not only to tweak layout but also to send rescaled versions of the design\u2019s images. And you want to do that because, after all, a smartphone does not need a 1,900-pixel background image1.\n\nHTML is less great. In the same way that you don\u2019t want CSS background images to be larger than required, you don\u2019t want that happening with s either. A smartphone only needs a small image but desktop users need a large one. Unfortunately s can\u2019t adapt like CSS, so what do we do?\n\nWell, you could just use a high resolution image and the fluid image technique would scale it down to fit the viewport; but that\u2019s sending an image five or six times the file size that\u2019s really needed, which makes it slow to download and unpleasant to use. Smartphones are pretty impressive devices \u2013 my ancient iPhone 3G is more powerful in every way than my first proper computer \u2013 but they\u2019re still terribly slow in comparison to today\u2019s desktop machines. Sending a massive image means it has to be manipulated in memory and redrawn as you scroll. You\u2019ll find phones rapidly run out of RAM and slow to a crawl.\n\nWell, OK. You went mobile first with everything else so why not put in mobile resolution s too? Because even though mobile devices are rapidly gaining share in your analytics stats, they\u2019re still not likely to be the major share of your user base. I don\u2019t think desktop users would be happy with pokey little mobile resolution images, do you? What we need are adaptive images.\n\nAdaptive image techniques\n\nThere are a number of possible solutions, each with pros and cons, and it\u2019s not as simple to find a graceful solution as you might expect.\n\nYour first thought might be to use JavaScript to trawl through the markup and rewrite the source attribute. That\u2019ll get you the right end result, but it\u2019ll have done it in a way you absolutely don\u2019t want. That\u2019s because of the way browsers load resources. It starts to load the HTML and builds the page on-the-fly; as soon as it finds an element it immediately asks the server for that image. After the HTML has finished loading, the JavaScript will run, change the src attribute, and then the browser will request that new image too. Not instead of, but as well as. Not good: that\u2019s added more bloat instead of cutting it.\n\nPlain JavaScript is out then, which is a problem, because what other tools do we have to work with as web designers? Let\u2019s ignore that for now and I\u2019ll outline another issue with the concept of serving different resolution images for different window widths: a basic file management problem. To request a different image, that image has to exist on the server. How\u2019s it going to get there? That\u2019s not a trivial problem, especially if you have non-technical users that update content through a CMS. Let\u2019s say you solve that \u2013 do you plan on a simple binary switch: big image|little image? Is that really efficient or future-proof? What happens if you have an archive of existing content that needs to behave this way? Can you apply such a solution to existing content or markup?\n\nThere\u2019s a detailed round-up of potential techniques for solving the adaptive images problem over at the Cloud Four blog if you fancy a dig around exploring all the options currently available. But I\u2019m here to show you what I think is the most flexible and easy to implement solution, so here we are.\n\nAdaptive Images\n\nAdaptive Images aims to mitigate most of the issues surrounding the problems of bringing the venerable tag into the 21st century. And it works by leaving that tag completely alone \u2013 just add that desktop resolution image into the markup as you\u2019ve been doing for years now. We\u2019ll fix it using secret magic techniques and bottled pixie dreams. Well, fine: with one .htaccess file, one small PHP file and one line of JavaScript. But you\u2019re killing the mystique with that kind of talk.\n\nSo, what does this solution do?\n\n\n\tIt allows s to adapt to the same break points you use in your media queries, giving granular control in the same way you get with your CSS.\n\tIt installs on your server in five minutes or less and after that is automatic and you don\u2019t need to do anything.\n\tIt generates its own rescaled images on the server and doesn\u2019t require markup changes, so you can apply it to existing web content.\n\tIf you wish, it will make all of your images go mobile-first (just in case that\u2019s what you want if JavaScript and cookies aren\u2019t available).\n\n\nSound good? I hope so. Here\u2019s what you do.\n\nSetting up and rolling out\n\nI\u2019ll assume you have some basic server knowledge along with that wealth of front-end wisdom exploding out of your head: that you know not to overwrite any existing .htaccess file for example, and how to set file permissions on your server. Feeling up to it? Excellent.\n\n\n\tDownload the latest version of Adaptive Images either from the website or from the GitHub repository.\n\tUpload the included .htaccess and adaptive-images.php files into the root folder of your website.\n\tCreate a directory called ai-cache and make sure the server can write to it (CHMOD 755 should do it).\n\tAdd the following line of JavaScript into the of your site:\n\n\n\n\nThat\u2019s it, unless you want to tweak the default settings. You likely do, but essentially you\u2019re already up and running.\n\nHow it works\n\nAdaptive Images does a number of things depending on the scenario the script has to handle, but here\u2019s a basic overview of what it does when you load a page running it:\n\n\n\tA session cookie is written with the value of the visitor\u2019s screen size in pixels.\n\tThe HTML encounters an tag and sends a request to the server for that image. It also sends the cookie, because that\u2019s how browsers work.\n\tApache sits on the server and receives the request for the image. Apache then has a look in the .htaccess file to see if there are any special instructions for files in the requested URL.\n\tThere are! The .htaccess says \u201cHey, server! Any request you get for a JPG, GIF or PNG file just send to the adaptive-images.php file instead.\u201d\n\tThe PHP file then does some intelligent thinking which can cover a number of scenarios, but I\u2019ll illustrate one path that can happen:\n\n\n\t\n\t\tThe PHP file looks for the cookie and finds out that the user has a maximum screen width of 480px.\n\t\tThe PHP has a look at the available media query sizes that were configured and decides which one matches the user\u2019s device.\n\t\tIt then has a look inside the /ai-cache/480/ folder to see if a rescaled image already exists there.\n\t\tWe\u2019ll pretend it doesn\u2019t \u2013 the PHP then goes to the actual requested URI and finds that the original file does exist.\n\t\tIt has a look to see how wide that image is. If it\u2019s already smaller than the user\u2019s screen width it sends it along and stops there. But, let\u2019s pretend the image is 1,000px wide.\n\t\tThe PHP then resizes the image and saves it into the /ai-cache/480 folder ready for the next time someone needs it.\n\t\n\nIt also does a few other things when needs arise, for example:\n\n\n\tIt sends images with a cache header field that tells proxies not to cache the image, while telling browsers they should. This avoids problems with proxy servers and network caching systems grabbing the wrong image and storing it.\n\tIt handles cases where there isn\u2019t a cookie set, and you can choose whether to then send the mobile version or the largest configured media query size.\n\tIt compares timestamps between the source image and the generated cache image \u2013 to ensure that if the source image gets updated, the old cached file won\u2019t be sent.\n\n\nCustomizing\n\nThere are a few options you can customize if you don\u2019t like the default values. By looking in the PHP\u2019s configuration section at the top of the file, you can:\n\n\n\tSet the resolution breakpoints to match your media query break points.\n\tChange the name and location of the ai-cache folder.\n\tChange the quality level any generated JPG images are saved at.\n\tHave it perform a subtle sharpen on rescaled images to help keep detail.\n\tToggle whether you want it to compare the files in the cache folder with the source ones or not.\n\tSet how long the browser should cache the images for.\n\tSwitch between a mobile-first or desktop-first approach when a cookie isn\u2019t found.\n\n\nMore importantly, you probably want to omit a few folders from the AI behaviour. You don\u2019t need or want it resizing the images you\u2019re using in your CSS, for example. That\u2019s fine \u2013 just open up the .htaccess file and follow the instructions to list any directories you want AI to ignore. Or, if you\u2019re a dab hand at RewriteRules you can remove the exclamation mark at the start of the rule and it\u2019ll only apply AI behaviour to a given list of folders.\n\nCaveats\n\nAs I mentioned, I think this is one of the most flexible, future-proof, retrofittable and easy to use solutions available today. But, there are problems with this approach as there are with all of the ones I\u2019ve seen so far.\n\nThis is a PHP solution\n\nI wish I was smarter and knew some fancy modern languages the cool kids discuss at parties, but I don\u2019t. So, you need PHP on your server. That said, Adaptive Images has a Creative Commons licence2 and I would welcome anyone to contribute a port of the code3. \n\nContent delivery networks\n\nAdaptive Images relies on the server being able to: intercept requests for images; do some logic; and send one of a given number of responses. Content delivery networks are generally dumb caches, and they won\u2019t allow that to happen. Adaptive Images will not work if you\u2019re using a CDN to deliver your website.\n\nA minor but interesting cookie issue.\n\nAs Yoav Weiss pointed out in his article Preloaders, cookies and race conditions, there is no way to guarantee that a cookie will be set before images are requested \u2013 even though the JavaScript that sets the cookie is loaded by the browser before it finds any tags. That could mean images being requested without a cookie being available. Adaptive Images has a two-fold mechanism to avoid this being a problem:\n\n\n\tThe $mobile_first toggle allows you to choose what to send to a browser if a cookie isn\u2019t set. If FALSE then it will send the highest configured resolution; if TRUE it will send the lowest.\n\tEven if set to TRUE, Adaptive Images checks the User Agent String. If it discovers the user is on a desktop environment, it will override $mobile_first and set it to FALSE.\n\n\nThis means that if $mobile_first is set to TRUE and the user was unlucky (their browser didn\u2019t write the cookie fast enough), mobile devices will be supplied with the smallest image, and desktop devices will get the largest.\n\nThe best way to get a cookie written is to use JavaScript as I\u2019ve explained above, because it\u2019s the fastest way. However, for those that want it, there is a JavaScript-free method which uses CSS and a bogus PHP \u2018image\u2019 to set the cookie. A word of caution: because it requests an external file, this method is slower than the JavaScript one, and it is very likely that the cookie won\u2019t be set until after images have been requested.\n\nThe future\n\nFor today, this is a pretty good solution. It works, and as it doesn\u2019t interfere with your markup or source material in any way, the process is non-destructive. If a future solution is superior, you can just remove the Adaptive Images files and you\u2019re good to go \u2013 you\u2019d never know AI had been there.\n\nHowever, this isn\u2019t really a long-term solution, not least because of the intermittent problem of the cookie and image request race condition. What we really need are a number of standardized ways to handle this in the future.\n\nFirst, we could do with browsers sending far more information about the user\u2019s environment along with each HTTP request (device size, connection speed, pixel density, etc.), because the way things work now is no longer fit for purpose. The web now is a much broader entity used on far more diverse devices than when these technologies were dreamed up, and we absolutely require the server to have better knowledge about device capabilities than is currently possible. Relying on cookies to do this job doesn\u2019t cut it, and the User Agent String is a complete mess incapable of fulfilling the various purposes we are forced to hijack it for.\n\nSecondly, we need a W3C-backed markup level solution to supply semantically different content at different resolutions, not just rescaled versions of the same content as Adaptive Images does.\n\nI hope you\u2019ve found this interesting and will find Adaptive Images useful.\n\nFootnotes\n\n1 While I\u2019m talking about preventing smartphones from downloading resources they don\u2019t need: you should be careful of your media query construction if you want to stop WebKit downloading all the images in all of the CSS files.\n\n2 Adaptive Images has a very broad Creative Commons licence and I warmly welcome feedback and community contributions via the GitHub repository. \n\n3 There is a ColdFusion port of an older version of Adaptive Images. I do not have anything to do with ported versions of Adaptive Images.", "year": "2011", "author": "Matt Wilcox", "author_slug": "mattwilcox", "published": "2011-12-04T00:00:00+00:00", "url": "https://24ways.org/2011/adaptive-images-for-responsive-designs/", "topic": "ux"} {"rowid": 269, "title": "Adaptive Images for Responsive Designs\u2026 Again", "contents": "When I was asked to write an article for 24 ways I jumped at the chance, as I\u2019d been wanting to write about some fun hacks for responsive images and related parsing behaviours. My heart sank a little when Matt Wilcox beat me to the subject, but it floated back up when I realized I disagreed with his method and still had something to write about.\n\nSo, Matt Wilcox, if that is your real name (and I\u2019m pretty sure it is), I disagree. I see your dirty server-based hack and raise you an even dirtier client-side hack. Evil laugh, etc., etc.\n\nYou guys can stomach yet another article about responsive design, right? Right?\n\nHalf the room gets up to leave\n\nWhoa, whoa\u2026 OK, I\u2019ll cut to the chase\u2026\n\nTL;DR\n\nIn a previous episode, we were introduced to Debbie and her responsive cat poetry page. Well, now she\u2019s added some reviews of cat videos and some images of cats. Check out her new page and have a play around with the browser window. At smaller widths, the images change and the design responds. The benefits of this method are:\n\n\n\tit\u2019s entirely client-side\n\timages are still shown to users without JavaScript\n\tyour media queries stay in your CSS file\n\tno repetition of image URLs\n\tno extra downloads per image\n\tit\u2019s fast enough to work on resize\n\tit\u2019s pure filth\n\n\nWhat\u2019s wrong with the server-side solution?\n\nResponsive design is a client-side issue; involving the server creates a boatload of problems.\n\n\n\tIt sets a cookie at the top of the page which is read in subsequent requests. However, the cookie is not guaranteed to be set in time for requests on the same page, so the server may see an old value or no value at all.\n\tServing images via server scripts is much slower than plain old static hosting.\n\tThe URL can only cache with vary: cookie, so the cache breaks when the cookie changes, even if the change is unrelated. Also, far-future caching is out for devices that can change width.\n\tIt depends on detecting screen width, which is rather messy on mobile devices.\n\tResponding to things other than screen width (such as DPI) means packing more information into the cookie, and a more complicated script at the top of each page.\n\n\nSo, why isn\u2019t this straightforward on the client?\n\nClient-side solutions to the problem involve JavaScript testing user agent properties (such as screen width), looping through some images and setting their URLs accordingly. However, by the time JavaScript has sprung into action, the original image source has already started downloading. If you change the source of an image via JavaScript, you\u2019re setting off yet another request.\n\nImages are downloaded as soon as their DOM node is created. They don\u2019t need to be visible, they don\u2019t need to be in the document.\n\nnew Image().src = url\n\nThe above will start an HTTP request for url. This is a handy trick for quick requests and preloading, but also shows the browser\u2019s eagerness to download images.\n\nHere\u2019s an example of that in action. Check out the network tab in Web Inspector (other non-WebKit development aids are available) to see the image requests.\n\nBecause of this, some client-side solutions look like this:\n\n\n\nwhere t.gif is a 1\u00d71px tiny transparent GIF.\n\nThis results in no images if JavaScript isn\u2019t available. Dealing with the absence of JavaScript is still important, even on mobile. I was recently asked to make a website work on an old Blackberry 9000. I was able to get most of the way there by preventing that OS parsing any JavaScript, and that was only possible because the site didn\u2019t depend on it.\n\nWe need to delay loading images for JavaScript users, but ensure they load for users without JavaScript. How can we conditionally parse markup depending on JavaScript support?\n\nOh yeah!