home / 24ways

24ways

Custom SQL query returning 37 rows

Query parameters

rowidtitlecontentsyearauthorauthor_slugpublishedurltopic
74 Should We Be Reactive? Evolution Looking at the evolution of the web and the devices we use should help remind us that the times we’re adjusting to are just another step on a journey. These times seem to be telling us that we need to embrace flexibility. Imagine an HTML file containing nothing but text. It’s viewable on any web-capable device and reasonably readable: the notion of the universality of the web was very much a founding principle. Right from the beginning, browser vendors understood that we’d want text to reflow (why wouldn’t we?), so I consider the first websites to have been fluid. As we attempted to exert more control through our designs in the early days of the web, debates about whether we should produce fixed or fluid sites raged. We could create fluid designs using tables, but what we didn’t have then was a wide range of web capable devices or the ability to control this fluidity. The biggest changes occurred when stats showed enough people using a different screen resolution we could cater for. To me, the techniques of responsive web design provide the control we were missing. Combining new approaches to layout and images with media queries empowered us to learn how to embrace the inherent flexibility of the web in ways to suit our work and the devices used by our audience. Perhaps another kind of flexibility might be found in how we use context to affect how we present our content; to consider how we might use the information we can access from people, browsers and devices to provide web experiences – effectively creating sites that react to initial or changing circumstances in the relationship between people and our content. Embracing flexibility So what is context? Put simply, you could think of it as a secondary piece of information that helps clarify the meaning of the first. It helps set a scene or describe circumstances. I think that Cennydd Bowles has summed it up really well through talks he’s given recently, in which he’s arrived at the acronym DETAILS (Device, Environment, Time, Activity, Individual, Location, Social) – I encourage you to keep an eye out for his next book due in the new year where he’ll explore this idea much further. This clarity over what context could mean in terms of what we do on the web is fundamental, directing us towards ways we might use it. When you stop to think about it, we’ve been using some basic pieces of this information right from the beginning, like bits of JavaScript or Java applets that serve an appropriate greeting to your site’s visitors, or show their location, or even local weather. But what if we think of this from the beginning of our projects? We should think about our content first. Once we know this and have a direction, perhaps then we can think about what context, or even multiple contexts, might help us to communicate more effectively. The real world There’s always been a disconnect between the real world and the web, which is to be expected. But the world around us is a sea of data; every fundamental building block: people, places, events and things have information waiting to be explored. For sites based around physical objects or locations, this divide is really apparent. We don’t ordinarily take the time to describe in code the properties of a place, or consider whether your relationship to the place in the real world should have any impact on your relationship with a site about it. When I think about local businesses, they have such rich properties to draw on and yet we don’t really explore them in any meaningful way, even through something as simple as opening hours. Now we have data… We’ve long had access to the current time both on server- and client-sides. The use of geolocation is easier than ever, but when we look at the range of information we could glean to help us make some choices, maybe there’s some help on the horizon from projects like the W3C Device APIs Working Group. This might prove useful to help make us aware of network and battery conditions of a device, along with the potential to gain data from other sensors, which could tell us about lighting conditions, ambient noise levels and temperature depending on the capabilities of the device. It may be that our sites have some form of login or access to your profile from another site. Along with data from our devices and browsers, this should give us a sense of how best to talk to our audience in certain situations. We don’t necessarily need to know any personal details, just enough to make decisions about how to present our sites. The reactive web? So why reactive web design? I’m hoping that a name might help us to have a common vocabulary not only about what we mean when we talk about context, but how it could be considered through our projects, right from the early stages. How could this manifest itself? A simple example might be a location-aware panel on your site. Perhaps the space is a little down in your content hierarchy but serves a perfectly valid purpose by default. To visitors outside the country perhaps this works fine, but within your country maybe this panel could be used to communicate more effectively. Further still, if we knew the visitors were in the vicinity, we could talk to them more directly. What if both time and location were relevant? This space could work as before but you could consider how time could intersect with your local audience. If you know they’re local and it’s a certain time of day, you could communicate directly with them. This example isn’t beyond what banner ads often do and uses easily accessible information. There are more unusual combinations we may be able to find, such as movement and presence. Perhaps a site that tells a story, which changes design and content based on whether you’re moving, how long you’ve been on the site and how far you’ve travelled. This isn’t what we typically expect from websites, but we should bear in mind that what websites are now will not be what they become in the future. You could do much of this contextual presentation through native apps, of course. The Silent History, an app novel written and designed for iPad and iPhone, uses an exploration element, providing “hundreds of location-based stories across the U.S. and around the world. These can be read only when your device’s GPS matches the coordinates of the specified location.” But considering the universality of the web, we could redefine what web-based experiences should be like. Not all methods would work well on the web, but that’s a decision that has to be made for a specific project. By thinking more broadly about any web-capable device, we can use what we know to provide relevant experiences for our site’s visitors. We need to be sure what we mean by relevant, of course! Reality bites While there are incredible possibilities, from a simple panel on a site to something bordering on living sites that evolve and change with our circumstances, we need to act with a degree of pragmatism and understand how much of what we could do is based on assumptions and the bias of our own experiences. We could go wild with changing the way our content is presented based on contextual information, but if we’re not careful what we end up with confuses and could provide a very fractured experience. As much as possible we need to think more ethnographically, observe and question people in the situations we think may be relevant, and test our assumptions as early as we can. Even on small projects, there may be ways we can validate our assumptions and test with our audience. The key to applying contextual content or cues is not to break the experience between contextual views (as I think we now wouldn’t when hiding content on a mobile view). It’s another instance of progressive enhancement – as we know certain pieces of information, we can enhance the experience. Also, if you do change content, how can you not make a more cumbersome experience for your visitors? It’s all about communication Content is at the core of what we do, but if we consider context we need to understand the impact on that. The effect could be as subtle as an altered hierarchy, involve swapping out panels of content, or in extreme instances perhaps all of your content might change. In some ways, this extends the notion of adaptive content that Karen McGrane has been talking about, to how we write and store the content we create. Thinking about the the impact of context may require us to re-evaluate our site structure, too. Whatever we decide, we have to be clear what will happen and manage the expectations of our users. The bottom line What I’m proposing isn’t that we go crazy and end up with a confused, disjointed set of experiences across the web. What I hope is that starting right from the beginning of a project, we think about what context is and could be, and see what relevance it might have to what we’re trying to communicate. This strategic process leads us to think about design. We are slowly adapting to what it means to be flexible through responsive and adaptive processes. What does thinking about contextual states mean to us (or designing for state in general)? Does this highlight again how difficult it’ll be for our tools to keep up with our processes and output? In terms of code, the vast majority of this data comes from the client-side through JavaScript. While we can progressively enhance, this could lead to a lot of code bloat through feature or capability detection, and potentially a lot of conditional loading of scripts. It’s a real shame we don’t get much we can rely on from the server-side – we know how unreliable user agents are! We need to understand why we’d do this. Are we trying to communicate well and be useful, or doing it to show off? Underneath it all, what do we base our decisions on? Do we have actual insight or are we proceeding from our assumptions and the bias of our own experiences? Scott Jenson summed it up best for me: (to paraphrase) the pain we put people through has to be greatly outweighed by the value we offer. I see that this could be another potential step in our evolution on the web; continuing this exploration of the flexibility the web allows us. It’s amazing we can do such incredible things from what is essentially a set of disparate, linked documents. 2012 Dan Donald dandonald 2012-12-09T00:00:00+00:00 https://24ways.org/2012/should-we-be-reactive/ design
127 Showing Good Form Earlier this year, I forget exactly when (it’s been a good year), I was building a client site that needed widgets which look like this (designed, incidentally, by my erstwhile writing partner, Cameron Adams): Building this was a challenge not just in CSS, but in choosing the proper markup – how should such a widget be constructed? Mmm … markup It seemed to me there were two key issues to deal with: The function of the interface is to input information, so semantically this is a form, therefore we have to find a way of building it using form elements: fieldset, legend, label and input We can’t use a table for layout, even though that would clearly be the easiest solution! Abusing tables for layout is never good – physical layout is not what table semantics mean. But even if this data can be described as a table, we shouldn’t mix forms markup with non-forms markup, because of the behavioral impact this can have on a screen reader: To take a prominent example, the screen reader JAWS has a mode specifically for interacting with forms (cunningly known as “forms mode”). When running in this mode its output only includes relevant elements – legends, labels and form controls themselves. Any other kind of markup – like text in a previous table cell, a paragraph or list in between – is simply ignored. The user in this situation would have to switch continually in and out of forms mode to hear all the content. (For more about this issue and some test examples, there’s a thread at accessify forum which wanders in that direction.) One further issue for screen reader users is implied by the design: the input fields are associated together in rows and columns, and a sighted user can visually scan across and down to make those associations; but a blind user can’t do that. For such a user the row and column header data will need to be there at every axis; in other words, the layout should be more like this: And constructed with appropriate semantic markup to convey those relationships. By this point the selection of elements seems pretty clear: each row is a fieldset, the row header is a legend, and each column header is a label, associated with an input. Here’s what that form looks like with no CSS: And here’s some markup for the first row (with most of the attributes removed just to keep this example succinct): <fieldset> <legend> <span>Match points</span> </legend> <label> <span>Win</span> <input value="3" /> </label> <label> <span>Draw</span> <input value="1" /> </label> <label> <span>Lose</span> <input value="0" /> </label> <label> <span>Played</span> <input value="0" /> </label> </fieldset> The span inside each legend is because legend elements are highly resistant to styling! Indeed they’re one of the most stubborn elements in the browsers’ vocabulary. Oh man … how I wrestled with the buggers … until this obvious alternative occurred to me! So the legend element itself is just a container, while all the styling is on the inner span. Oh yeah, there was some CSS too I’m not gonna dwell too much on the CSS it took to make this work – this is a short article, and it’s all there in the demo [demo page, style sheet] But I do want to touch on the most interesting bit – where we get from a layout with headers on every row, to one where only the top row has headers – or at least, so it appears to graphical browsers. For screen readers, as we noted, we need those headers on every row, so we should employ some cunning CSS to partly negate their visual presence, without removing them from the output. The core styling for each label span is like this: label span { display:block; padding:5px; line-height:1em; background:#423221; color:#fff; font-weight:bold; } But in the rows below the header they have these additional rules: fieldset.body label span { padding:0 5px; line-height:0; position:relative; top:-10000em; } The rendered width of the element is preserved, ensuring that the surrounding label is still the same width as the one in the header row above, and hence a unified column width is preserved all the way down. But the element effectively has no height, and so it’s effectively invisible. The styling is done this way, rather than just setting the height to zero and using overflow:hidden, because to do that would expose an unrelated quirk with another popular screen reader! (It would hide the output from Window Eyes, as shown in this test example at access matters.) The finished widget It’s an intricate beast allright! But after all that we do indeed get the widget we want: Demo page Style sheet It’s not perfect, most notably because the legends have to have a fixed width; this can be in em to allow for text scaling, but it still doesn’t allow the content to break into multiple lines. It also doesn’t look quite right in Safari; and some CSS hacking was needed to make it look right in IE6 and IE7. Still it worked well enough for the purpose, and satisfied the client completely. And most of all it re-assured me in my faith – that there’s never any need to abuse tables for layout. (Unless of course you think this content is a table anyway, but that’s another story!) 2006 James Edwards jamesedwards 2006-12-11T00:00:00+00:00 https://24ways.org/2006/showing-good-form/ ux
104 Sitewide Search On A Shoe String One of the questions I got a lot when I was building web sites for smaller businesses was if I could create a search engine for their site. Visitors should be able to search only this site and find things without the maintainer having to put “related articles” or “featured content” links on every page by hand. Back when this was all fields this wasn’t easy as you either had to write your own scraping tool, use ht://dig or a paid service from providers like Yahoo, Altavista or later on Google. In the former case you had to swallow the bitter pill of computing and indexing all your content and storing it in a database for quick access and in the latter it hurt your wallet. Times have moved on and nowadays you can have the same functionality for free using Yahoo’s “Build your own search service” – BOSS. The cool thing about BOSS is that it allows for a massive amount of hits a day and you can mash up the returned data in any format you want. Another good feature of it is that it comes with JSON-P as an output format which makes it possible to use it without any server-side component! Starting with a working HTML form In order to add a search to your site, you start with a simple HTML form which you can use without JavaScript. Most search engines will allow you to filter results by domain. In this case we will search “bbc.co.uk”. If you use Yahoo as your standard search, this could be: <form id="customsearch" action="http://search.yahoo.com/search"> <div> <label for="p">Search this site:</label> <input type="text" name="p" id="term"> <input type="hidden" name="vs" id="site" value="bbc.co.uk"> <input type="submit" value="go"> </div> </form> The Google equivalent is: <form id="customsearch" action="http://www.google.co.uk/search"> <div> <label for="p">Search this site:</label> <input type="text" name="as_q" id="term"> <input type="hidden" name="as_sitesearch" id="site" value="bbc.co.uk"> <input type="submit" value="go"> </div> </form> In any case make sure to use the ID term for the search term and site for the site, as this is what we are going to use for the script. To make things easier, also have an ID called customsearch on the form. To use BOSS, you should get your own developer API for BOSS and replace the one in the demo code. There is click tracking on the search results to see how successful your app is, so you should make it your own. Adding the BOSS magic BOSS is a REST API, meaning you can use it in any HTTP request or in a browser by simply adding the right parameters to a URL. Say for example you want to search “bbc.co.uk” for “christmas” all you need to do is open the following URL: http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&format=xml&appid=YOUR-APPLICATION-ID Try it out and click it to see the results in XML. We don’t want XML though, which is why we get rid of the format=xml parameter which gives us the same information in JSON: http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&appid=YOUR-APPLICATION-ID JSON makes most sense when you can send the output to a function and immediately use it. For this to happen all you need is to add a callback parameter and the JSON will be wrapped in a function call. Say for example we want to call SITESEARCH.found() when the data was retrieved we can do it this way: http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&callback=SITESEARCH.found&appid=YOUR-APPLICATION-ID You can use this immediately in a script node if you want to. The following code would display the total amount of search results for the term christmas on bbc.co.uk as an alert: <script type="text/javascript"> var SITESEARCH = {}; SITESEARCH.found = function(o){ alert(o.ysearchresponse.totalhits); } </script> <script type="text/javascript" src="http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&callback=SITESEARCH.found&appid=Kzv_lcHV34HIybw0GjVkQNnw4AEXeyJ9Rb1gCZSGxSRNrcif_HdMT9qTE1y9LdI-"> </script> However, for our example, we need to be a bit more clever with this. Enhancing the search form Here’s the script that enhances a search form to show results below it. SITESEARCH = function(){ var config = { IDs:{ searchForm:'customsearch', term:'term', site:'site' }, loading:'Loading results...', noresults:'No results found.', appID:'YOUR-APP-ID', results:20 }; var form; var out; function init(){ if(config.appID === 'YOUR-APP-ID'){ alert('Please get a real application ID!'); } else { form = document.getElementById(config.IDs.searchForm); if(form){ form.onsubmit = function(){ var site = document.getElementById(config.IDs.site).value; var term = document.getElementById(config.IDs.term).value; if(typeof site === 'string' && typeof term === 'string'){ if(typeof out !== 'undefined'){ out.parentNode.removeChild(out); } out = document.createElement('p'); out.appendChild(document.createTextNode(config.loading)); form.appendChild(out); var APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' + term + '?callback=SITESEARCH.found&sites=' + site + '&count=' + config.results + '&appid=' + config.appID; var s = document.createElement('script'); s.setAttribute('src',APIurl); s.setAttribute('type','text/javascript'); document.getElementsByTagName('head')[0].appendChild(s); return false; } }; } } }; function found(o){ var list = document.createElement('ul'); var results = o.ysearchresponse.resultset_web; if(results){ var item,link,description; for(var i=0,j=results.length;i<j;i++){ item = document.createElement('li'); link = document.createElement('a'); link.setAttribute('href',results[i].clickurl); link.innerHTML = results[i].title; item.appendChild(link); description = document.createElement('p'); description.innerHTML = results[i]['abstract']; item.appendChild(description); list.appendChild(item); } } else { list = document.createElement('p'); list.appendChild(document.createTextNode(config.noresults)); } form.replaceChild(list,out); out = list; }; return{ config:config, init:init, found:found }; }(); Oooohhhh scary code! Let’s go through this one bit at a time: We start by creating a module called SITESEARCH and give it an configuration object: SITESEARCH = function(){ var config = { IDs:{ searchForm:'customsearch', term:'term', site:'site' }, loading:'Loading results...', appID:'YOUR-APP-ID', results:20 } Configuration objects are a great idea to make your code easy to change and also to override. In this case you can define different IDs than the one agreed upon earlier, define a message to show when the results are loading, when there aren’t any results, the application ID and the number of results that should be displayed. Note: you need to replace “YOUR-APP-ID” with the real ID you retrieved from BOSS, otherwise the script will complain! var form; var out; function init(){ if(config.appID === 'YOUR-APP-ID'){ alert('Please get a real application ID!'); } else { We define form and out as variables to make sure that all the methods in the module have access to them. We then check if there was a real application ID defined. If there wasn’t, the script complains and that’s that. form = document.getElementById(config.IDs.searchForm); if(form){ form.onsubmit = function(){ var site = document.getElementById(config.IDs.site).value; var term = document.getElementById(config.IDs.term).value; if(typeof site === 'string' && typeof term === 'string'){ If the application ID was a winner, we check if the form with the provided ID exists and apply an onsubmit event handler. The first thing we get is the values of the site we want to search in and the term that was entered and check that those are strings. if(typeof out !== 'undefined'){ out.parentNode.removeChild(out); } out = document.createElement('p'); out.appendChild(document.createTextNode(config.loading)); form.appendChild(out); If both are strings we check of out is undefined. We will create a loading message and subsequently the list of search results later on and store them in this variable. So if out is defined, it’ll be an old version of a search (as users will re-submit the form over and over again) and we need to remove that old version. We then create a paragraph with the loading message and append it to the form. var APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' + term + '?callback=SITESEARCH.found&sites=' + site + '&count=' + config.results + '&appid=' + config.appID; var s = document.createElement('script'); s.setAttribute('src',APIurl); s.setAttribute('type','text/javascript'); document.getElementsByTagName('head')[0].appendChild(s); return false; } }; } } }; Now it is time to call the BOSS API by assembling a correct REST URL, create a script node and apply it to the head of the document. We return false to ensure the form does not get submitted as we want to stay on the page. Notice that we are using SITESEARCH.found as the callback method, which means that we need to define this one to deal with the data returned by the API. function found(o){ var list = document.createElement('ul'); var results = o.ysearchresponse.resultset_web; if(results){ var item,link,description; We create a new list and then get the resultset_web array from the data returned from the API. If there aren’t any results returned, this array will not exist which is why we need to check for it. Once we done that we can define three variables to repeatedly store the item title we want to display, the link to point to and the description of the link. for(var i=0,j=results.length;i<j;i++){ item = document.createElement('li'); link = document.createElement('a'); link.setAttribute('href',results[i].clickurl); link.innerHTML = results[i].title; item.appendChild(link); description = document.createElement('p'); description.innerHTML = results[i]['abstract']; item.appendChild(description); list.appendChild(item); } We then loop over the results array and assemble a list of results with the titles in links and paragraphs with the abstract of the site. Notice the bracket notation for abstract as abstract is a reserved word in JavaScript2 :). } else { list = document.createElement('p'); list.appendChild(document.createTextNode(config.noresults)); } form.replaceChild(list,out); out = list; }; If there aren’t any results, we define a paragraph with the no results message as list. In any case we replace the old out (the loading message) with the list and re-define out as the list. return{ config:config, init:init, found:found }; }(); All that is left to do is return the properties and methods we want to make public. In this case found needs to be public as it is accessed by the API return. We return init to make it accessible and config to allow implementers to override any of the properties. Using the script In order to use this script, all you need to do is to add it after the form in the document, override the API key with your own and call init(): <form id="customsearch" action="http://search.yahoo.com/search"> <div> <label for="p">Search this site:</label> <input type="text" name="p" id="term"> <input type="hidden" name="vs" id="site" value="bbc.co.uk"> <input type="submit" value="go"> </div> </form> <script type="text/javascript" src="boss-site-search.js"></script> <script type="text/javascript"> SITESEARCH.config.appID = 'copy-the-id-you-know-to-get-where'; SITESEARCH.init(); </script> Where to go from here This is just a very simple example of what you can do with BOSS. You can define languages and regions, retrieve and display images and news and mix the results with other data sources before displaying them. One very cool feature is that by adding a view=keyterms parameter to the URL you can get the keywords of each of the results to drill deeper into the search. An example for this written in PHP is available on the YDN blog. For JavaScript solutions there is a handy wrapper called yboss available to help you go nuts. 2008 Christian Heilmann chrisheilmann 2008-12-04T00:00:00+00:00 https://24ways.org/2008/sitewide-search-on-a-shoestring/ code
301 Stretching Time Time is valuable. It’s a precious commodity that, if we’re not too careful, can slip effortlessly through our fingers. When we think about the resources at our disposal we’re often guilty of forgetting the most valuable resource we have to hand: time. We are all given an allocation of time from the time bank. 86,400 seconds a day to be precise, not a second more, not a second less. It doesn’t matter if we’re rich or we’re poor, no one can buy more time (and no one can save it). We are all, in this regard, equals. We all have the same opportunity to spend our time and use it to maximum effect. As such, we need to use our time wisely. I believe we can ‘stretch’ time, ensuring we make the most of every second and maximising the opportunities that time affords us. Through a combination of ‘Structured Procrastination’ and ‘Focused Finishing’ we can open our eyes to all of the opportunities in the world around us, whilst ensuring that we deliver our best work precisely when it’s required. A win win, I’m sure you’ll agree. Structured Procrastination I’m a terrible procrastinator. I used to think that was a curse – “Why didn’t I just get started earlier?” – over time, however, I’ve started to see procrastination as a valuable tool if it is used in a structured manner. Don Norman refers to procrastination as ‘late binding’ (a term I’ve happily hijacked). As he argues, in Why Procrastination Is Good, late binding (delay, or procrastination) offers many benefits: Delaying decisions until the time for action is beneficial… it provides the maximum amount of time to think, plan, and determine alternatives. We live in a world that is constantly changing and evolving, as such the best time to execute is often ‘just in time’. By delaying decisions until the last possible moment we can arrive at solutions that address the current reality more effectively, resulting in better outcomes. Procrastination isn’t just useful from a project management perspective, however. It can also be useful for allowing your mind the space to wander, make new discoveries and find creative connections. By embracing structured procrastination we can ‘prime the brain’. As James Webb Young argues, in A Technique for Producing Ideas, all ideas are made of other ideas and the more we fill our minds with other stimuli, the greater the number of creative opportunities we can uncover and bring to life. By late binding, and availing of a lack of time pressure, you allow the mind space to breathe, enabling you to uncover elements that are important to the problem you’re working on and, perhaps, discover other elements that will serve you well in future tasks. When setting forth upon the process of writing this article I consciously set aside time to explore. I allowed myself the opportunity to read, taking in new material, safe in the knowledge that what I discovered – if not useful for this article – would serve me well in the future. Ron Burgundy summarises this neatly: Procrastinator? No. I just wait until the last second to do my work because I will be older, therefore wiser. An ‘older, therefore wiser’ mind is a good thing. We’re incredibly fortunate to live in a world where we have a wealth of information at our fingertips. Don’t waste the opportunity to learn, rather embrace that opportunity. Make the most of every second to fill your mind with new material, the rewards will be ample. Deadlines are deadlines, however, and deadlines offer us the opportunity to focus our minds, bringing together the pieces of the puzzle we found during our structured procrastination. Like everyone I’ll hear a tiny, but insistent voice in my head that starts to rise when the deadline is approaching. The older you get, the closer to the deadline that voice starts to chirp up. At this point we need to focus. Focused Finishing We live in an age of constant distraction. Smartphones are both a blessing and a curse, they keep us connected, but if we’re not careful the constant connection they provide can interrupt our flow. When a deadline is accelerating towards us it’s important to set aside the distractions and carve out a space where we can work in a clear and focused manner. When it’s time to finish, it’s important to avoid context switching and focus. All those micro-interactions throughout the day – triaging your emails, checking social media and browsing the web – can get in the way of you hitting your deadline. At this point, they’re distractions. Chunking tasks and managing when they’re scheduled can improve your productivity by a surprising order of magnitude. At this point it’s important to remove distractions which result in ‘attention residue’, where your mind is unable to focus on the current task, due to the mental residue of other, unrelated tasks. By focusing on a single task in a focused manner, it’s possible to minimise the negative impact of attention residue, allowing you to maximise your performance on the task at hand. Cal Newport explores this in his excellent book, Deep Work, which I would highly recommend reading. As he puts it: Efforts to deepen your focus will struggle if you don’t simultaneously wean your mind from a dependence on distraction. To help you focus on finishing it’s helpful to set up a work-focused environment that is purposefully free from distractions. There’s a time and a place for structured procrastination, but – equally – there’s a time and a place for focused finishing. The French term ‘mise en place’ is drawn from the world of fine cuisine – I discovered it when I was procrastinating – and it’s applicable in this context. The term translates as ‘putting in place’ or ‘everything in its place’ and it refers to the process of getting the workplace ready before cooking. Just like a professional chef organises their utensils and arranges their ingredients, so too can you. Thanks to the magic of multiple users on computers, it’s possible to create a separate user on your computer – without access to email and other social tools – so that you can switch to that account when you need to focus and hit the deadline. Another, less technical way of achieving the same result – depending, of course, upon your line of work – is to close your computer and find some non-digital, unconnected space to work in. The goal is to carve out time to focus so you can finish. As Newport states: If you don’t produce, you won’t thrive – no matter how skilled or talented you are. Procrastination is fine, but only if it’s accompanied by finishing. Create the space to finish and you’ll enjoy the best of both worlds. In closing… There is a time and a place for everything: there is a time to procrastinate, and a time to focus. To truly reap the rewards of time, the mind needs both. By combining the processes of ‘Structured Procrastination’ and ‘Focused Finishing’ we can make the most of our 86,400 seconds a day, ensuring we are constantly primed to make new discoveries, but just as importantly, ensuring we hit the all-important deadlines. Make the most of your time, you only get so much. Use every second productively and you’ll be thankful that you did. Don’t waste your time, once it’s gone, it’s gone… and you can never get it back. 2016 Christopher Murphy christophermurphy 2016-12-21T00:00:00+00:00 https://24ways.org/2016/stretching-time/ process
284 Subliminal User Experience The term ‘user experience’ 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. Good 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’s about omitting clutter to make way for the necessary, and using the most fundamental of design tools to influence a user’s 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. There 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. The 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. We’ll cover three elements that should get you thinking in the right mindset: progress activity and post-active states pseudo-class preloading buttons and their (mis)behaviour Progress activity and the post-active state We’ve long established that we can’t control the devices our products are viewed on, which browser they’ll 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’t part of the interface — it’s merely a container. A simple, visual recognition of your users’ activity may be all it takes to make or break the product. Let’s begin with a commonly overlooked case: progress activity. A 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? From this point on, your user is in limbo. The link has fallen back to either its regular or :visited state. You’ve effectively abandoned them and are relying entirely on the browser they’re using to communicate that something is happening. This poses quite a few problems: The user may lose focus of what they were doing. There is little consistency between progress indication in browsers. The user may not even notice that their action has been acknowledged. How many times have one or more of these events happened to you due to a lack of communication from the interface? Think about the differences between Safari and Chrome in this area — two browsers that, when compared to each other, are relatively similar in nature, though this basic feature differs in execution. Like 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. Consider the basic loading indicator. It’s nothing new — in fact, some would argue it’s quite a cliché. 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’s 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’s valuable attention have significantly increased. Demo: Progress activity and the post-active state This 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’s 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’re more likely to exit from. Pseudo-class preloading Another 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’re 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’s preload the elements we know we’ll need. A 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. element { background: url(path/to/image.jpg) -9999em -9999em no-repeat; } element .tooltip { display: none; } element:hover .tooltip { display: block; background: url(path/to/image.jpg) 0 0; } Background 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 — albeit tedious — method for achieving the same goal, so if you’re using a sprite, preloading in this way may not be necessary The differences between preloading and not can only be visualized properly with an actual demonstration. Demo: Preloading revealed content Buttons and their (mis)behaviour Almost all of the time, a button serves just one purpose: to be clicked (or tapped). When a button’s 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. It 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. It’s rare that a user would ever want to select and use the text on a button, so let’s cleanly disable it: element { -moz-user-select: -moz-none; -webkit-user-select: none; user-select: none; } If 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: element { -moz-user-drag: -moz-none; -webkit-user-drag: none; user-drag: none; } Demo: A more usable button Disabling global features like this should be done with utmost caution as it’s very easy to cross the line between enhancement and friction. Cases where this is acceptable are very rare, but it’s a good trick to keep in mind nevertheless. Both Apple’s iCloud and Metalab’s Flow applications use these tools appropriately and to great extent. You 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’s job, not that of our users. We can (almost) ensure it does work for them by accommodating for errors like this in most cases. Final thoughts Designing 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. The samples you’ve 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’s not the technology, or the way it’s done that’s important — it’s the logic and the concept of designing everything. 2011 Chris Sealey chrissealey 2011-12-03T00:00:00+00:00 https://24ways.org/2011/subliminal-user-experience/ ux
261 Surviving—and Thriving—as a Remote Worker Remote work is hot right now. Many people even say that remote work is the future. Why should a company limit itself to hiring from a specific geographic location when there’s an entire world of talent out there? I’ve been working remotely, full-time, for five and a half years. I’ve reached the point where I can’t even fathom working in an office. The idea of having to wake up at a specific time and commute into an office, work for eight hours, and then commute home, feels weirdly anachronistic. I’ve grown attached to my current level of freedom and flexibility. However, it took me a lot of trial and error to reach success as a remote worker — and sometimes even now, I slip up. Working remotely requires a great amount of discipline, independence, and communication. It can feel isolating, especially if you lean towards the more extroverted side of the social spectrum. Remote working isn’t for everyone, but most people, with enough effort, can make it work — or even thrive. Here’s what I’ve learned in over five years of working remotely. Experiment with your environment As a remote worker, you have almost unprecedented control of your environment. You can often control the specific desk and chair you use, how you accessorize your home office space — whether that’s a dedicated office, a corner of your bedroom, or your kitchen table. (Ideally, not your couch… but I’ve been there.) Hate fluorescent lights? Change your lightbulbs. Cover your work area in potted plants. Put up blackout curtains and work in the dark like a vampire. Whatever makes you feel most comfortable and productive, and doesn’t completely destroy your eyesight. Working remotely doesn’t always mean working from home. If you don’t have a specific reason you need to work from home (like specialized equipment), try working from other environments (which is especially helpful it you have roommates, or children). Cafes are the quintessential remote worker hotspot, but don’t just limit yourself to your favorite local haunt. More cities worldwide are embracing co-working spaces, where you can rent either a roaming spot or a dedicated desk. If you’re a social person, this is a great way to build community in your work environment. Most have phone rooms, so you can still take calls. Co-working spaces can be expensive, and not everyone has either the extra income, or work-provided stipend, to work from one. Local libraries are also a great work location. They’re quiet, usually have free wi-fi, and you have the added bonus of being able to check out books after work instead of, ahem, spending too much money on Kindle books. (I know most libraries let you check out ebooks, but reader, I am impulsive and impatient person. When I want a book now, I mean now.) Just be polite — make sure your headphones don’t leak, and don’t work from a library if you have a day full of calls. Remember, too, that you don’t have to stay in the same spot all day. It’s okay to go out for lunch and then resume work from a different location. If you find yourself getting restless, take a walk. Wash some dishes while you mull through a problem. Don’t force yourself to sit at your desk for eight hours if that doesn’t work for you. Set boundaries If you’re a workaholic, working remotely can be a challenge. It’s incredibly easy to just… work. All the time. My work computer is almost always with me. If I remember at 11pm that I wanted to do something, there’s nothing but my own willpower keeping me from opening up my laptop and working until 2am. Some people are naturally disciplined. Some have discipline instilled in them as children. And then some, like me, are undisciplined disasters that realize as adults that wow, I guess it’s time to figure this out, eh? Learning how to set boundaries is one of the most important lessons I’ve learned working remotely. (And honestly, it’s something I still struggle with). For a long time, I had a bad habit of waking up, checking my phone for new Slack messages, seeing something I need to react to, and then rolling over to my couch with my computer. Suddenly, it’s noon, I’m unwashed, unfed, starting to get a headache, and wondering why suddenly I hate all of my coworkers. Even when I finally tear myself from my computer to shower, get dressed, and eat, the damage is done. The rest of my day is pretty much shot. I recently had a conversation with a coworker, in which she remarked that she used to fill her empty time with work. Wake up? Scroll through Slack and email before getting out of bed. Waiting in line for lunch? Check work. Hanging out on her couch in the evening? You get the drift. She was only able to break the habit after taking a three month sabbatical, where she had no contact with work the entire time. I too had just returned from my own sabbatical. I took her advice, and no longer have work Slack on my phone, unless I need it for an event. After the event, I delete it. I also find it too easy to fill empty time with work. Now, I might wake up and procrastinate by scrolling through other apps, but I can’t get sucked into work before I’m even dressed. I’ve gotten pretty good at forbidding myself from working until I’m ready, but building any new habit requires intentionality. Something else I experimented with for a while was creating a separate account on my computer for social tasks, so if I wanted to hang out on my computer in the evening, I wouldn’t get distracted by work. It worked exceptionally well. The only problems I encountered were technical, like app licensing and some of my work proxy configurations. I’ve heard other coworkers have figured out ways to work through these technical issues, so I’m hoping to give it another try soon. You might noticed that a lot of these ideas are just hacks for making myself not work outside of my designated work times. It’s true! If you’re a more disciplined person, you might not need any of these coping mechanisms. If you’re struggling, finding ways to subvert your own bad habits can be the difference between thriving or burning out. Create intentional transition time I know it’s a stereotype that people who work from home stay in their pajamas all day, but… sometimes, it’s very easy to do. I’ve found that in order to reach peak focus, I need to create intentional transition time. The most obvious step is changing into different clothing than I woke up in. Ideally, this means getting dressed in real human clothing. I might decide that it’s cold and gross out and I want to work in joggers and a hoody all day, but first, I need to change out of my pajamas, put on a bra, and then succumb to the lure of comfort. I’ve found it helpful to take similar steps at the end of my day. If I’ve spent the day working from home, I try to end my day with something that occupies my body, while letting my mind unwind. Often, this is doing some light cleaning or dinner prep. If I try to go straight into another mentally heavy task without allowing myself this transition time, I find it hard to context switch. This is another reason working from outside your home is advantageous. Commutes, even if it’s a ten minute walk down the road, are great transition time. Lunch is a great transition time. You can decompress between tasks by going out for lunch, or cooking and eating lunch in your kitchen — not next to your computer. Embrace async If you’re used to working in an office, you’ve probably gotten pretty used to being able to pop over to a colleague’s desk if you need to ask a question. They’re pretty much forced to engage with you at that point. When you’re working remotely, your coworkers might not be in the same timezone as you. They might take an hour to finish up a task before responding to you, or you might not get an answer for your entire day because dangit Gary’s in Australia and it’s 3am there right now. For many remote workers, that’s part of the package. When you’re not co-located, you have to build up some patience and tolerance around waiting. You need to intentionally plan extra time into your schedule for waiting on answers. Asynchronous communication is great. Not everyone can be present for every meeting or office conversation — and the same goes for working remotely. However, when you’re remote, you can read through your intranet messages later or scroll back a couple hours in Slack. My company has a bunch of internal blogs (“p2s”) where we record major decisions and hold asynchronous conversations. I feel like even if I missed a meeting, or something big happened while I was asleep, I can catch up later. We have a phrase — “p2 or it didn’t happen.” Working remotely has made me a better communicator largely because I’ve gotten into the habit of making written updates. I’ve also trained myself to wait before responding, which allows me to distance myself from what could potentially be an emotional reaction. (On the internet, no one can see you making that face.) Having the added space that comes from not being in the same physical location with somebody else creates an opportunity to rein myself in and take the time to craft an appropriate response, without having the pressure of needing to reply right meow. Lean into it! (That said, if you’re stuck, sometimes the best course of action is to hop on a video call with someone and hash out the details. Use the tools most appropriate for the problem. They invented Zoom for a reason.) Seek out social opportunities Even introverts can feel lonely or isolated. When you work remotely, there isn’t a built-in community you’re surrounded by every day. You have to intentionally seek out social opportunities that an office would normally provide. I have a couple private Slack channels where I can joke around with work friends. Having that kind of safe space to socialize helps me feel less alone. (And, if the channels get too noisy, I can mute them for a couple hours.) Every now and then, I’ll also hop on a video call with some work friends and just hang out for a little while. It feels great to actually see someone laugh. If you work from a co-working space, that space likely has events. My co-working space hosts social hours, holiday parties, and sometimes even lunch-and-learns. These events are great opportunities for making new friends and forging professional connections outside of work. If you don’t have access to a co-working space, your town or city likely has meetups. Create a Meetup.com account and search for something that piques your interest. If you’ve been stuck inside your house for days, heads-down on a hard deadline, celebrate by getting out of the house. Get coffee or drinks with friends. See a show. Go to a religious service. Take a cooking class. Try yoga. Find excuses to be around someone other than your cats. When you can’t fall back on your work to provide community, you need to build your own. These are tips that I’ve found help me, but not everyone works the same way. Remember that it’s okay to experiment — just because you’ve worked one way, doesn’t mean that’s the best way for you. Check in with yourself every now and then. Are you happy with your work environment? Are you feeling lonely, down, or exhausted? Try switching up your routine for a couple weeks and jot down how you feel at the end of each day. Look for patterns. You deserve to have a comfortable and productive work environment! Hope to see you all online soon 🙌 2018 Mel Choyce melchoyce 2018-12-09T00:00:00+00:00 https://24ways.org/2018/thriving-as-a-remote-worker/ process
328 Swooshy Curly Quotes Without Images The problem Take a quote and render it within blockquote tags, applying big, funky and stylish curly quotes both at the beginning and the end without using any images – at all. The traditional way Feint background images under the text, or an image in the markup housed in a little float. Often designers only use the opening curly quote as it’s just too difficult to float a closing one. Why is the traditional way bad? Well, for a start there are no actual curly quotes in the text (unless you’re doing some nifty image replacement). Thus with CSS disabled you’ll only have default blockquote styling to fall back on. Secondly, images don’t resize, so scaling text will have no affect on your graphic curlies. The solution Use really big text. Then it can be resized by the browser, resized using CSS, and even be restyled with a new font style if you fancy it. It’ll also make sense when CSS is unavailable. The problem Creating “Drop Caps” with CSS has been around for a while (Big Dan Cederholm discusses a neat solution in that first book of his), but drop caps are normal characters – the A to Z or 1 to 10 – and these can all be pulled into a set space and do not serve up a ton of whitespace, unlike punctuation characters. Curly quotes aren’t like traditional characters. Like full stops, commas and hashes they float within the character space and leave lots of dead white space, making it bloody difficult to manipulate them with CSS. Styles generally fit around text, so cutting into that character is tricky indeed. Also, all that extra white space is going to push into the quote text and make it look pretty uneven. This grab highlights the actual character space: See how this is emphasized when we add a normal alphabetical character within the span. This is what we’re dealing with here: Then, there’s size. Call in a curly quote at less than 300% font-size and it ain’t gonna look very big. The white space it creates will be big enough, but the curlies will be way too small. We need more like 700% (as in this example) to make an impression, but that sure makes for a big character space. Prepare the curlies Firstly, remove the opening “ from the quote. Replace it with the opening curly quote character entity “. Then replace the closing “ with the entity reference for that, which is ”. Now at least the curlies will look nice and swooshy. Add the hooks Two reasons why we aren’t using :first-letter pseudo class to manipulate the curlies. Firstly, only CSS2-friendly browsers would get what we’re doing, and secondly we need to affect the last “letter” of our text also – the closing curly quote. So, add a span around the opening curly, and a second span around the closing curly, giving complete control of the characters: <blockquote><span class="bqstart">“</span>Speech marks. Curly quotes. That annoying thing cool people do with their fingers to emphasize a buzzword, shortly before you hit them.<span class="bqend">”</span></blockquote> So far nothing will look any different, aside form the curlies looking a bit nicer. I know we’ve just added extra markup, but the benefits as far as accessibility are concerned are good enough for me, and of course there are no images to download. The CSS OK, easy stuff first. Our first rule .bqstart floats the span left, changes the color, and whacks the font-size up to an exuberant 700%. Our second rule .bqend does the same tricks aside from floating the curly to the right. .bqstart { float: left; font-size: 700%; color: #FF0000; } .bqend { float: right; font-size: 700%; color: #FF0000; } That gives us this, which is rubbish. I’ve highlighted the actual span area with outlines: Note that the curlies don’t even fit inside the span! At this stage on IE 6 PC you won’t even see the quotes, as it only places focus on what it thinks is in the div. Also, the quote text is getting all spangled. Fiddle with margin and padding Think of that span outline box as a window, and that you need to position the curlies within that window in order to see them. By adding some small adjustments to the margin and padding it’s possible to position the curlies exactly where you want them, and remove the excess white space by defining a height: .bqstart { float: left; height: 45px; margin-top: -20px; padding-top: 45px; margin-bottom: -50px; font-size: 700%; color: #FF0000; } .bqend { float: right; height: 25px; margin-top: 0px; padding-top: 45px; font-size: 700%; color: #FF0000; } I wanted the blocks of my curlies to align with the quote text, whereas you may want them to dig in or stick out more. Be aware however that my positioning works for IE PC and Mac, Firefox and Safari. Too much tweaking seems to break the magic in various browsers at various times. Now things are fitting beautifully: I must admit that the heights, margins and spacing don’t make a lot of sense if you analyze them. This was a real trial and error job. Get it working on Safari, and IE would fail. Sort IE, and Firefox would go weird. Finished The final thing looks ace, can be resized, looks cool without styles, and can be edited with CSS at any time. Here’s a real example (note that I’m specifying Lucida Grande and then Verdana for my curlies): “Speech marks. Curly quotes. That annoying thing cool people do with their fingers to emphasize a buzzword, shortly before you hit them.” Browsers happy As I said, too much tweaking of margins and padding can break the effect in some browsers. Even now, Firefox insists on dropping the closing curly by approximately 6 or 7 pixels, and if I adjust the padding for that, it’ll crush it into the text on Safari or IE. Weird. Still, as I close now it seems solid through resizing tests on Safari, Firefox, Camino, Opera and IE PC and Mac. Lovely. It’s probably not perfect, but together we can beat the evil typographic limitations of the web and walk together towards a brighter, more aligned world. Merry Christmas. 2005 Simon Collison simoncollison 2005-12-21T00:00:00+00:00 https://24ways.org/2005/swooshy-curly-quotes-without-images/ business
300 Taking Device Orientation for a Spin When The Police sang “Don’t Stand So Close To Me” they weren’t talking about using a smartphone to view a panoramic image on Facebook, but they could have been. For years, technology has driven relentlessly towards devices we can carry around in our pockets, and now that we’re there, we’re expected to take the thing out of our pocket and wave it around in front of our faces like a psychotic donkey in search of its own dangly carrot. But if you can’t beat them, join them. A brave new world A couple of years back all sorts of specs for new HTML5 APIs sprang up much to our collective glee. Emboldened, we ran a few tests and found they basically didn’t work in anything and went off disheartened into the corner for a bit of a sob. Turns out, while we were all busy boohooing, those browser boffins have actually being doing some work, and lo and behold, some of these APIs are even half usable. Mostly literally half usable—we’re still talking about browsers, after all. Now, of course they’re all a bit JavaScripty and are going to involve complex methods and maths and science and probably about a thousand dependancies from Github that will fall out of fashion while we’re still trying to locate the documentation, right? Well, no! So what if we actually wanted to use one of these APIs, say to impress our friends with our ability to make them wave their phones in front of their faces (because no one enjoys looking hapless more than the easily-technologically-impressed), how could we do something like that? Let’s find out. The Device Orientation API The phone-wavy API is more formally known as the DeviceOrientation Event Specification. It does a bunch of stuff that basically doesn’t work, but also gives us three values that represent orientation of a device (a phone, a tablet, probably not a desktop computer) around its x, y and z axes. You might think of it as pitch, roll and yaw if you like to spend your weekends wearing goggles and a leather hat. The main way we access these values is through an event listener, which can inform our code every time the value changes. Which is constantly, because you try and hold a phone still and then try and hold the Earth still too. The API calls those pitch, roll and yaw values alpha, beta and gamma. Chocks away: window.addEventListener('deviceorientation', function(e) { console.log(e.alpha); console.log(e.beta); console.log(e.gamma); }); If you look at this test page on your phone, you should be able to see the numbers change as you twirl the thing around your body like the dance partner you never had. Wrist strap recommended. One important note Like may of these newfangled APIs, Device Orientation is only available over HTTPS. We’re not allowed to have too much fun without protection, so make sure that you’re working on a secure line. I’ve found a quick and easy way to share my local dev environment over TLS with my devices is to use an ngrok tunnel. ngrok http -host-header=rewrite mylocaldevsite.dev:80 ngrok will then set up a tunnel to your dev site with both HTTP and HTTPS URL options. You, of course, want the HTTPS option. Right, where were we? Make something to look at It’s all well and good having a bunch of numbers, but they’re no use unless we do something with them. Something creative. Something to inspire the generations. Or we could just build that Facebook panoramic image viewer thing (because most of us are familiar with it and we’re not trying to be too clever here). Yeah, let’s just build one of those. Our basic framework is going to be similar to that used for an image carousel. We have a container, constrained in size, and CSS overflow property set to hidden. Into this we place our wide content and use positioning to move the content back and forth behind the ‘window’ so that the part we want to show is visible. Here it is mocked up with a slider to set the position. When you release the slider, the position updates. (This actually tests best on desktop with your window slightly narrowed.) The details of the slider aren’t important (we’re about to replace it with phone-wavy goodness) but the crucial part is that moving the slider results in a function call to position the image. This takes a percentage value (0-100) with 0 being far left and 100 being far right (or ‘alt-nazi’ or whatever). var position_image = function(percent) { var pos = (img_W / 100)*percent; img.style.transform = 'translate(-'+pos+'px)'; }; All this does is figure out what that percentage means in terms of the image width, and set the transform: translate(…); CSS property to move the image. (We use translate because it might be a bit faster to animate than left/right positioning.) Ok. We can now read the orientation values from our device, and we can programatically position the image. What we need to do is figure out how to convert those raw orientation values into a nice tidy percentage to pass to our function and we’re done. (We’re so not done.) The maths bit If we go back to our raw values test page and make-believe that we have a fascinating panoramic image of some far-off beach or historic monument to look at, you’ll note that the main value that is changing as we swing back and forth is the ‘alpha’ value. That’s the one we want to track. As our goal here is hey, these APIs are interesting and fun and not let’s build the world’s best panoramic image viewer, we’ll start by making a few assumptions and simplifications: When the image loads, we’ll centre the image and take the current nose-forward orientation reading as the middle. Moving left, we’ll track to the left of the image (lower percentage). Moving right, we’ll track to the right (higher percentage). If the user spins round, does cartwheels or loads the page then hops on a plane and switches earthly hemispheres, they’re on their own. Nose-forward When the page loads, the initial value of alpha gives us our nose-forward position. In Safari on iOS, this is normalised to always be 0, whereas most everywhere else it tends to be bound to pointy-uppy north. That doesn’t really matter to us, as we don’t know which direction the user might be facing in anyway — we just need to record that initial state and then use it to compare any new readings. var initial_position = null; window.addEventListener('deviceorientation', function(e) { if (initial_position === null) { initial_position = Math.floor(e.alpha); }; var current_position = initial_position - Math.floor(e.alpha); }); (I’m rounding down the values with Math.floor() to make debugging easier - we’ll take out the rounding later.) We get our initial position if it’s not yet been set, and then calculate the current position as a difference between the new value and the stored one. These values are weird One thing you need to know about these values, is that they range from 0 to 360 but then you also get weird left-of-zero values like -2 and whatever. And they wrap past 360 back to zero as you’d expect if you do a forward roll. What I’m interested in is working out my rotation. If 0 is my nose-forward position, I want a positive value as I turn right, and a negative value as I turn left. That puts the awkward 360-tipping point right behind the user where they can’t see it. var rotation = current_position; if (current_position > 180) rotation = current_position-360; Which way up? Since we’re talking about orientation, we need to remember that the values are going to be different if the device is held in portrait on landscape mode. See for yourself - wiggle it like a steering wheel and you get different values. That’s easy to account for when you know which way up the device is, but in true browser style, the API for that bit isn’t well supported. The best I can come up with is: var screen_portrait = false; if (window.innerWidth < window.innerHeight) { screen_portrait = true; } It works. Then we can use screen_portrait to branch our code: if (screen_portrait) { if (current_position > 180) rotation = current_position-360; } else { if (current_position < -180) rotation = 360+current_position; } Here’s the code in action so you can see the values for yourself. If you change screen orientation you’ll need to refresh the page (it’s a demo!). Limiting rotation Now, while the youth of today are rarely seen without a phone in their hands, it would still be unreasonable to ask them to spin through 360° to view a photo. Instead, we need to limit the range of movement to something like 60°-from-nose in either direction and normalise our values to pan the entire image across that 120° range. -60 would be full-left (0%) and 60 would be full-right (100%). If we set max_rotation = 60, that code ends up looking like this: if (rotation > max_rotation) rotation = max_rotation; if (rotation < (0-max_rotation)) rotation = 0-max_rotation; var percent = Math.floor(((rotation + max_rotation)/(max_rotation*2))*100); We should now be able to get a rotation from -60° to +60° expressed as a percentage. Try it for yourself. The big reveal All that’s left to do is pass that percentage to our image positioning function and would you believe it, it might actually work. position_image(percent); You can see the final result and take it for a spin. Literally. So what have we made here? Have we built some highly technical panoramic image viewer to aid surgeons during life-saving operations using only JavaScript and some slightly questionable mathematics? No, my friends, we have not. Far from it. What we have made is progress. We’ve taken a relatively newly available hardware API and a bit of simple JavaScript and paired it with existing CSS knowledge and made something that we didn’t have this morning. Something we probably didn’t even want this morning. Something that if you take a couple of steps back and squint a bit might be a prototype for something vaguely interesting. But more importantly, we’ve learned that our browsers are just a little bit more capable than we thought. The web platform is maturing rapidly. There are new, relatively unexplored APIs for doing all sorts of crazy thing that are often dismissed as the preserve of native apps. Like some sort of app marmalade. Poppycock. The web is an amazing, exciting place to create things. All it takes is some base knowledge of the fundamentals, a creative mind and a willingness to learn. We have those! So let’s create things. 2016 Drew McLellan drewmclellan 2016-12-24T00:00:00+00:00 https://24ways.org/2016/taking-device-orientation-for-a-spin/ code
267 Taming Complexity I’m going to step into my UX trousers for this one. I wouldn’t usually wear them in public, but it’s Christmas, so there’s nothing wrong with looking silly. Anyway, to business. Wherever I roam, I hear the familiar call for simplicity and the denouncement of complexity. I read often that the simpler something is, the more usable it will be. We understand that simple is hard to achieve, but we push for it nonetheless, convinced it will make what we build easier to use. Simple is better, right? Well, I’ll try to explore that. Much of what follows will not be revelatory to some but, like all good lessons, I think this serves as a welcome reminder that as we live in a complex world it’s OK to sometimes reflect that complexity in the products we build. Myths and legends Less is more, we’ve been told, ever since master of poetic verse Robert Browning used the phrase in 1855. Well, I’ve conducted some research, and it appears he knew nothing of web design. Neither did modernist architect Ludwig Mies van der Rohe, a later pedlar of this worthy yet contradictory notion. Broad is narrow. Tall is short. Eggs are chips. See: anyone can come up with this stuff. To paraphrase Einstein, simple doesn’t have to be simpler. In other words, simple doesn’t dictate that we remove the complexity. Complex doesn’t have to be confusing; it can be beautiful and elegant. On the web, complex can be necessary and powerful. A website that simplifies the lives of its users by offering them everything they need in one site or screen is powerful. For some, the greater the density of information, the more useful the site. In our decision-making process, principles such as Occam’s razor’s_razor (in a nutshell: simple is better than complex) are useful, but simple is for the user to determine through their initial impression and subsequent engagement. What appears simple to me or you might appear very complex to someone else, based on their own mental model or needs. We can aim to deliver simple, but they’ll be the judge. As a designer, developer, content alchemist, user experience discombobulator, or whatever you call yourself, you’re often wrestling with a wealth of material, a huge number of features, and numerous objectives. In many cases, much of that stuff is extraneous, and goes in the dustbin. However, it can be just as likely that there’s a truckload of suggested features and content because it all needs to be there. Don’t be afraid of that weight. In the right hands, less can indeed mean more, but it’s just as likely that less can very often lead to, well… less. Complexity is powerful Simple is the ability to offer a powerful experience without overwhelming the audience or inducing information anxiety. Giving them everything they need, without having them ferret off all over a site to get things done, is important. It’s useful to ask throughout a site’s lifespan, “does the user have everything they need?” It’s so easy to let our designer egos get in the way and chop stuff out, reduce down to only the things we want to see. That benefits us in the short term, but compromises the audience long-term. The trick is not to be afraid of complexity in itself, but to avoid creating the perception of complexity. Give a user a flight simulator and they’ll crash the plane or jump out. Give them everything they need and more, but make it feel simple, and you’re building a relationship, empowering people. This can be achieved carefully with what some call gradual engagement, and often the sensible thing might be to unleash complexity in carefully orchestrated phases, initially setting manageable levels of engagement and interaction, gradually increasing the inherent power of the product and fostering an empowered community. The design aesthetic Here’s a familiar scenario: the client or project lead gets overexcited and skips most of the important decision-making, instead barrelling straight into a bout of creative direction Tourette’s. Visually, the design needs to be minimal, white, crisp, full of white space, have big buttons, and quite likely be “clean”. Of course, we all like our websites to be clean as that’s more hygienic. But what do these words even mean, really? Early in a project they’re abstract distractions, unnecessary constraints. This premature narrowing forces us to think much more about throwing stuff out rather than acknowledging that what we’re building is complex, and many of the components perhaps necessary. Simple is not a formula. It cannot be achieved just by using a white background, by throwing things away, or by breathing a bellowsful of air in between every element and having it all float around in space. Simple is not a design treatment. Simple is hard. Simple requires deep investigation, a thorough understanding of every aspect of a project, in line with the needs and expectations of the audience. Recognizing this helps us empathize a little more with those most vocal of UX practitioners. They usually appreciate that our successes depend on a thorough understanding of the user’s mental models and expected outcomes. I personally still consider UX people to be web designers like the rest of us (mainly to wind them up), but they’re web designers that design every decision, and by putting the user experience at the heart of their process, they have a greater chance of finding simplicity in complexity. The visual design aesthetic — the façade — is only a part of that. Divide and conquer I’m currently working on an app that’s complex in architecture, and complex in ambition. We’ll be releasing in carefully orchestrated private phases, gradually introducing more complexity in line with the unavoidably complex nature of the objective, but my job is to design the whole, the complete system as it will be when it’s out of beta and beyond. I’ve noticed that I’m not throwing much out; most of it needs to be there. Therefore, my responsibility is to consider interesting and appropriate methods of navigation and bring everything together logically. I’m using things like smart defaults, graphical timelines and colour keys to make sense of the complexity, techniques that are sympathetic to the content. They act as familiar points of navigation and reference, yet are malleable enough to change subtly to remain relevant to the information they connect. It’s really OK to have a lot of stuff, so long as we make each component work smartly. It’s a divide and conquer approach. By finding simplicity and logic in each content bucket, I’ve made more sense of the whole, allowing me to create key layouts where most of the simplified buckets are collated and sometimes combined, providing everything the user needs and expects in the appropriate places. I’m also making sure I don’t reduce the app’s power. I need to reflect the scale of opportunity, and provide access to or knowledge of the more advanced tools and features for everyone: a window into what they can do and how they can help. I know it’s the minority who will be actively building the content, but the power is in providing those opportunities for all. Much of this will be familiar to the responsible practitioners who build websites for government, local authorities, utility companies, newspapers, magazines, banking, and we-sell-everything-ever-made online shops. Across the web, there are sites and tools that thrive on complexity. Alas, the majority of such sites have done little to make navigation intuitive, or empower audiences. Where we can make a difference is by striving to make our UIs feel simple, look wonderful, not intimidating — even if they’re mind-meltingly complex behind that façade. Embrace, empathize and tame So, there are loads of ways to exploit complexity, and make it seem simple. I’ve hinted at some methods above, and we’ve already looked at gradual engagement as a way to make sense of complexity, so that’s a big thumbs-up for a release cycle that increases audience power. Prior to each and every release, it’s also useful to rest on the finished thing for a while and use it yourself, even if you’re itching to release. ‘Ready’ often isn’t, and ‘finished’ never is, and the more time you spend browsing around the sites you build, the more you learn what to question, where to add, or subtract. It’s definitely worth building in some contingency time for sitting on your work, so to speak. One thing I always do is squint at my layouts. By squinting, I get a sort of abstract idea of the overall composition, and general feel for the thing. It makes my face look stupid, but helps me see how various buckets fit together, and how simple or complex the site feels overall. I mentioned the need to put our design egos to one side and not throw out anything useful, and I think that’s vital. I’m a big believer in economy, reduction, and removing the extraneous, but I’m usually referring to decoration, bells and whistles, and fluff. I wouldn’t ever advocate the complete removal of powerful content from a project roadmap. Above all, don’t fear complexity. Embrace and tame it. Work hard to empathize with audience needs, and you can create elegant, playful, risky, surprising, emotive, delightful, and ultimately simple things. 2011 Simon Collison simoncollison 2011-12-21T00:00:00+00:00 https://24ways.org/2011/taming-complexity/ ux
132 Tasty Text Trimmer In most cases, when designing a user interface it’s best to make a decision about how data is best displayed and stick with it. Failing to make a decision ultimately leads to too many user options, which in turn can be taxing on the poor old user. Under some circumstances, however, it’s good to give the user freedom in customising their workspace. One good example of this is the ‘Article Length’ tool in Apple’s Safari RSS reader. Sliding a slider left of right dynamically changes the length of each article shown. It’s that kind of awesomey magic stuff that’s enough to keep you from sleeping. Let’s build one. The Setup Let’s take a page that has lots of long text items, a bit like a news page or like Safari’s RSS items view. If we were to attach a class name to each element we wanted to resize, that would give us something to hook onto from the JavaScript. Example 1: The basic page. As you can see, I’ve wrapped my items in a DIV and added a class name of chunk to them. It’s these chunks that we’ll be finding with the JavaScript. Speaking of which … Our Core Functions There are two main tasks that need performing in our script. The first is to find the chunks we’re going to be resizing and store their original contents away somewhere safe. We’ll need this so that if we trim the text down we’ll know what it was if the user decides they want it back again. We’ll call this loadChunks. var loadChunks = function(){ var everything = document.getElementsByTagName('*'); var i, l; chunks = []; for (i=0, l=everything.length; i<l; i++){ if (everything[i].className.indexOf(chunkClass) > -1){ chunks.push({ ref: everything[i], original: everything[i].innerHTML }); } } }; The variable chunks is stored outside of this function so that we can access it from our next core function, which is doTrim. var doTrim = function(interval) { if (!chunks) loadChunks(); var i, l; for (i=0, l=chunks.length; i<l; i++){ var a = chunks[i].original.split(' '); a = a.slice(0, interval); chunks[i].ref.innerHTML = a.join(' '); } }; The first thing that needs to be done is to call loadChunks if the chunks variable isn’t set. This should only happen the first time doTrim is called, as from that point the chunks will be loaded. Then all we do is loop through the chunks and trim them. The trimming itself (lines 6-8) is very simple. We split the text into an array of words (line 6), then select only a portion from the beginning of the array up until the number we want (line 7). Finally the words are glued back together (line 8). In essense, that’s it, but it leaves us needing to know how to get the number into this function in the first place, and how that number is generated by the user. Let’s look at the latter case first. The YUI Slider Widget There are lots of JavaScript libraries available at the moment. A fair few of those are really good. I use the Yahoo! User Interface Library professionally, but have only recently played with their pre-build slider widget. Turns out, it’s pretty good and perfect for this task. Once you have the library files linked in (check the docs linked above) it’s fairly straightforward to create yourself a slider. slider = YAHOO.widget.Slider.getHorizSlider("sliderbg", "sliderthumb", 0, 100, 5); slider.setValue(50); slider.subscribe("change", doTrim); All that’s needed then is some CSS to make the slider look like a slider, and of course a few bits of HTML. We’ll see those later. See It Working! Rather than spell out all the nuts and bolts of implementing this fairly simple script, let’s just look at in it action and then pick on some interesting bits I’ve added. Example 2: Try the Tasty Text Trimmer. At the top of the JavaScript file I’ve added a small number of settings. var chunkClass = 'chunk'; var minValue = 10; var maxValue = 100; var multiplier = 5; Obvious candidates for configuration are the class name used to find the chunks, and also the some minimum and maximum values. The minValue is the fewest number of words we wish to display when the slider is all the way down. The maxValue is the length of the slider, in this case 100. Moving the slider makes a call to our doTrim function with the current value of the slider. For a slider 100 pixels long, this is going to be in the range of 0-100. That might be okay for some things, but for longer items of text you’ll want to allow for displaying more than 100 words. I’ve accounted for this by adding in a multiplier – in my code I’m multiplying the value by 5, so a slider value of 50 shows 250 words. You’ll probably want to tailor the multiplier to the type of content you’re using. Keeping it Accessible This effect isn’t something we can really achieve without JavaScript, but even so we must make sure that this functionality has no adverse impact on the page when JavaScript isn’t available. This is achieved by adding the slider markup to the page from within the insertSliderHTML function. var insertSliderHTML = function(){ var s = '<a id="slider-less" href="#less"><img src="icon_min.gif" width="10" height="10" alt="Less text" class="first" /></a>'; s +=' <div id="sliderbg"><div id="sliderthumb"><img src="sliderthumbimg.gif" /></div></div>'; s +=' <a id="slider-more" href="#more"><img src="icon_max.gif" width="10" height="10" alt="More text" /></a>'; document.getElementById('slider').innerHTML = s; } The other important factor to consider is that a slider can be tricky to use unless you have good eyesight and pretty well controlled motor skills. Therefore we should provide a method of changing the value by the keyboard. I’ve done this by making the icons at either end of the slider links so they can be tabbed to. Clicking on either icon fires the appropriate JavaScript function to show more or less of the text. In Conclusion The upshot of all this is that without JavaScript the page just shows all the text as it normally would. With JavaScript we have a slider for trimming the text excepts that can be controlled with the mouse or with a keyboard. If you’re like me and have just scrolled to the bottom to find the working demo, here it is again: Try the Tasty Text Trimmer Trimmer for Christmas? Don’t say I never give you anything! 2006 Drew McLellan drewmclellan 2006-12-01T00:00:00+00:00 https://24ways.org/2006/tasty-text-trimmer/ code
65 The Accessibility Mindset Accessibility is often characterized as additional work, hard to learn and only affecting a small number of people. Those myths have no logical foundation and often stem from outdated information or misconceptions. Indeed, it is an additional skill set to acquire, quite like learning new JavaScript frameworks, CSS layout techniques or new HTML elements. But it isn’t particularly harder to learn than those other skills. A World Health Organization (WHO) report on disabilities states that, [i]ncluding children, over a billion people (or about 15% of the world’s population) were estimated to be living with disability. Being disabled is not as unusual as one might think. Due to chronic health conditions and older people having a higher risk of disability, we are also currently paving the cowpath to an internet that we can still use in the future. Accessibility has a very close relationship with usability, and advancements in accessibility often yield improvements in the usability of a website. Websites are also more adaptable to users’ needs when they are built in an accessible fashion. Beyond the bare minimum In the time of table layouts, web developers could create code that passed validation rules but didn’t adhere to the underlying semantic HTML model. We later developed best practices, like using lists for navigation, and with HTML5 we started to wrap those lists in nav elements. Working with accessibility standards is similar. The Web Content Accessibility Guidelines (WCAG) 2.0 can inform your decision to make websites accessible and can be used to test that you met the success criteria. What it can’t do is measure how well you met them. W3C developed a long list of techniques that can be used to make your website accessible, but you might find yourself in a situation where you need to adapt those techniques to be the most usable solution for your particular problem. The checkbox below is implemented in an accessible way: The input element has an id and the label associated with the checkbox refers to the input using the for attribute. The hover area is shown with a yellow background and a black dotted border: Open video The label is clickable and the checkbox has an accessible description. Job done, right? Not really. Take a look at the space between the label and the checkbox: Open video The gutter is created using a right margin which pushes the label to the right. Users would certainly expect this space to be clickable as well. The simple solution is to wrap the label around the checkbox and the text: Open video You can also set the label to display:block; to further increase the clickable area: Open video And while we’re at it, users might expect the whole box to be clickable anyway. Let’s apply the CSS that was on a wrapping div element to the label directly: Open video The result enhances the usability of your form element tremendously for people with lower dexterity, using a voice mouse, or using touch interfaces. And we only used basic HTML and CSS techniques; no JavaScript was added and not one extra line of CSS. <form action="#"> <label for="uniquecheckboxid"> <input type="checkbox" name="checkbox" id="uniquecheckboxid" /> Checkbox 4 </label> </form> Button Example The button below looks like a typical edit button: a pencil icon on a real button element. But if you are using a screen reader or a braille keyboard, the button is just read as “button” without any indication of what this button is for. Open video A screen reader announcing a button. Contains audio. The code snippet shows why the button is not properly announced: <button> <span class="icon icon-pencil"></span> </button> An icon font is used to display the icon and no text alternative is given. A possible solution to this problem is to use the title or aria-label attributes, which solves the alternative text use case for screen reader users: Open video A screen reader announcing a button with a title. However, screen readers are not the only way people with and without disabilities interact with websites. For example, users can reset or change font families and sizes at will. This helps many users make websites easier to read, including people with dyslexia. Your icon font might be replaced by a font that doesn’t include the glyphs that are icons. Additionally, the icon font may not load for users on slow connections, like on mobile phones inside trains, or because users decided to block external fonts altogether. The following screenshots show the mobile GitHub view with and without external fonts: The mobile GitHub view with and without external fonts. Even if the title/aria-label approach was used, the lack of visual labels is a barrier for most people under those circumstances. One way to tackle this is using the old-fashioned img element with an appropriate alt attribute, but surprisingly not every browser displays the alternative text visually when the image doesn’t load. <button> <img src="icon-pencil.svg" alt="Edit"> </button> Providing always visible text is an alternative that can work well if you have the space. It also helps users understand the meaning of the icons. <button> <span class="icon icon-pencil"></span> Edit </button> This also reads just fine in screen readers: Open video A screen reader announcing the revised button. Clever usability enhancements don’t stop at a technical implementation level. Take the BBC iPlayer pages as an example: when a user navigates the “captioned videos” or “audio description” categories and clicks on one of the videos, captions or audio descriptions are automatically switched on. Small things like this enhance the usability and don’t need a lot of engineering resources. It is more about connecting the usability dots for people with disabilities. Read more about the BBC iPlayer accessibility case study. More information W3C has created several documents that make it easier to get the gist of what web accessibility is and how it can benefit everyone. You can find out “How People with Disabilities Use the Web”, there are “Tips for Getting Started” for developers, designers and content writers. And for the more seasoned developer there is a set of tutorials on web accessibility, including information on crafting accessible forms and how to use images in an accessible way. Conclusion You can only produce a web project with long-lasting accessibility if accessibility is not an afterthought. Your organization, your division, your team need to think about accessibility as something that is the foundation of your website or project. It needs to be at the same level as performance, code quality and design, and it needs the same attention. Users often don’t notice when those fundamental aspects of good website design and development are done right. But they’ll always know when they are implemented poorly. If you take all this into consideration, you can create accessibility solutions based on the available data and bring accessibility to people who didn’t know they’d need it: Open video In this video from the latest Apple keynote, the Apple TV is operated by voice input through a remote. When the user asks “What did she say?” the video jumps back fifteen seconds and captions are switched on for a brief time. All three, the remote, voice input and captions have their roots in assisting people with disabilities. Now they benefit everyone. 2015 Eric Eggert ericeggert 2015-12-17T00:00:00+00:00 https://24ways.org/2015/the-accessibility-mindset/ code
260 The Art of Mathematics: A Mandala Maker Tutorial In front-end development, there’s often a great deal of focus on tools that aim to make our work more efficient. But what if you’re new to web development? When you’re just starting out, the amount of new material can be overwhelming, particularly if you don’t have a solid background in Computer Science. But the truth is, once you’ve learned a little bit of JavaScript, you can already make some pretty impressive things. A couple of years back, when I was learning to code, I started working on a side project. I wanted to make something colorful and fun to share with my friends. This is what my app looks like these days: Mandala Maker user interface The coolest part about it is the fact that it’s a tool: anyone can use it to create something original and brand new. In this tutorial, we’ll build a smaller version of this app – a symmetrical drawing tool in ES5, JavaScript and HTML5. The tutorial app will have eight reflections, a color picker and a Clear button. Once we’re done, you’re on your own and can tweak it as you please. Be creative! Preparations: a blank canvas The first thing you’ll need for this project is a designated drawing space. We’ll use the HTML5 canvas element and give it a width and a height of 600px (you can set the dimensions to anything else if you like). Files Create 3 files: index.html, styles.css, main.js. Don’t forget to include your JS and CSS files in your HTML. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" type="text/css" href="style.css"> <script src="main.js"></script> </head> <body onload="init()"> <canvas width="600" height="600"> <p>Your browser doesn't support canvas.</p> </canvas> </body> </html> I’ll ask you to update your HTML file at a later point, but the CSS file we’ll start with will stay the same throughout the project. This is the full CSS we are going to use: body { background-color: #ccc; text-align: center; } canvas { touch-action: none; background-color: #fff; } button { font-size: 110%; } Next steps We are done with our preparations and ready to move on to the actual tutorial, which is made up of 4 parts: Building a simple drawing app with one line and one color Adding a Clear button and a color picker Adding more functionality: 2 line drawing (add the first reflection) Adding more functionality: 8 line drawing (add 6 more reflections!) Interactive demos This tutorial will be accompanied by four CodePens, one at the end of each section. In my own app I originally used mouse events, and only added touch events when I realized mobile device support was (A) possible, and (B) going to make my app way more accessible. For the sake of code simplicity, I decided that in this tutorial app I will only use one event type, so I picked a third option: pointer events. These are supported by some desktop browsers and some mobile browsers. An up-to-date version of Chrome is probably your best bet. Part 1: A simple drawing app Let’s get started with our main.js file. Our basic drawing app will be made up of 6 functions: init, drawLine, stopDrawing, recordPointerLocation, handlePointerMove, handlePointerDown. It also has nine variables: var canvas, context, w, h, prevX = 0, currX = 0, prevY = 0, currY = 0, draw = false; The variables canvas and context let us manipulate the canvas. w is the canvas width and h is the canvas height. The four coordinates are used for tracking the current and previous location of the pointer. A short line is drawn between (prevX, prevY) and (currX, currY) repeatedly many times while we move the pointer upon the canvas. For your drawing to appear, three conditions must be met: the pointer (be it a finger, a trackpad or a mouse) must be down, it must be moving and the movement has to be on the canvas. If these three conditions are met, the boolean draw is set to true. 1. init Responsible for canvas set up, this listens to pointer events and the location of their coordinates and sets everything in motion by calling other functions, which in turn handle touch and movement events. function init() { canvas = document.querySelector("canvas"); context = canvas.getContext("2d"); w = canvas.width; h = canvas.height; canvas.onpointermove = handlePointerMove; canvas.onpointerdown = handlePointerDown; canvas.onpointerup = stopDrawing; canvas.onpointerout = stopDrawing; } 2. drawLine This is called to action by handlePointerMove() and draws the pointer path. It only runs if draw = true. It uses canvas methods you can read about in the canvas API documentation. You can also learn to use the canvas element in this tutorial. lineWidth and linecap set the properties of our paint brush, or digital pen, but pay attention to beginPath and closePath. Between those two is where the magic happens: moveTo and lineTo take canvas coordinates as arguments and draw from (a,b) to (c,d), which is to say from (prevX,prevY) to (currX,currY). function drawLine() { var a = prevX, b = prevY, c = currX, d = currY; context.lineWidth = 4; context.lineCap = "round"; context.beginPath(); context.moveTo(a, b); context.lineTo(c, d); context.stroke(); context.closePath(); } 3. stopDrawing This is used by init when the pointer is not down (onpointerup) or is out of bounds (onpointerout). function stopDrawing() { draw = false; } 4. recordPointerLocation This tracks the pointer’s location and stores its coordinates. Also, you need to know that in computer graphics the origin of the coordinate space (0,0) is at the top left corner, and all elements are positioned relative to it. When we use canvas we are dealing with two coordinate spaces: the browser window and the canvas itself. This function converts between the two: it subtracts the canvas offsetLeft and offsetTop so we can later treat the canvas as the only coordinate space. If you are confused, read more about it. function recordPointerLocation(e) { prevX = currX; prevY = currY; currX = e.clientX - canvas.offsetLeft; currY = e.clientY - canvas.offsetTop; } 5. handlePointerMove This is set by init to run when the pointer moves. It checks if draw = true. If so, it calls recordPointerLocation to get the path and drawLine to draw it. function handlePointerMove(e) { if (draw) { recordPointerLocation(e); drawLine(); } } 6. handlePointerDown This is set by init to run when the pointer is down (finger is on touchscreen or mouse it clicked). If it is, calls recordPointerLocation to get the path and sets draw to true. That’s because we only want movement events from handlePointerMove to cause drawing if the pointer is down. function handlePointerDown(e) { recordPointerLocation(e); draw = true; } Finally, we have a working drawing app. But that’s just the beginning! See the Pen Mandala Maker Tutorial: Part 1 by Hagar Shilo (@hagarsh) on CodePen. Part 2: Add a Clear button and a color picker Now we’ll update our HTML file, adding a menu div with an input of the type and class color and a button of the class clear. <body onload="init()"> <canvas width="600" height="600"> <p>Your browser doesn't support canvas.</p> </canvas> <div class="menu"> <input type="color" class="color" /> <button type="button" class="clear">Clear</button> </div> </body> Color picker This is our new color picker function. It targets the input element by its class and gets its value. function getColor() { return document.querySelector(".color").value; } Up until now, the app used a default color (black) for the paint brush/digital pen. If we want to change the color we need to use the canvas property strokeStyle. We’ll update drawLine by adding strokeStyle to it and setting it to the input value by calling getColor. function drawLine() { //...code... context.strokeStyle = getColor(); context.lineWidth = 4; context.lineCap = "round"; //...code... } Clear button This is our new Clear function. It responds to a button click and displays a dialog asking the user if she really wants to delete the drawing. function clearCanvas() { if (confirm("Want to clear?")) { context.clearRect(0, 0, w, h); } } The method clearRect takes four arguments. The first two (0,0) mark the origin, which is actually the top left corner of the canvas. The other two (w,h) mark the full width and height of the canvas. This means the entire canvas will be erased, from the top left corner to the bottom right corner. If we were to give clearRect a slightly different set of arguments, say (0,0,w/2,h), the result would be different. In this case, only the left side of the canvas would clear up. Let’s add this event handler to init: function init() { //...code... canvas.onpointermove = handleMouseMove; canvas.onpointerdown = handleMouseDown; canvas.onpointerup = stopDrawing; canvas.onpointerout = stopDrawing; document.querySelector(".clear").onclick = clearCanvas; } See the Pen Mandala Maker Tutorial: Part 2 by Hagar Shilo (@hagarsh) on CodePen. Part 3: Draw with 2 lines It’s time to make a line appear where no pointer has gone before. A ghost line! For that we are going to need four new coordinates: a', b', c' and d' (marked in the code as a_, b_, c_ and d_). In order for us to be able to add the first reflection, first we must decide if it’s going to go over the y-axis or the x-axis. Since this is an arbitrary decision, it doesn’t matter which one we choose. Let’s go with the x-axis. Here is a sketch to help you grasp the mathematics of reflecting a point across the x-axis. The coordinate space in my sketch is different from my explanation earlier about the way the coordinate space works in computer graphics (more about that in a bit!). Now, look at A. It shows a point drawn where the pointer hits, and B shows the additional point we want to appear: a reflection of the point across the x-axis. This is our goal. A sketch illustrating the mathematics of reflecting a point. What happens to the x coordinates? The variables a/a' and c/c' correspond to prevX and currX respectively, so we can call them “the x coordinates”. We are reflecting across x, so their values remain the same, and therefore a' = a and c' = c. What happens to the y coordinates? What about b' and d'? Those are the ones that have to change, but in what way? Thanks to the slightly misleading sketch I showed you just now (of A and B), you probably think that the y coordinates b' and d' should get the negative values of b and d respectively, but nope. This is computer graphics, remember? The origin is at the top left corner and not at the canvas center, and therefore we get the following values: b = h - b, d' = h - d, where h is the canvas height. This is the new code for the app’s variables and the two lines: the one that fills the pointer’s path and the one mirroring it across the x-axis. function drawLine() { var a = prevX, a_ = a, b = prevY, b_ = h-b, c = currX, c_ = c, d = currY, d_ = h-d; //... code ... // Draw line #1, at the pointer's location context.moveTo(a, b); context.lineTo(c, d); // Draw line #2, mirroring the line #1 context.moveTo(a_, b_); context.lineTo(c_, d_); //... code ... } In case this was too abstract for you, let’s look at some actual numbers to see how this works. Let’s say we have a tiny canvas of w = h = 10. Now let a = 3, b = 2, c = 4 and d = 3. So b' = 10 - 2 = 8 and d' = 10 - 3 = 7. We use the top and the left as references. For the y coordinates this means we count from the top, and 8 from the top is also 2 from the bottom. Similarly, 7 from the top is 3 from the bottom of the canvas. That’s it, really. This is how the single point, and a line (not necessarily a straight one, by the way) is made up of many, many small segments that are similar to point in behavior. If you are still confused, I don’t blame you. Here is the result. Draw something and see what happens. See the Pen Mandala Maker Tutorial: Part 3 by Hagar Shilo (@hagarsh) on CodePen. Part 4: Draw with 8 lines I have made yet another confusing sketch, with points C and D, so you understand what we’re trying to do. Later on we’ll look at points E, F, G and H as well. The circled point is the one we’re adding at each particular step. The circled point at C has the coordinates (-3,2) and the circled point at D has the coordinates (-3,-2). Once again, keep in mind that the origin in the sketches is not the same as the origin of the canvas. A sketch illustrating points C and D. This is the part where the math gets a bit mathier, as our drawLine function evolves further. We’ll keep using the four new coordinates: a', b', c' and d', and reassign their values for each new location/line. Let’s add two more lines in two new locations on the canvas. Their locations relative to the first two lines are exactly what you see in the sketch above, though the calculation required is different (because of the origin points being different). function drawLine() { //... code ... // Reassign values a_ = w-a; b_ = b; c_ = w-c; d_ = d; // Draw the 3rd line context.moveTo(a_, b_); context.lineTo(c_, d_); // Reassign values a_ = w-a; b_ = h-b; c_ = w-c; d_ = h-d; // Draw the 4th line context.moveTo(a_, b_); context.lineTo(c_, d_); //... code ... What is happening? You might be wondering why we use w and h as separate variables, even though we know they have the same value. Why complicate the code this way for no apparent reason? That’s because we want the symmetry to hold for a rectangular canvas as well, and this way it will. Also, you may have noticed that the values of a' and c' are not reassigned when the fourth line is created. Why write their value assignments twice? It’s for readability, documentation and communication. Maintaining the quadruple structure in the code is meant to help you remember that all the while we are dealing with two y coordinates (current and previous) and two x coordinates (current and previous). What happens to the x coordinates? As you recall, our x coordinates are a (prevX) and c (currX). For the third line we are adding, a' = w - a and c' = w - c, which means… For the fourth line, the same thing happens to our x coordinates a and c. What happens to the y coordinates? As you recall, our y coordinates are b (prevY) and d (currY). For the third line we are adding, b' = b and d' = d, which means the y coordinates are the ones not changing this time, making this is a reflection across the y-axis. For the fourth line, b' = h - b and d' = h - d, which we’ve seen before: that’s a reflection across the x-axis. We have four more lines, or locations, to define. Note: the part of the code that’s responsible for drawing a micro-line between the newly calculated coordinates is always the same: context.moveTo(a_, b_); context.lineTo(c_, d_); We can leave it out of the next code snippets and just focus on the calculations, i.e, the reassignments. Once again, we need some concrete examples to see where we’re going, so here’s another sketch! The circled point E has the coordinates (2,3) and the circled point F has the coordinates (2,-3). The ability to draw at A but also make the drawing appear at E and F (in addition to B, C and D that we already dealt with) is the functionality we are about to add to out code. A sketch illustrating points E and F. This is the code for E and F: // Reassign for 5 a_ = w/2+h/2-b; b_ = w/2+h/2-a; c_ = w/2+h/2-d; d_ = w/2+h/2-c; // Reassign for 6 a_ = w/2+h/2-b; b_ = h/2-w/2+a; c_ = w/2+h/2-d; d_ = h/2-w/2+c; Their x coordinates are identical and their y coordinates are reversed to one another. This one will be out final sketch. The circled point G has the coordinates (-2,3) and the circled point H has the coordinates (-2,-3). A sketch illustrating points G and H. This is the code: // Reassign for 7 a_ = w/2-h/2+b; b_ = w/2+h/2-a; c_ = w/2-h/2+d; d_ = w/2+h/2-c; // Reassign for 8 a_ = w/2-h/2+b; b_ = h/2-w/2+a; c_ = w/2-h/2+d; d_ = h/2-w/2+c; //...code... } Once again, the x coordinates of these two points are the same, while the y coordinates are different. And once again I won’t go into the full details, since this has been a long enough journey as it is, and I think we’ve covered all the important principles. But feel free to play around with the code and change it. I really recommend commenting out the code for some of the points to see what your drawing looks like without them. I hope you had fun learning! This is our final app: See the Pen Mandala Maker Tutorial: Part 4 by Hagar Shilo (@hagarsh) on CodePen. 2018 Hagar Shilo hagarshilo 2018-12-02T00:00:00+00:00 https://24ways.org/2018/the-art-of-mathematics/ code
144 The Mobile Web, Simplified A note from the editors: although eye-opening in 2006, this article is no longer relevant to today’s mobile web. Considering a foray into mobile web development? Following are four things you need to know before making the leap. 1. 4 billion mobile subscribers expected by 2010 Fancy that. Coupled with the UN prediction of 6.8 billion humans by 2010, 4 billion mobile subscribers (source) is an astounding 59% of the planet. Just how many of those subscribers will have data plans and web-enabled phones is still in question, but inevitably this all means one thing for you and me: A ton of potential eyes to view our web content on a mobile device. 2. Context is king Your content is of little value to users if it ignores the context in which it is viewed. Consider how you access data on your mobile device. You might be holding a bottle of water or gripping a handle on the subway/tube. You’re probably seeking specific data such as directions or show times, rather than the plethora of data at your disposal via a desktop PC. The mobile web, a phrase often used to indicate “accessing the web on a mobile device”, is very much a context-, content-, and component-specific environment. Expressed in terms of your potential target audience, access to web content on a mobile device is largely influenced by surrounding circumstances and conditions, information relevant to being mobile, and the feature set of the device being used. Ask yourself, What is relevant to my users and the tasks, problems, and needs they may encounter while being mobile? Answer that question and you’ll be off to a great start. 3. WAP 2.0 is an XHTML environment In a nutshell, here are a few fundamental tenets of mobile internet technology: Wireless Application Protocol (WAP) is the protocol for enabling mobile access to internet content. Wireless Markup Language (WML) was the language of choice for WAP 1.0. Nearly all devices sold today are WAP 2.0 devices. With the introduction of WAP 2.0, XHTML Mobile Profile (XHTML-MP) became the preferred markup language. XHTML-MP will be familiar to anyone experienced with XHTML Transitional or Strict. Summary? The mobile web is rapidly becoming an XHTML environment, and thus you and I can apply our existing “desktop web” skills to understand how to develop content for it. With WML on the decline, the learning curve is much smaller today than it was several years ago. I’m generalizing things gratuitously, but the point remains: Get off yo’ lazy butt and begin to take mobile seriously. I’ll even pass you a few tips for getting started. First, the DOCTYPE for XHTML-MP is as follows: <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile10.dtd"> As for MIME type, Open Mobile Alliance (OMA) specifies using the MIME type application/vnd.wap.xhtml+xml, but ultimately you need to ensure the server delivering your mobile content is configured properly for the MIME type you choose to use, as there are other options (see Setting up WAP Servers). Once you’ve made it to the body, the XHTML-MP markup is not unlike what you’re already used to. A few resources worth skimming: Developers Home XHTML-MP Tutorial – An impressively replete resource for all things XHTML-MP XHTML-MP Tags List – A complete list of XHTML-MP elements and accompanying attributes And last but certainly not least, CSS. There exists WAP CSS, which is essentially a subset of CSS2 with WAP-specific extensions. For all intents and purposes, much of the CSS you’re already comfortable using will be transferrable to mobile. As for including CSS in your pages, your options are the same as for desktop sites: external, embedded, and inline. Some experts will argue embedded or inline over external in favor of reducing the number of HTTP connections per page request, yet many popular mobilized sites and apps employ external linking without issue. Stocking stuffers: Flickr Mobile, Fandango Mobile, and Popurls Mobile. A few sites with whom you can do the View Source song and dance for further study. 4. “Cell phone” is so DynaTAC If you’re a U.S. resident, listen up: You must rid your vocabulary of the term “cell phone”. We’re one of the few economies on the planet to refer to a mobile phone accordingly. If you care to find yourself in any of the worthwhile mobile development circles, begin using terms more widely accepted: “mobile” or “mobile phone” or “handset” or “handy”. If you’re not sure which, go for “mobile”. Such as, “Yo dog, check out my new mobile.” More importantly, however, is overcoming the mentality that access to the mobile web can be done only with a phone. Instead, “device” encourages us to think phone, handheld computer, watch, Nintendo DS, car, you name it. Simple enough? 2006 Cameron Moll cameronmoll 2006-12-19T00:00:00+00:00 https://24ways.org/2006/the-mobile-web-simplified/ ux
22 The Responsive Hover Paradigm CSS transitions and animations provide web designers with a whole slew of tools to spruce up our designs. Move over ActionScript tweens! The techniques we can now implement with CSS are reminiscent of Flash-based adventures from the pages of web history. Pairing CSS enhancements with our :hover pseudo-class allows us to add interesting events to our websites. We have a ton of power at our fingertips. However, with this power, we each have to ask ourselves: just because I can do something, should I? Why bother? We hear a lot of mantras in the web community. Some proclaim the importance of content; some encourage methods like mobile first to support content; and others warn of the overhead and speed impact of decorative flourishes and visual images. I agree, one hundred percent. At the same time, I believe that content can reign king and still provide a beautiful design with compelling interactions and acceptable performance impacts. Maybe, just maybe, we can even have a little bit of fun when crafting these systems! Yes, a site with pure HTML content and no CSS will load very fast on your mobile phone, but it leaves a lot to be desired. If you went to your local library and every book looked the same, how would you know which one to borrow? Imagine if every book was printed on the same paper stock with the same cover page in the same type size set at a legible point value… how would you know if you were going to purchase a cookbook about wild game or a young adult story about teens fighting to the death? For certain audiences, seeing a site with hip, lively hovers sure beats a stale website concept. I’ve worked on many higher education sites, and setting the interactive options is often a very important factor in engaging potential students, alumni, and donors. The same can go for e-commerce sites: enticing your audience with surprise and delight factors can be the difference between a successful and a lost sale. Knowing your content and audience can help you decide if an intriguing experience is appropriate for your site; if it is, then hover responses can be a real asset. Why hover? We have all these capabilities with CSS properties to create the aforementioned fun interactions, and it would be quite easy to fall back into some old patterns and animation abuse. The world of Flash intros and skip links could be recreated with CSS keyframes. However, I don’t think any of us want to go the route of forcing users into unwanted exchanges and road blocking content. What’s great about utilizing hover to pair with CSS powered actions is that it’s user initiated. It’s a well-established expectation that when a user mouses over an object, something changes. If we can identify that something as a link, then we will expect something to change as we move our mouse over it. By waiting to trigger a CSS-based response until a user chooses to engage with a target makes for a more polished experience (as opposed to barraging our screens with animations all willy-nilly). This makes it the perfect opportunity to add some unique spunk. What about mobile, touch, and responsive? So, you’re on board with this so far, but what about mobile and touch devices? Sure, some devices like the Samsung Galaxy S4 have some hovering capabilities, but certainly most do not. Beyond mobile devices, we also have to worry about desktops with touch capabilities. It’s super difficult to detect if a user is currently using touch or hover. One option we have is to design strictly for touch only and send hover enhancements to the graveyard. However, being that I’m all “fuck yeah hovers!,” I like to explore all options. So, let’s examine four different types of hover patterns and see how they can translate to our touch devices. 1. The essential text hover Changing text color on hover is something we’ve done for a while and it has helped aid in identifying links. To maintain the best accessibility we can achieve, it helps to have a different visual indicator on the default :link state, such as an underline. By making sure all text links have an underline, we won’t have to rely on visual changes during hover to make sure touch device users know that it is a link. For hover-enabled devices, we can add a basic color transition. Doing so creates a nice fade, which makes the change on hover less jarring. Kinda like smooth jazz. The code* to achieve this is quite simple: a { color: #6dd4b1; transition: color 0.25s linear; } a:hover, a:focus { color: #357099; } Browser prefixes are omitted You can see in the final result that, for both touch and hover, everyone wins: See the Pen Most Basic Link Transition by Jenn Lukas (@Jenn) on CodePen 2. Visual background wizardry and animated hovers We can take this a step further by again making changes to our aesthetic on hover, but not making any content changes. Altering image hovers for fun and personality can separate your site from others; that personality is important and can enhance our content. Let’s look at a few sites that do this really well. Scroll down to the judges section of CSS Off and check out the illustrations of the judges. On hover, the illustration fades into a photo of the judge. This provides a realistic alternative to the drawing. Users without the hover can click into the detail page, where they can see the full color picture and learn more about the judges; the information is still available through a different pathway. Going back to the higher education field, let’s visit Delaware Valley College. The school had recently gone through a rebranding that included loop icons as a symbol to connect ideas. These icons are brought into the website on hover of the slideshow arrows (WebKit browsers). The hover reveals a loop animation, tying in overall themes and adding some extra pizzazz that makes me think, “This is a hip place that feels current.” For visitors who can’t access the hover effect, the default arrow state clearly represents a clickable link, and there is swipe functionality on mobile devices to boot. DIY.org’s Frontend Dev page has a bunch of enjoyable hover actions happening, featuring scaling transforms and looping animations. Nothing new is revealed on hover, so touch devices won’t miss anything, but it intrigues the user who is visiting a site about front-end dev doing cool front-end things. It backs up its claim of front-end knowledge by adding this enhancement. The old Cowork Chicago (now redirecting) had a great example, captured here: Coop: Chicago Coworking from Jenn Lukas on Vimeo. The code for the Join areas is quite simple: .join-buttons .daily, .join-buttons .monthly { height: 260px; z-index: 0; margin-top: 30px; transition: height .2s linear,margin .2s linear; } .join-buttons .daily:hover, .join-buttons .monthly:hover { height: 280px; margin-top: 20px; } li.button:hover { z-index: 20; } The slight rotation on the photos, and the change of color and size of the rate options on hover, add to the fun factor. The site attempts to advertise the co-working space by letting bits of their charisma show through with these transitions. They don’t hit the user over the head with animations, but provide a nice addition to make sure visitors know it’s a welcoming place to work. Some text is added on the hover, but the text isn’t essential to determine where the link goes. 3. Image block hovers There have been more designs popping up with large image blocks acting as extensive hit area links to subsequent pages. On hover of these links, text is revealed, letting the user know where the link destination goes. See the Pen Transitioning Max Height by Jenn Lukas (@Jenn) on CodePen This type of link is tough for users on touch as the image might not provide enough context to reveal its target. If you weren’t aware of what my illustrated avatar from 2007 looked like (or even if you did), then how would you know that this is a link to my Twitter page? Instead, if we provide enough context — such as the @jennlukas handle — you could assume the destination. Users who receive the hover can also see the Twitter bio. It won’t break the experience for users that can’t hover, but it will provide a nice interaction and some more information for those that can. See the Pen Transitioning Max Height by Jenn Lukas (@Jenn) on CodePen The Esquire site follows this same pattern, in which the title of the story is shown and the subheading is revealed on hover. Dining at Altitude took the opposite approach, where all text is shown by default and, on hover, you can see more of the image that the text sits atop. This is a nice technique to follow. For touch users, following the link will allow them to see more of the image detail that was revealed on hover. 4. Drop-down navigation menu hovers Main navigation options that rely on hover have come up as a problem for touch. One way to address this is to be sure your top level items are all functional links to somewhere, and not blank anchors to trigger a submenu drop-down. This ensures that, even without the hover-triggered menu, users can still navigate to those top-level pages. From there, they should be able to access the tertiary pages shown in the drop-down. Following this arrangement, drop-down menus act as a quick shortcut and aren’t necessary to the navigational structure. If the top navigation items are your most visited pages, this execution won’t hinder your visitors. If the information within the menu is vital, such as a lone account menu, another option is to show drop-down menus on click instead of hover. This pattern will allow both mouse and touch users to access the drop-downs. Why can’t we just detect hover? This is a really tricky thing to do. Internet Explorer 10 on Windows 8 uses the aria-haspopup attribute to simulate hover on touch devices, but usually our audience stretches beyond that group. There’s been discussion around using Modernizr, but false positives have come with that. A W3C draft for Media Queries Level 4 includes a hover feature, but it’s not supported yet. Since some devices can hover and touch, should you rely on hover effects for those? Arguments have come up that users can be browsing your site with a mouse and then decide to switch to touch, or vice versa. That might be a large concern for you, or it might be an edge case that isn’t vital to your site’s success. For one site, I used mousemove and touchstart JavaScript events in order to detect if a visitor starts to browse the site with a mouse. The design initiates for touch users, showing all text on load, but as soon as a mouse movement occurs, the text becomes hidden and is then revealed on hover. See the Pen Detect Touch devices with mousemove and touchstart by Jenn Lukas (@Jenn) on CodePen One downside to this approach is that the text is viewable until a mouse enters the document, but if the elements are further down the page it might not be noticed. A second downside is if a user on a touch- and hover-enabled device starts browsing with the mouse and then switches back to touch, the hover-centric styles will remain until a new page load. These were acceptable scenarios in the project I worked on, but might not be for every project. Can we give our visitors a choice? I’ve been thinking about how we can combat the concern of not knowing if our customers are using touch or a mouse, not to mention keyboard or Wacom tablets or Minority Report screens. We can cover keyboards with our friend :focus, but that still doesn’t solve our other dilemmas. Remember when we couldn’t rely on browsers to zoom text and we had to use those small A, medium A, big A [AAA] buttons? On selection of one of those options, a different style sheet would load with small, medium, or large text sizes to satisfy our user’s request. We could even set cookies to remember their font choices. What if we offered a similar solution, a hover/touch switcher, for our new predicament? See the Pen cwuJf by Jenn Lukas (@Jenn) on CodePen We could add this switcher to our design. Maybe add it to the header on smaller screens and the footer on larger screens to play the odds. Then be sure to deliver the appropriate touch- or hover-optimized adventure for our guests. How about adding View options in the areas where we’re hiding content until hover? Looking at Delta Cycle, there’s logic in place to switch layouts on some mobile devices. On desktops we can see the layout shows the product and price by default, and the name of the item and an Add to cart button on hover. If you want to keep this hover, but also worry that touch users can’t access it — or even if you are concerned that people might want to view it with more details up front — we could add another view switcher. See the Pen List/Grid Views for Hover or Touch by Jenn Lukas (@Jenn) on CodePen Similar to the list versus grid view we often see in operating systems, a choice here could cover all of our bases. Conclusion There is no one-size-fits-all solution when it comes to hover patterns. Design for your content. If you are providing important information about driving directions or healthcare, you might want to err on the side of designing for touch only. If you are behind an educational site and trying to entice more traffic and sign-ups, or a more immersive e-commerce site selling pies, then hover activity can help support your content and engage your visitors without being a detriment. While content can be our top priority, let’s not forget that our designs and interactions, hovers included, can have a great positive impact on how visitors experience our site. Hover wisely, friends. 2013 Jenn Lukas jennlukas 2013-12-12T00:00:00+00:00 https://24ways.org/2013/the-responsive-hover-paradigm/  
251 The System, the Search, and the Food Bank Imagine a warehouse, half the length of a football field, with a looped conveyer belt down the center. On the belt are plastic bins filled with assortments of shelf-stable food—one may have two bags of potato chips, seventeen pudding cups, and a box of tissues; the next, a dozen cans of beets. The conveyer belt is ringed with large, empty cardboard boxes, each labeled with categories like “Bottled Water” or “Cereal” or “Candy.” Such was the scene at my local food bank a few Saturdays ago, when some friends and I volunteered for a shift sorting donated food items. Our job was to fill the labeled cardboard boxes with the correct items nabbed from the swiftly moving, randomly stocked plastic bins. I could scarcely believe my good fortune of assignments. You want me to sort things? Into categories? For several hours? And you say there’s an element of time pressure? Listen, is there some sort of permanent position I could be conscripted into. Look, I can’t quite explain it: I just know that I love sorting, organizing, and classifying things—groceries at a food bank, but also my bookshelves, my kitchen cabinets, my craft supplies, my dishwasher arrangement, yes I am a delight to live with, why do you ask? The opportunity to create meaning from nothing is at the core of my excitement, which is why I’ve tried to build a career out of organizing digital content, and why I brought a frankly frightening level of enthusiasm to the food bank. “I can’t believe they’re letting me do this,” I whispered in awe to my conveyer belt neighbor as I snapped up a bag of popcorn for the Snacks box with the kind of ferocity usually associated with birds of prey. The jumble of donated items coming into the center need to be sorted in order for the food bank to be able to quantify, package, and distribute the food to those who need it (I sense a metaphor coming on). It’s not just a nice-to-have that we spent our morning separating cookies from carrots—it’s a crucial step in the process. Organization makes the difference between chaos and sense, between randomness and usefulness, whether we’re talking about donated groceries or—there it is—web content. This happens through the magic of criteria matching. In order for us to sort the food bank donations correctly, we needed to know not only the categories we were sorting into, but also the criteria for each category. Does canned ravioli count as Canned Soup? Does enchilada sauce count as Tomatoes? Do protein bars count as Snacks? (Answers: yes, yes, and only if they are under 10 grams of protein or will expire within three months.) Is X a Y? was the question at the heart of our food sorting—but it’s also at the heart of any information-seeking behavior. When we are organizing, or looking for, any kind of information, we are asking ourselves: What is the criteria that defines Y? Does X meet that criteria? We don’t usually articulate it so concretely because it’s a background process, only leaping to consciousness when we encounter a stumbling block. If cans of broth flew by on the conveyer belt, it didn’t require much thought to place them in the Canned Soup box. Boxed broth, on the other hand, wasn’t allowed, causing a small cognitive hiccup—this X is NOT a Y—that sometimes meant having to re-sort our boxes. On the web, we’re interested—I would hope—in reducing cognitive hiccups for our users. We are interested in making our apps easy to use, our websites easy to navigate, our information easy to access. After all, most of the time, the process of using the internet is one of uniting a question with an answer—Is this article from a trustworthy source? Is this clothing the style I want? Is this company paying their workers a living wage? Is this website one that can answer my question? Is X a Y? We have a responsibility, therefore, to make information easy for our users to find, understand, and act on. This means—well, this means a lot of things, and I’ve got limited space here, so let’s focus on these three lessons from the food bank: Use plain, familiar language. This advice seems to be given constantly, but that’s because it’s solid and it’s not followed enough. Your menu labels, page names, and headings need to reflect the word choice of your users. Think how much harder it would have been to sort food if the boxes were labeled according to nutritional content, grocery store aisle number, or Latin name. How much would it slow sorting down if the Tomatoes box were labeled Nightshades? It sounds silly, but it’s not that different from sites that use industry jargon, company lingo, acronyms (oh, yes, I’ve seen it), or other internally focused language when trying to provide wayfinding for users. Choose words that your audience knows—not only will they be more likely to spot what they’re looking for on your site or app, but you’ll turn up more often in search results. Create consistency in all things. Missteps in consistency look like my earlier chicken broth example—changing up how something looks, sounds, or functions creates a moment of cognitive dissonance, and those moments add up. The names of products, the names of brands, the names of files and forms and pages, the names of processes and procedures and concepts—these all need to be consistently spelled, punctuated, linked, and referenced, no matter what section or level the user is in. If submenus are visible in one section, they should be visible in all. If calls-to-action are a graphic button in one section, they are the same graphic button in all. Every affordance, every module, every design choice sets up user expectations; consistency keeps those expectations afloat, making for a smoother experience overall. Make the system transparent. By this, I do not mean that every piece of content should be elevated at all times. The horror. But I do mean that we should make an effort to communicate the boundaries of the digital space from any given corner within. Navigation structures operate just as much as a table of contents as they do a method of moving from one place to another. Page hierarchies help explain content relationships, communicating conceptual relevancy and relative importance. Submenus illustrate which related concepts may be found within a given site section. Take care to show information that conveys the depth and breadth of the system, rather than obscuring it. This idea of transparency was perhaps the biggest challenge we experienced in food sorting. Imagine us volunteers as users, each looking for a specific piece of information in the larger system. Like any new visitor to a website, we came into the system not knowing the full picture. We didn’t know every category label around the conveyer belt, nor what criteria each category warranted. The system wasn’t transparent for us, so we had to make it transparent as we went. We had to stop what we were doing and ask questions. We’d ask staff members. We’d ask more seasoned volunteers. We’d ask each other. We’d make guesses, and guess wrongly, and mess up the boxes, and correct our mistakes, and learn. The more we learned, the easier the sorting became. That is, we were able to sort more quickly, more efficiently, more accurately. The better we understood the system, the better we were at interacting with it. The same is true of our users: the better they understand digital spaces, the more effective they are at using them. But visitors to our apps and websites do not have the luxury of learning the whole system. The fumbling trial-and-error method that I used at the food bank can, on a website, drive users away—or, worse, misinform or hurt them. This is why we must make choices that prioritize transparency, consistency, and familiarity. Our users want to know if X is a Y—well-sorted content can give them the answer. 2018 Lisa Maria Martin lisamariamartin 2018-12-16T00:00:00+00:00 https://24ways.org/2018/the-system-the-search-and-the-food-bank/ content
186 The Web Is Your CMS It is amazing what you can do these days with the services offered on the web. Flickr stores terabytes of photos for us and converts them automatically to all kind of sizes, finds people in them and even allows us to edit them online. YouTube does almost the same complete job with videos, LinkedIn allows us to maintain our CV, Delicious our bookmarks and so on. We don’t have to do these tasks ourselves any more, as all of these systems also come with ways to use the data in the form of Application Programming Interfaces, or APIs for short. APIs give us raw data when we send requests telling the system what we want to get back. The problem is that every API has a different idea of what is a simple way of accessing this data and in which format to give it back. Making it easier to access APIs What we need is a way to abstract the pains of different data formats and authentication formats away from the developer — and this is the purpose of the Yahoo Query Language, or YQL for short. Libraries like jQuery and YUI make it easy and reliable to use JavaScript in browsers (yes, even IE6) and YQL allows us to access web services and even the data embedded in web documents in a simple fashion – SQL style. Select * from the web and filter it the way I want YQL is a web service that takes a few inputs itself: A query that tells it what to get, update or access An output format – XML, JSON, JSON-P or JSON-P-X A callback function (if you defined JSON-P or JSON-P-X) You can try it out yourself – check out this link to get back Flickr photos for the search term ‘santa’*%20from%20flickr.photos.search%20where%20text%3D%22santa%22&format=xml in XML format. The YQL query for this is select * from flickr.photos.search where text="santa" The easiest way to take your first steps with YQL is to look at the console. There you get sample queries, access to all the data sources available to you and you can easily put together complex queries. In this article, however, let’s use PHP to put together a web page that pulls in Flickr photos, blog posts, Videos from YouTube and latest bookmarks from Delicious. Check out the demo and get the source code on GitHub. <?php /* YouTube RSS */ $query = 'select description from rss(5) where url="http://gdata.youtube.com/feeds/base/users/chrisheilmann/uploads?alt=rss&v=2&orderby=published&client=ytapi-youtube-profile";'; /* Flickr search by user id */ $query .= 'select farm,id,owner,secret,server,title from flickr.photos.search where user_id="11414938@N00";'; /* Delicious RSS */ $query .= 'select title,link from rss where url="http://feeds.delicious.com/v2/rss/codepo8?count=10";'; /* Blog RSS */ $query .= 'select title,link from rss where url="http://feeds.feedburner.com/wait-till-i/gwZf"'; /* The YQL web service root with JSON as the output */ $root = 'http://query.yahooapis.com/v1/public/yql?format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys'; /* Assemble the query */ $query = "select * from query.multi where queries='".$query."'"; $url = $root . '&q=' . urlencode($query); /* Do the curl call (access the data just like a browser would) */ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $output = curl_exec($ch); curl_close($ch); $data = json_decode($output); $results = $data->query->results->results; /* YouTube output */ $youtube = '<ul id="youtube">'; foreach($results[0]->item as $r){ $cleanHTML = undoYouTubeMarkupCrimes($r->description); $youtube .= '<li>'.$cleanHTML.'</li>'; } $youtube .= '</ul>'; /* Flickr output */ $flickr = '<ul id="flickr">'; foreach($results[1]->photo as $r){ $flickr .= '<li>'. '<a href="http://www.flickr.com/photos/codepo8/'.$r->id.'/">'. '<img src="http://farm' .$r->farm . '.static.flickr.com/'. $r->server . '/' . $r->id . '_' . $r->secret . '_s.jpg" alt="'.$r->title.'"></a></li>'; } $flickr .= '</ul>'; /* Delicious output */ $delicious = '<ul id="delicious">'; foreach($results[2]->item as $r){ $delicious .= '<li><a href="'.$r->link.'">'.$r->title.'</a></li>'; } $delicious .= '</ul>'; /* Blog output */ $blog = '<ul id="blog">'; foreach($results[3]->item as $r){ $blog .= '<li><a href="'.$r->link.'">'.$r->title.'</a></li>'; } $blog .= '</ul>'; function undoYouTubeMarkupCrimes($str){ $cleaner = preg_replace('/555px/','100%',$str); $cleaner = preg_replace('/width="[^"]+"/','',$cleaner); $cleaner = preg_replace('/<tbody>/','<colgroup><col width="20%"><col width="50%"><col width="30%"></colgroup><tbody>',$cleaner); return $cleaner; } ?> What we are doing here is create a few different YQL statements and queue them together with the query.multi table. Each of these can be run inside YQL itself. Check out the YouTube, Flickr, Delicious and Blog example in the console if you don’t believe me. The benefit of using this table is that we don’t make individual requests for each query but we get all the data in one single request – which means a much better performing solution as the YQL server farm is faster on the web than our servers. We point the query to the YQL web service end point and get the resulting data using cURL. All that we need to do then is to convert the returned data to HTML lists that can be printed out inside an HTML template. Mixing, matching and using HTML as a data source This was a simple example of what YQL can do for you. Where it gets really powerful however is by mixing and matching different APIs. YQL is also a good tool to get information from HTML documents. By using the html table you can load the content of an HTML document (which gets fixed automatically by HTMLTidy) and use XPATH to filter down results to what you need. Take the following example which takes headlines from the news.bbc.co.uk homepage and runs the results through Yahoo’s Term Extractor API to give you a list of currently hot topics. select * from search.termextract where context in ( select content from html where url="http://news.bbc.co.uk" and xpath="//table[@width=800]//a" ) Try it out in the console or see the results here. In English, this means: Go to http://news.bbc.co.uk and get me the HTML Run it through HTML Tidy to clean it up. Get me only the links inside the table with an attribute of width and the value 800 Get only the content of the link and for each of the links Take the content and send it as context to the Yahoo Term Extractor API If we choose JSON-P as the output format we can use the outcome directly in JavaScript (see this demo or see its source): <ul id="hottopics"></ul> <script type="text/javascript"> function hottopics(o){ var res = o.query.results.Result, all = res.length, topics = {}, out = [], html = '', i=0; /* create hash from topics to prevent repetition */ for(i=0;i<all;i++){ topics[res[i]] = res[i]; }; for(i in topics){ out.push(i); }; html = '<li>' + out.join('</li><li>') + '</li>'; document.getElementById('hottopics').innerHTML = html; }; </script> <script type="text/javascript" src="http://query.yahooapis.com/v1/public/yql?q=select%20content%20from%20search.termextract%20where %20context%20in%20(select%20content%20from%20html%20where%20url%3D%22http%3A%2F%2Fnews.bbc.co.uk%22%20and%20xpath%3D%22%2F%2Ftable%5B%40width%3D800%5D%2F%2Fa%22)&format=json&callback=hottopics"></script> Using JSON, we can also use PHP which means the demo works for everybody – not only those with JavaScript enabled (see this demo or see its source): <ul id="hottopics"><li> <?php $url = 'http://query.yahooapis.com/v1/public/yql?q=select%20content'. '%20from%20search.termextract%20where%20context%20in'. '%20(select%20content%20from%20html%20where%20url%3D%22'. 'http%3A%2F%2Fnews.bbc.co.uk%22%20and%20xpath%3D%22%2F%2F'. 'table%5B%40width%3D800%5D%2F%2Fa%22)&format=json'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $output = curl_exec($ch); curl_close($ch); $data = json_decode($output); $topics = array_unique($data->query->results->Result); echo join('</li><li>',$topics); ?> </li></ul> Summary This article could only scratch the surface of YQL. You have not only read access to the web but you can also write to web services. For example you can update Twitter, post to your WordPress blog or shorten a URL with bit.ly. Using Open Tables you can add any web service to the YQL interface and you can even run server-side JavaScript which is for example useful to return Flickr photos as HTML or get the HTML content from a document that needs POST data. The web of data is already here, and using YQL you don’t have to be a web services expert to use it and be part of it. 2009 Christian Heilmann chrisheilmann 2009-12-17T00:00:00+00:00 https://24ways.org/2009/the-web-is-your-cms/ code
252 Turn Jekyll up to Eleventy Sometimes it pays not to over complicate things. While many of the sites we use on a daily basis require relational databases to manage their content and dynamic pages to respond to user input, for smaller, simpler sites, serving pre-rendered static HTML is usually a much cheaper — and more secure — option. The JAMstack (JavaScript, reusable APIs, and prebuilt Markup) is a popular marketing term for this way of building websites, but in some ways it’s a return to how things were in the early days of the web, before developers started tinkering with CGI scripts or Personal HomePage. Indeed, my website has always served pre-rendered HTML; first with the aid of Movable Type and more recently using Jekyll, which Anna wrote about in 2013. By combining three approachable languages — Markdown for content, YAML for data and Liquid for templating — the ergonomics of Jekyll found broad appeal, influencing the design of the many static site generators that followed. But Jekyll is not without its faults. Aside from notoriously slow build times, it’s also built using Ruby. While this is an elegant programming language, it is yet another ecosystem to understand and manage, and often alongside one we already use: JavaScript. For all my time using Jekyll, I would think to myself “this, but in Node”. Thankfully, one of Santa’s elves (Zach Leatherman) granted my Atwoodian wish and placed such a static site generator under my tree. Introducing Eleventy Eleventy is a more flexible alternative Jekyll. Besides being written in Node, it’s less strict about how to organise files and, in addition to Liquid, supports other templating languages like EJS, Pug, Handlebars and Nunjucks. Best of all, its build times are significantly faster (with future optimisations promising further gains). As content is saved using the familiar combination of YAML front matter and Markdown, transitioning from Jekyll to Eleventy may seem like a reasonable idea. Yet as I’ve discovered, there are a few gotchas. If you’ve been considering making the switch, here are a few tips and tricks to help you on your way1. Note: Throughout this article, I’ll be converting Matt Cone’s Markdown Guide site as an example. If you want to follow along, start by cloning the git repository, and then change into the project directory: git clone https://github.com/mattcone/markdown-guide.git cd markdown-guide Before you start If you’ve used tools like Grunt, Gulp or Webpack, you’ll be familiar with Node.js but, if you’ve been exclusively using Jekyll to compile your assets as well as generate your HTML, now’s the time to install Node.js and set up your project to work with its package manager, NPM: Install Node.js: Mac: If you haven’t already, I recommend installing Homebrew, a package manager for the Mac. Then in the Terminal type brew install node. Windows: Download the Windows installer from the Node.js website and follow the instructions. Initiate NPM: Ensure you are in the directory of your project and then type npm init. This command will ask you a few questions before creating a file called package.json. Like RubyGems’s Gemfile, this file contains a list of your project’s third-party dependencies. If you’re managing your site with Git, make sure to add node_modules to your .gitignore file too. Unlike RubyGems, NPM stores its dependencies alongside your project files. This folder can get quite large, and as it contains binaries compiled to work with the host computer, it shouldn’t be version controlled. Eleventy will also honour the contents of this file, meaning anything you want Git to ignore, Eleventy will ignore too. Installing Eleventy With Node.js installed and your project setup to work with NPM, we can now install Eleventy as a dependency: npm install --save-dev @11ty/eleventy If you open package.json you should see the following: … "devDependencies": { "@11ty/eleventy": "^0.6.0" } … We can now run Eleventy from the command line using NPM’s npx command. For example, to covert the README.md file to HTML, we can run the following: npx eleventy --input=README.md --formats=md This command will generate a rendered HTML file at _site/README/index.html. Like Jekyll, Eleventy shares the same default name for its output directory (_site), a pattern we will see repeatedly during the transition. Configuration Whereas Jekyll uses the declarative YAML syntax for its configuration file, Eleventy uses JavaScript. This allows its options to be scripted, enabling some powerful possibilities as we’ll see later on. We’ll start by creating our configuration file (.eleventy.js), copying the relevant settings in _config.yml over to their equivalent options: module.exports = function(eleventyConfig) { return { dir: { input: "./", // Equivalent to Jekyll's source property output: "./_site" // Equivalent to Jekyll's destination property } }; }; A few other things to bear in mind: Whereas Jekyll allows you to list folders and files to ignore under its exclude property, Eleventy looks for these values inside a file called .eleventyignore (in addition to .gitignore). By default, Eleventy uses markdown-it to parse Markdown. If your content uses advanced syntax features (such as abbreviations, definition lists and footnotes), you’ll need to pass Eleventy an instance of this (or another) Markdown library configured with the relevant options and plugins. Layouts One area Eleventy currently lacks flexibility is the location of layouts, which must reside within the _includes directory (see this issue on GitHub). Wanting to keep our layouts together, we’ll move them from _layouts to _includes/layouts, and then update references to incorporate the layouts sub-folder. We could update the layout: frontmatter property in each of our content files, but another option is to create aliases in Eleventy’s config: module.exports = function(eleventyConfig) { // Aliases are in relation to the _includes folder eleventyConfig.addLayoutAlias('about', 'layouts/about.html'); eleventyConfig.addLayoutAlias('book', 'layouts/book.html'); eleventyConfig.addLayoutAlias('default', 'layouts/default.html'); return { dir: { input: "./", output: "./_site" } }; } Determining which template language to use Eleventy will transform Markdown (.md) files using Liquid by default, but we’ll need to tell Eleventy how to process other files that are using Liquid templates. There are a few ways to achieve this, but the easiest is to use file extensions. In our case, we have some files in our api folder that we want to process with Liquid and output as JSON. By appending the .liquid file extension (i.e. basic-syntax.json becomes basic-syntax.json.liquid), Eleventy will know what to do. Variables On the surface, Jekyll and Eleventy appear broadly similar, but as each models its content and data a little differently, some template variables will need updating. Site variables Alongside build settings, Jekyll let’s you store common values in its configuration file which can be accessed in our templates via the site.* namespace. For example, in our Markdown Guide, we have the following values: title: "Markdown Guide" url: https://www.markdownguide.org baseurl: "" repo: http://github.com/mattcone/markdown-guide comments: false author: name: "Matt Cone" og_locale: "en_US" Eleventy’s configuration uses JavaScript which is not suited to storing values like this. However, like Jekyll, we can use data files to store common values. If we add our site-wide values to a JSON file inside a folder called _data and name this file site.json, we can keep the site.* namespace and leave our variables unchanged. { "title": "Markdown Guide", "url": "https://www.markdownguide.org", "baseurl": "", "repo": "http://github.com/mattcone/markdown-guide", "comments": false, "author": { "name": "Matt Cone" }, "og_locale": "en_US" } Page variables The table below shows a mapping of common page variables. As a rule, frontmatter properties are accessed directly, whereas derived metadata values (things like URLs, dates etc.) get prefixed with the page.* namespace: Jekyll Eleventy page.url page.url page.date page.date page.path page.inputPath page.id page.outputPath page.name page.fileSlug page.content content page.title title page.foobar foobar When iterating through pages, frontmatter values are available via the data object while content is available via templateContent: Jekyll Eleventy item.url item.url item.date item.date item.path item.inputPath item.name item.fileSlug item.id item.outputPath item.content item.templateContent item.title item.data.title item.foobar item.data.foobar Ideally the discrepancy between page and item variables will change in a future version (see this GitHub issue), making it easier to understand the way Eleventy structures its data. Pagination variables Whereas Jekyll’s pagination feature is limited to paginating posts on one page, Eleventy allows you to paginate any collection of documents or data. Given this disparity, the changes to pagination are more significant, but this table shows a mapping of equivalent variables: Jekyll Eleventy paginator.page pagination.pageNumber paginator.per_page pagination.size paginator.posts pagination.items paginator.previous_page_path pagination.previousPageHref paginator.next_page_path pagination.nextPageHref Filters Although Jekyll uses Liquid, it provides a set of filters that are not part of the core Liquid library. There are quite a few — more than can be covered by this article — but you can replicate them by using Eleventy’s addFilter configuration option. Let’s convert two used by our Markdown Guide: jsonify and where. The jsonify filter outputs an object or string as valid JSON. As JavaScript provides a native JSON method, we can use this in our replacement filter. addFilter takes two arguments; the first is the name of the filter and the second is the function to which we will pass the content we want to transform: // {{ variable | jsonify }} eleventyConfig.addFilter('jsonify', function (variable) { return JSON.stringify(variable); }); Jekyll’s where filter is a little more complicated in that it takes two additional arguments: the key to look for, and the value it should match: {{ site.members | where: "graduation_year","2014" }} To account for this, instead of passing one value to the second argument of addFilter, we can instead pass three: the array we want to examine, the key we want to look for and the value it should match: // {{ array | where: key,value }} eleventyConfig.addFilter('where', function (array, key, value) { return array.filter(item => { const keys = key.split('.'); const reducedKey = keys.reduce((object, key) => { return object[key]; }, item); return (reducedKey === value ? item : false); }); }); There’s quite a bit going on within this filter, but I’ll try to explain. Essentially we’re examining each item in our array, reducing key (passed as a string using dot notation) so that it can be parsed correctly (as an object reference) before comparing its value to value. If it matches, item remains in the returned array, else it’s removed. Phew! Includes As with filters, Jekyll provides a set of tags that aren’t strictly part of Liquid either. This includes one of the most useful, the include tag. LiquidJS, the library Eleventy uses, does provide an include tag, but one using the slightly different syntax defined by Shopify. If you’re not passing variables to your includes, everything should work without modification. Otherwise, note that whereas with Jekyll you would do this: <!-- page.html --> {% include include.html value="key" %} <!-- include.html --> {{ include.value }} in Eleventy, you would do this: <!-- page.html --> {% include "include.html", value: "key" %} <!-- include.html --> {{ value }} A downside of Shopify’s syntax is that variable assignments are no longer scoped to the include and can therefore leak; keep this in mind when converting your templates as you may need to make further adjustments. Tweaking Liquid You may have noticed in the above example that LiquidJS expects the names of included files to be quoted (else it treats them as variables). We could update our templates to add quotes around file names (the recommended approach), but we could also disable this behaviour by setting LiquidJS’s dynamicPartials option to false. Additionally, Eleventy doesn’t support the include_relative tag, meaning you can’t include files relative to the current document. However, LiquidJS does let us define multiple paths to look for included files via its root option. Thankfully, Eleventy allows us to pass options to LiquidJS: eleventyConfig.setLiquidOptions({ dynamicPartials: false, root: [ '_includes', '.' ] }); Collections Jekyll’s collections feature lets authors create arbitrary collections of documents beyond pages and posts. Eleventy provides a similar feature, but in a far more powerful way. Collections in Jekyll In Jekyll, creating collections requires you to add the name of your collections to _config.yml and create corresponding folders in your project. Our Markdown Guide has two collections: collections: - basic-syntax - extended-syntax These correspond to the folders _basic-syntax and _extended-syntax whose content we can iterate over like so: {% for syntax in site.extended-syntax %} {{ syntax.title }} {% endfor %} Collections in Eleventy There are two ways you can set up collections in 11ty. The first, and most straightforward, is to use the tag property in content files: --- title: Strikethrough syntax-id: strikethrough syntax-summary: "~~The world is flat.~~" tag: extended-syntax --- We can then iterate over tagged content like this: {% for syntax in collections.extended-syntax %} {{ syntax.data.title }} {% endfor %} Eleventy also allows us to configure collections programmatically. For example, instead of using tags, we can search for files using a glob pattern (a way of specifying a set of filenames to search for using wildcard characters): eleventyConfig.addCollection('basic-syntax', collection => { return collection.getFilteredByGlob('_basic-syntax/*.md'); }); eleventyConfig.addCollection('extended-syntax', collection => { return collection.getFilteredByGlob('_extended-syntax/*.md'); }); We can extend this further. For example, say we wanted to sort a collection by the display_order property in our document’s frontmatter. We could take the results of collection.getFilteredByGlob and then use JavaScript’s sort method to sort the result: eleventyConfig.addCollection('example', collection => { return collection.getFilteredByGlob('_examples/*.md').sort((a, b) => { return a.data.display_order - b.data.display_order; }); }); Hopefully, this gives you just a hint of what’s possible using this approach. Using directory data to manage defaults By default, Eleventy will maintain the structure of your content files when generating your site. In our case, that means /_basic-syntax/lists.md is generated as /_basic-syntax/lists/index.html. Like Jekyll, we can change where files are saved using the permalink property. For example, if we want the URL for this page to be /basic-syntax/lists.html we can add the following: --- title: Lists syntax-id: lists api: "no" permalink: /basic-syntax/lists.html --- Again, this is probably not something we want to manage on a file-by-file basis but again, Eleventy has features that can help: directory data and permalink variables. For example, to achieve the above for all content stored in the _basic-syntax folder, we can create a JSON file that shares the name of that folder and sits inside it, i.e. _basic-syntax/_basic-syntax.json and set our default values. For permalinks, we can use Liquid templating to construct our desired path: { "layout": "syntax", "tag": "basic-syntax", "permalink": "basic-syntax/{{ title | slug }}.html" } However, Markdown Guide doesn’t publish syntax examples at individual permanent URLs, it merely uses content files to store data. So let’s change things around a little. No longer tied to Jekyll’s rules about where collection folders should be saved and how they should be labelled, we’ll move them into a folder called _content: markdown-guide └── _content ├── basic-syntax ├── extended-syntax ├── getting-started └── _content.json We will also add a directory data file (_content.json) inside this folder. As directory data is applied recursively, setting permalink to false will mean all content in this folder and its children will no longer be published: { "permalink": false } Static files Eleventy only transforms files whose template language it’s familiar with. But often we may have static assets that don’t need converting, but do need copying to the destination directory. For this, we can use pass-through file copy. In our configuration file, we tell Eleventy what folders/files to copy with the addPassthroughCopy option. Then in the return statement, we enable this feature by setting passthroughFileCopy to true: module.exports = function(eleventyConfig) { … // Copy the `assets` directory to the compiled site folder eleventyConfig.addPassthroughCopy('assets'); return { dir: { input: "./", output: "./_site" }, passthroughFileCopy: true }; } Final considerations Assets Unlike Jekyll, Eleventy provides no support for asset compilation or bundling scripts — we have plenty of choices in that department already. If you’ve been using Jekyll to compile Sass files into CSS, or CoffeeScript into Javascript, you will need to research alternative options, options which are beyond the scope of this article, sadly. Publishing to GitHub Pages One of the benefits of Jekyll is its deep integration with GitHub Pages. To publish an Eleventy generated site — or any site not built with Jekyll — to GitHub Pages can be quite involved, but typically involves copying the generated site to the gh-pages branch or including that branch as a submodule. Alternatively, you could use a continuous integration service like Travis or CircleCI and push the generated site to your web server. It’s enough to make your head spin! Perhaps for this reason, a number of specialised static site hosts have emerged such as Netlify and Google Firebase. But remember; you can publish a static site almost anywhere! Going one louder If you’ve been considering making the switch, I hope this brief overview has been helpful. But it also serves as a reminder why it can be prudent to avoid jumping aboard bandwagons. While it’s fun to try new software and emerging technologies, doing so can require a lot of work and compromise. For all of Eleventy’s appeal, it’s only a year old so has little in the way of an ecosystem of plugins or themes. It also only has one maintainer. Jekyll on the other hand is a mature project with a large community of maintainers and contributors supporting it. I moved my site to Eleventy because the slowness and inflexibility of Jekyll was preventing me from doing the things I wanted to do. But I also had time to invest in the transition. After reading this guide, and considering the specific requirements of your project, you may decide to stick with Jekyll, especially if the output will essentially stay the same. And that’s perfectly fine! But these go to 11. Information provided is correct as of Eleventy v0.6.0 and Jekyll v3.8.5 ↩ 2018 Paul Lloyd paulrobertlloyd 2018-12-11T00:00:00+00:00 https://24ways.org/2018/turn-jekyll-up-to-eleventy/ content
16 URL Rewriting for the Fearful I think it was Marilyn Monroe who said, “If you can’t handle me at my worst, please just fix these rewrite rules, I’m getting an internal server error.” Even the blonde bombshell hated configuring URL rewrites on her website, and I think most of us know where she was coming from. The majority of website projects I work on require some amount of URL rewriting, and I find it mildly enjoyable — I quite like a good rewrite rule. I suspect you may not share my glee, so in this article we’re going to go back to basics to try to make the whole rigmarole more understandable. When we think about URL rewriting, usually that means adding some rules to an .htaccess file for an Apache web server. As that’s the most common case, that’s what I’ll be sticking to here. If you work with a different server, there’s often documentation specifically for translating from Apache’s mod_rewrite rules. I even found an automatic converter for nginx. This isn’t going to be a comprehensive guide to every URL rewriting problem you might ever have. That would take us until Christmas. If you consider yourself a trial-and-error dabbler in the HTTP 500-infested waters of URL rewriting, then hopefully this will provide a little bit more of a basis to help you figure out what you’re doing. If you’ve ever found yourself staring at the white screen of death after screwing up your .htaccess file, don’t worry. As Michael Jackson once insipidly whined, you are not alone. The basics Rewrite rules form part of the Apache web server’s configuration for a website, and can be placed in a number of different locations as part of your virtual host configuration. By far the simplest and most portable option is to use an .htaccess file in your website root. Provided your server has mod_rewrite available, all you need to do to kick things off in your .htaccess file is: RewriteEngine on The general formula for a rewrite rule is: RewriteRule URL/to/match URL/to/use/if/it/matches [options] When we talk about URL rewriting, we’re normally talking about one of two things: redirecting the browser to a different URL; or rewriting the URL internally to use a particular file. We’ll look at those in turn. Redirects Redirects match an incoming URL, and then redirect the user’s browser to a different address. These can be useful for maintaining legacy URLs if content changes location as part of a site redesign. Redirecting the old URL to the new location makes sure that any incoming links, such as those from search engines, continue to work. In 1998, Sir Tim Berners-Lee wrote that Cool URIs don’t change, encouraging us all to go the extra mile to make sure links keep working forever. I think that sometimes it’s fine to move things around — especially to correct bad URL design choices of the past — provided that you can do so while keeping those old URLs working. That’s where redirects can help. A redirect might look like this RewriteRule ^article/used/to/be/here.php$ /article/now/lives/here/ [R=301,L] Rewriting By default, web servers closely map page URLs to the files in your site. On receiving a request for http://example.com/about/history.html the server goes to the configured folder for the example.com website, and then goes into the about folder and returns the history.html file. A rewrite rule changes that process by breaking the direct relationship between the URL and the file system. “When there’s a request for /about/history.html” a rewrite rule might say, “use the file /about_section.php instead.” This opens up lots of possibilities for creative ways to map URLs to the files that know how to serve up the page. Most MVC frameworks will have a single rule to rewrite all page URLs to one single file. That file will be a script which kicks off the framework to figure out what to do to serve the page. RewriteRule ^for/this/url/$ /use/this/file.php [L] Matching patterns By now you’ll have noted the weird ^ and $ characters wrapped around the URL we’re trying to match. That’s because what we’re actually using here is a pattern. Technically, it is what’s called a Perl Compatible Regular Expression (PCRE) or simply a regex or regexp. We’ll call it a pattern because we’re not animals. What are these patterns? If I asked you to enter your credit card expiry date as MM/YY then chances are you’d wonder what I wanted your credit card details for, but you’d know that I wanted a two-digit month, a slash, and a two-digit year. That’s not a regular expression, but it’s the same idea: using some placeholder characters to define the pattern of the input you’re trying to match. We’ve already met two regexp characters. ^ Matches the beginning of a string $ Matches the end of a string When a pattern starts with ^ and ends with $ it’s to make sure we match the complete URL start to finish, not just part of it. There are lots of other ways to match, too: [0-9] Matches a number, 0–9. [2-4] would match numbers 2 to 4 inclusive. [a-z] Matches lowercase letters a–z [A-Z] Matches uppercase letters A–Z [a-z0-9] Combining some of these, this matches letters a–z and numbers 0–9 These are what we call character groups. The square brackets basically tell the server to match from the selection of characters within them. You can put any specific characters you’re looking for within the brackets, as well as the ranges shown above. However, all these just match one single character. [0-9] would match 8 but not 84 — to match 84 we’d need to use [0-9] twice. [0-9][0-9] So, if we wanted to match 1984 we could to do this: [0-9][0-9][0-9][0-9] …but that’s getting silly. Instead, we can do this: [0-9]{4} That means any character between 0 and 9, four times. If we wanted to match a number, but didn’t know how long it might be (for example, a database ID in the URL) we could use the + symbol, which means one or more. [0-9]+ This now matches 1, 123 and 1234567. Putting it into practice Let’s say we need to write a rule to match article URLs for this website, and to rewrite them to use /article.php under the hood. The articles all have URLs like this: 2013/article-title/ They start with a year (from 2005 up to 2013, currently), a slash, and then have a URL-safe version of the article title (a slug), ending in a slash. We’d match it like this: ^[0-9]{4}/[a-z0-9-]+/$ If that looks frightening, don’t worry. Breaking it down, from the start of the URL (^) we’re looking for four numbers ([0-9]{4}). Then a slash — that’s just literal — and then anything lowercase a–z or 0–9 or a dash ([a-z0-9-]) one or more times (+), ending in a slash (/$). Putting that into a rewrite rule, we end up with this: RewriteRule ^[0-9]{4}/[a-z0-9-]+/$ /article.php We’re getting close now. We can match the article URLs and rewrite them to use article.php. Now we just need to make sure that article.php knows which article it’s supposed to display. Capturing groups, and replacements When rewriting URLs you’ll often want to take important parts of the URL you’re matching and pass them along to the script that handles the request. That’s usually done by adding those parts of the URL on as query string arguments. For our example, we want to make sure that article.php knows the year and the article title we’re looking for. That means we need to call it like this: /article.php?year=2013&slug=article-title To do this, we need to mark which parts of the pattern we want to reuse in the destination. We do this with round brackets or parentheses. By placing parentheses around parts of the pattern we want to reuse, we create what’s called a capturing group. To capture an important part of the source URL to use in the destination, surround it in parentheses. Our pattern now looks like this, with parentheses around the parts that match the year and slug, but ignoring the slashes: ^([0-9]{4})/([a-z0-9-]+)/$ To use the capturing groups in the destination URL, we use the dollar sign and the number of the group we want to use. So, the first capturing group is $1, the second is $2 and so on. (The $ is unrelated to the end-of-pattern $ we used before.) RewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 The value of the year capturing group gets used as $1 and the article title slug is $2. Had there been a third group, that would be $3 and so on. In regexp parlance, these are called back-references as they refer back to the pattern. Options Several brain-taxing minutes ago, I mentioned some options as the final part of a rewrite rule. There are lots of options (or flags) you can set to change how the rule is processed. The most useful (to my mind) are: R=301 Perform an HTTP 301 redirect to send the user’s browser to the new URL. A status of 301 means a resource has moved permanently and so it’s a good way of both redirecting the user to the new URL, and letting search engines know to update their indexes. L Last. If this rule matches, don’t bother processing the following rules. Options are set in square brackets at the end of the rule. You can set multiple options by separating them with commas: RewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 [L] or RewriteRule ^about/([a-z0-9-]+).jsp/$ /about/$1/ [R=301,L] Common pitfalls Once you’ve built up a few rewrite rules, things can start to go wrong. You may have been there: a rule which looks perfectly good is somehow not matching. One common reason for this is hidden behind that [L] flag. L for Last is a useful option to tell the rewrite engine to stop once the rule has been matched. This is what it does — the remaining rules in the .htaccess file are then ignored. However, once a URL has been rewritten, the entire set of rules are then run again on the new URL. If the new URL matches any of the rules, that too will be rewritten and on it goes. One way to avoid this problem is to keep your ‘real’ pages under a folder path that will never match one of your rules, or that you can exclude from the rewrite rules. Useful snippets I find myself reusing the same few rules over and over again, just with minor changes. Here are some useful examples to refer back to. Excluding a directory As mentioned above, if you’re rewriting lots of fancy URLs to a collection of real files it can be helpful to put those files in a folder and exclude it from rewrite rules. This helps solve the issue of rewrite rules reapplying to your newly rewritten URL. To exclude a directory, put a rule like this at the top of your file, before your other rules. Our files are in a folder called _source, the dash in the rule means do nothing, and the L flag means the following rules won’t be applied. RewriteRule ^_source - [L] This is also useful for excluding things like CMS folders from your website’s rewrite rules RewriteRule ^perch - [L] Adding or removing www from the domain Some folk like to use a www and others don’t. Usually, it’s best to pick one and go with it, and redirect the one you don’t want. On this site, we don’t use www.24ways.org so we redirect those requests to 24ways.org. This uses a RewriteCond which is like an if for a rewrite rule: “If this condition matches, then apply the following rule.” In this case, it’s if the HTTP HOST (or domain name, basically) matches this pattern, then redirect everything: RewriteCond %{HTTP_HOST} ^www.24ways.org$ [NC] RewriteRule ^(.*)$ http://24ways.org/$1 [R=301,L] The [NC] flag means ‘no case’ — the match is case-insensitive. The dots in the domain are escaped with a backslash, as a dot is a regular expression character which means match anything, so we escape it because we literally mean a dot in this instance. Removing file extensions Sometimes all you need to do to tidy up a URL is strip off the technology-specific file extension, so that /about/history.php becomes /about/history. This is easily achieved with the help of some more rewrite conditions. RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^(.+)$ $1.php [L,QSA] This says if the file being asked for isn’t a file (!-f) and if it isn’t a directory (!-d) and if the file name plus .php is an actual file (-f) then rewrite by adding .php on the end. The QSA flag means ‘query string append’: append the existing query string onto the rewritten URL. It’s these sorts of more generic catch-all rules that you need to watch out for when your .htaccess gets rerun after a successful match. Without care they can easily rematch the newly rewritten URL. Logging for when it all goes wrong Although not possible within your .htaccess file, if you have access to your Apache configuration files you can enable rewrite logging. This can be useful to track down where a rule is going wrong, if it’s matching incorrectly or failing to match. It also gives you an overview of the amount of work being done by the rewrite engine, enabling you to rearrange your rules and maximise performance. RewriteEngine On RewriteLog "/full/system/path/to/rewrite.log" RewriteLogLevel 5 To be doubly clear: this will not work from an .htaccess file — it needs to be added to the main Apache configuration files. (I sometimes work using MAMP PRO locally on my Mac, and this can be pasted into the snappily named Customized virtual host general settings box in the Advanced tab for your site.) The white screen of death One of the most frustrating things when working with rewrite rules is that when you make a mistake it can result in the server returning an HTTP 500 Internal Server Error. This in itself isn’t an error message, of course. It’s more of a notification that an error has occurred. The real error message can usually be found in your Apache error log. If you have access to your server logs, check the Apache error log and you’ll usually find a much more descriptive error message, pointing you towards your mistake. (Again, if using MAMP PRO, go to Server, Apache and the View Log button.) In conclusion Rewriting URLs can be a bear, but the advantages are clear. Keeping a tidy URL structure, disconnected from the technology or file structure of your site can result in URLs that are easier to use and easier to maintain into the future. If you’re redesigning a site, remember that cool URIs don’t change, so budget some time to make sure that any content you move has a rewrite rule associated with it to keep any links working. Further reading To find out more about URL rewriting and perhaps even learn more about regular expressions, I can recommend the following resources. From the horse’s mouth, the Apache mod_rewrite documentation Particularly useful with that documentation is the RewriteRule Flags listing You may wish to don sunglasses to follow the otherwise comprehensive Regular-Expressions.info tutorial Friend of 24 ways, Neil Crosby has a mod_rewrite Beginner’s Guide which I’ve found handy over the years. As noted at the start, this isn’t a fully comprehensive guide, but I hope it’s useful in finding your feet with a powerful but sometimes annoying technology. Do you have useful snippets you often use on projects? Feel free to share them in the comments. 2013 Drew McLellan drewmclellan 2013-12-01T00:00:00+00:00 https://24ways.org/2013/url-rewriting-for-the-fearful/ code
49 Universal React One of the libraries to receive a huge amount of focus in 2015 has been ReactJS, a library created by Facebook for building user interfaces and web applications. More generally we’ve seen an even greater rise in the number of applications built primarily on the client side with most of the logic implemented in JavaScript. One of the main issues with building an app in this way is that you immediately forgo any customers who might browse with JavaScript turned off, and you can also miss out on any robots that might visit your site to crawl it (such as Google’s search bots). Additionally, we gain a performance improvement by being able to render from the server rather than having to wait for all the JavaScript to be loaded and executed. The good news is that this problem has been recognised and it is possible to build a fully featured client-side application that can be rendered on the server. The way in which these apps work is as follows: The user visits www.yoursite.com and the server executes your JavaScript to generate the HTML it needs to render the page. In the background, the client-side JavaScript is executed and takes over the duty of rendering the page. The next time a user clicks, rather than being sent to the server, the client-side app is in control. If the user doesn’t have JavaScript enabled, each click on a link goes to the server and they get the server-rendered content again. This means you can still provide a very quick and snappy experience for JavaScript users without having to abandon your non-JS users. We achieve this by writing JavaScript that can be executed on the server or on the client (you might have heard this referred to as isomorphic) and using a JavaScript framework that’s clever enough handle server- or client-side execution. Currently, ReactJS is leading the way here, although Ember and Angular are both working on solutions to this problem. It’s worth noting that this tutorial assumes some familiarity with React in general, its syntax and concepts. If you’d like a refresher, the ReactJS docs are a good place to start.  Getting started We’re going to create a tiny ReactJS application that will work on the server and the client. First we’ll need to create a new project and install some dependencies. In a new, blank directory, run: npm init -y npm install --save ejs express react react-router react-dom That will create a new project and install our dependencies: ejs is a templating engine that we’ll use to render our HTML on the server. express is a small web framework we’ll run our server on. react-router is a popular routing solution for React so our app can fully support and respect URLs. react-dom is a small React library used for rendering React components. We’re also going to write all our code in ECMAScript 6, and therefore need to install BabelJS and configure that too. npm install --save-dev babel-cli babel-preset-es2015 babel-preset-react Then, create a .babelrc file that contains the following: { "presets": ["es2015", "react"] } What we’ve done here is install Babel’s command line interface (CLI) tool and configured it to transform our code from ECMAScript 6 (or ES2015) to ECMAScript 5, which is more widely supported. We’ll need the React transforms when we start writing JSX when working with React. Creating a server For now, our ExpressJS server is pretty straightforward. All we’ll do is render a view that says ‘Hello World’. Here’s our server code: import express from 'express'; import http from 'http'; const app = express(); app.use(express.static('public')); app.set('view engine', 'ejs'); app.get('*', (req, res) => { res.render('index'); }); const server = http.createServer(app); server.listen(3003); server.on('listening', () => { console.log('Listening on 3003'); }); Here we’re using ES6 modules, which I wrote about on 24 ways last year, if you’d like a reminder. We tell the app to render the index view on any GET request (that’s what app.get('*') means, the wildcard matches any route). We now need to create the index view file, which Express expects to be defined in views/index.ejs: <!DOCTYPE html> <html> <head> <title>My App</title> </head> <body> Hello World </body> </html> Finally, we’re ready to run the server. Because we installed babel-cli earlier we have access to the babel-node executable, which will transform all your code before running it through node. Run this command: ./node_modules/.bin/babel-node server.js And you should now be able to visit http://localhost:3003 and see ‘Hello World’ right there: Building the React app Now we’ll build the React application entirely on the server, before adding the client-side JavaScript right at the end. Our app will have two routes, / and /about which will both show a small amount of content. This will demonstrate how to use React Router on the server side to make sure our React app plays nicely with URLs. Firstly, let’s update views/index.ejs. Our server will figure out what HTML it needs to render, and pass that into the view. We can pass a value into our view when we render it, and then use EJS syntax to tell it to output that data. Update the template file so the body looks like so: <body> <%- markup %> </body> Next, we’ll define the routes we want our app to have using React Router. For now we’ll just define the index route, and not worry about the /about route quite yet. We could define our routes in JSX, but I think for server-side rendering it’s clearer to define them as an object. Here’s what we’re starting with: const routes = { path: '', component: AppComponent, childRoutes: [ { path: '/', component: IndexComponent } ] } These are just placed at the top of server.js, after the import statements. Later we’ll move these into a separate file, but for now they are fine where they are. Notice how I define first that the AppComponent should be used at the '' path, which effectively means it matches every single route and becomes a container for all our other components. Then I give it a child route of /, which will match the IndexComponent. Before we hook these routes up with our server, let’s quickly define components/app.js and components/index.js. app.js looks like so: import React from 'react'; export default class AppComponent extends React.Component { render() { return ( <div> <h2>Welcome to my App</h2> { this.props.children } </div> ); } } When a React Router route has child components, they are given to us in the props under the children key, so we need to include them in the code we want to render for this component. The index.js component is pretty bland: import React from 'react'; export default class IndexComponent extends React.Component { render() { return ( <div> <p>This is the index page</p> </div> ); } } Server-side routing with React Router Head back into server.js, and firstly we’ll need to add some new imports: import React from 'react'; import { renderToString } from 'react-dom/server'; import { match, RoutingContext } from 'react-router'; import AppComponent from './components/app'; import IndexComponent from './components/index'; The ReactDOM package provides react-dom/server which includes a renderToString method that takes a React component and produces the HTML string output of the component. It’s this method that we’ll use to render the HTML from the server, generated by React. From the React Router package we use match, a function used to find a matching route for a URL; and RoutingContext, a React component provided by React Router that we’ll need to render. This wraps up our components and provides some functionality that ties React Router together with our app. Generally you don’t need to concern yourself about how this component works, so don’t worry too much. Now for the good bit: we can update our app.get('*') route with the code that matches the URL against the React routes: app.get('*', (req, res) => { // routes is our object of React routes defined above match({ routes, location: req.url }, (err, redirectLocation, props) => { if (err) { // something went badly wrong, so 500 with a message res.status(500).send(err.message); } else if (redirectLocation) { // we matched a ReactRouter redirect, so redirect from the server res.redirect(302, redirectLocation.pathname + redirectLocation.search); } else if (props) { // if we got props, that means we found a valid component to render // for the given route const markup = renderToString(<RoutingContext {...props} />); // render `index.ejs`, but pass in the markup we want it to display res.render('index', { markup }) } else { // no route match, so 404. In a real app you might render a custom // 404 view here res.sendStatus(404); } }); }); We call match, giving it the routes object we defined earlier and req.url, which contains the URL of the request. It calls a callback function we give it, with err, redirectLocation and props as the arguments. The first two conditionals in the callback function just deal with an error occuring or a redirect (React Router has built in redirect support). The most interesting bit is the third conditional, else if (props). If we got given props and we’ve made it this far it means we found a matching component to render and we can use this code to render it: ... } else if (props) { // if we got props, that means we found a valid component to render // for the given route const markup = renderToString(<RoutingContext {...props} />); // render `index.ejs`, but pass in the markup we want it to display res.render('index', { markup }) } else { ... } The renderToString method from ReactDOM takes that RoutingContext component we mentioned earlier and renders it with the properties required. Again, you need not concern yourself with what this specific component does or what the props are. Most of this is data that React Router provides for us on top of our components. Note the {...props}, which is a neat bit of JSX syntax that spreads out our object into key value properties. To see this better, note the two pieces of JSX code below, both of which are equivalent: <MyComponent a="foo" b="bar" /> // OR: const props = { a: "foo", b: "bar" }; <MyComponent {...props} /> Running the server again I know that felt like a lot of work, but the good news is that once you’ve set this up you are free to focus on building your React components, safe in the knowledge that your server-side rendering is working. To check, restart the server and head to http://localhost:3003 once more. You should see it all working! Refactoring and one more route Before we move on to getting this code running on the client, let’s add one more route and do some tidying up. First, move our routes object out into routes.js: import AppComponent from './components/app'; import IndexComponent from './components/index'; const routes = { path: '', component: AppComponent, childRoutes: [ { path: '/', component: IndexComponent } ] } export { routes }; And then update server.js. You can remove the two component imports and replace them with: import { routes } from './routes'; Finally, let’s add one more route for ./about and links between them. Create components/about.js: import React from 'react'; export default class AboutComponent extends React.Component { render() { return ( <div> <p>A little bit about me.</p> </div> ); } } And then you can add it to routes.js too: import AppComponent from './components/app'; import IndexComponent from './components/index'; import AboutComponent from './components/about'; const routes = { path: '', component: AppComponent, childRoutes: [ { path: '/', component: IndexComponent }, { path: '/about', component: AboutComponent } ] } export { routes }; If you now restart the server and head to http://localhost:3003/about` you’ll see the about page! For the finishing touch we’ll use the React Router link component to add some links between the pages. Edit components/app.js to look like so: import React from 'react'; import { Link } from 'react-router'; export default class AppComponent extends React.Component { render() { return ( <div> <h2>Welcome to my App</h2> <ul> <li><Link to='/'>Home</Link></li> <li><Link to='/about'>About</Link></li> </ul> { this.props.children } </div> ); } } You can now click between the pages to navigate. However, everytime we do so the requests hit the server. Now we’re going to make our final change, such that after the app has been rendered on the server once, it gets rendered and managed in the client, providing that snappy client-side app experience. Client-side rendering First, we’re going to make a small change to views/index.ejs. React doesn’t like rendering directly into the body and will give a warning when you do so. To prevent this we’ll wrap our app in a div: <body> <div id="app"><%- markup %></div> <script src="build.js"></script> </body> I’ve also added in a script tag to build.js, which is the file we’ll generate containing all our client-side code. Next, create client-render.js. This is going to be the only bit of JavaScript that’s exclusive to the client side. In it we need to pull in our routes and render them to the DOM. import React from 'react'; import ReactDOM from 'react-dom'; import { Router } from 'react-router'; import { routes } from './routes'; import createBrowserHistory from 'history/lib/createBrowserHistory'; ReactDOM.render( <Router routes={routes} history={createBrowserHistory()} />, document.getElementById('app') ) The first thing you might notice is the mention of createBrowserHistory. React Router is built on top of the history module, a module that listens to the browser’s address bar and parses the new location. It has many modes of operation: it can keep track using a hashbang, such as http://localhost/#!/about (this is the default), or you can tell it to use the HTML5 history API by calling createBrowserHistory, which is what we’ve done. This will keep the URLs nice and neat and make sure the client and the server are using the same URL structure. You can read more about React Router and histories in the React Router documentation. Finally we use ReactDOM.render and give it the Router component, telling it about all our routes, and also tell ReactDOM where to render, the #app element. Generating build.js We’re actually almost there! The final thing we need to do is generate our client side bundle. For this we’re going to use webpack, a module bundler that can take our application, follow all the imports and generate one large bundle from them. We’ll install it and babel-loader, a webpack plugin for transforming code through Babel. npm install --save-dev webpack babel-loader To run webpack we just need to create a configuration file, called webpack.config.js. Create the file in the root of our application and add the following code: var path = require('path'); module.exports = { entry: path.join(process.cwd(), 'client-render.js'), output: { path: './public/', filename: 'build.js' }, module: { loaders: [ { test: /.js$/, loader: 'babel' } ] } } Note first that this file can’t be written in ES6 as it doesn’t get transformed. The first thing we do is tell webpack the main entry point for our application, which is client-render.js. We use process.cwd() because webpack expects an exact location – if we just gave it the string ‘client-render.js’, webpack wouldn’t be able to find it. Next, we tell webpack where to output our file, and here I’m telling it to place the file in public/build.js. Finally we tell webpack that every time it hits a file that ends in .js, it should use the babel-loader plugin to transform the code first. Now we’re ready to generate the bundle! ./node_modules/.bin/webpack This will take a fair few seconds to run (on my machine it’s about seven or eight), but once it has it will have created public/build.js, a client-side bundle of our application. If you restart your server once more you’ll see that we can now navigate around our application without hitting the server, because React on the client takes over. Perfect! The first bundle that webpack generates is pretty slow, but if you run webpack -w it will go into watch mode, where it watches files for changes and regenerates the bundle. The key thing is that it only regenerates the small pieces of the bundle it needs, so while the first bundle is very slow, the rest are lightning fast. I recommend leaving webpack constantly running in watch mode when you’re developing. Conclusions First, if you’d like to look through this code yourself you can find it all on GitHub. Feel free to raise an issue there or tweet me if you have any problems or would like to ask further questions. Next, I want to stress that you shouldn’t use this as an excuse to build all your apps in this way. Some of you might be wondering whether a static site like the one we built today is worth its complexity, and you’d be right. I used it as it’s an easy example to work with but in the future you should carefully consider your reasons for wanting to build a universal React application and make sure it’s a suitable infrastructure for you. With that, all that’s left for me to do is wish you a very merry Christmas and best of luck with your React applications! 2015 Jack Franklin jackfranklin 2015-12-05T00:00:00+00:00 https://24ways.org/2015/universal-react/ code
96 Unwrapping the Wii U Browser The Wii U was released on 18 November 2012 in the US, and 30 November in the UK. It’s the first eighth generation home console, the first mainstream second-screen device, and it has some really impressive browser specs. Consoles are not just for games now: they’re marketed as complete entertainment solutions. Internet connectivity and browser functionality have gone from a nice-to-have feature in game consoles to a selling point. In Nintendo’s case, they see it as a challenge to design an experience that’s better than browsing on a desktop. Let’s make a browser that users can use on a daily basis, something that can really handle everything we’ve come to expect from a browser and do it more naturally. Sasaki – Iwata Asks on Nintendo.com With 11% of people using console browsers to visit websites, it’s important to consider these devices right from the start of projects. Browsing the web on a TV or handheld console is a very different experience to browsing on a desktop or a mobile phone, and has many usability implications. Console browser testing When I’m testing a console browser, one of the first things I do is run Niels Leenheer’s HTML5 test and Lea Verou’s CSS3 test. I use these benchmarks as a rough comparison of the standards each browser supports. In October, IE9 came out for the Xbox 360, scoring 120/500 in the HTML5 test and 32% in the CSS3 test. The PS Vita also had an update to its browser in recent weeks, jumping from 58/500 to 243/500 in the HTML5 test, and 32% to 55% in the CSS3 test. Manufacturers have been stepping up their game, trying to make their browsing experiences better. To give you an idea of how the Wii U currently compares to other devices, here are the test results of the other TV consoles I’ve tested. I’ve written more in-depth notes on TV and portable console browsers separately. Year of releaseHTML5 scoreCSS3 scoreNotes Wii U2012258/50048%Runs a Netfront browser (WebKit). Wii200689/500Wouldn’t runRuns an Opera browser. PS3200668/50038%Runs a Netfront browser (WebKit). Xbox 3602005120/50032%A browser for the Xbox (IE9) was only recently released in October 2012. The Kinect provides voice and gesture support. There’s also SmartGlass, a second-screen app for platforms including Android and iOS. The Wii U browser is Nintendo’s fifth attempt at a console browser. Based on these tests, it’s already looking promising. Why console browsers used to suck It takes a lot of system memory to run a good browser, and the problem of older consoles is that they don’t have much memory available. The original Nintendo DS needs a memory expansion pack just to run the browser, because the 4MB it has on board isn’t enough. I noticed that even on newer devices, some sites fail to load because the system runs out of memory. The Wii came out six years ago with an Opera browser. Still being used today and with such low resources available, the latest browser features can’t reasonably be supported. There’s also pressure to add features such as tabs, and enable gamers to use the browser while a game is paused. Nintendo’s browser team have the advantage of higher specs to play with on their new console (1GB of memory dedicated to games, 1GB for the system), which makes it easier to support the latest standards. But it’s still a challenge to fit everything in. …even though we have more memory, the amount of memory we can use for the browser is limited compared to a PC, so we’ve worked in ways that efficiently allocates the available memory per tab. To work on this, the experience working on the browser for the Nintendo 3DS system under a limited memory constraint helped us greatly. Sasaki – Iwata Asks on Nintendo.com In the box The Wii U consists of a console unit which plugs into a TV (the first to support HD), and a wireless controller known as a gamepad. The gamepad is a lot bigger than typical TV console controllers, and it has a touchscreen on the front. The touchscreen is resistive, responding to pressure rather than electrical current. It’s intended to be used with a stylus (provided) but fingers can be used. It might look a bit like one, but the gamepad isn’t a portable console designed to be taken out like the PS Vita. The gamepad can be used as a standalone screen with the TV switched off, as long as it’s within range of the console unit – it basically piggybacks off it. It’s surprisingly lightweight for its size. It has a wealth of detectors including 9-axis control. Sensors wake the device from sleep when it’s picked up. There’s also a camera on the front, and a headphone port and speakers, with audio coming through both the TV and the gamepad giving a surround sound feel. Up to six tabs can be opened at once, and the browser can be used while games are paused. There’s a really nice little feature here – the current game’s name is saved as a search option, so it’s really quick to look up contextual content such as walk-throughs. Controls Only one gamepad can be used to control the browser, but if there are Wiimotes connected, they can be used as pointers. This doesn’t let the user do anything except point (they each get a little hand icon with a number on it displayed on the screen), but it’s interesting that multiple people can be interacting with a site at once. See a bigger version The gamepad can also be used as a simple TV remote control, with basic functions such as bringing up the programme guide, adjusting volume and changing channel. I found the simplified interface much more usable than a full-featured remote control. I’m used to scrolling being sluggish on consoles, but the Wii U feels almost as snappy as a desktop browser. Sites load considerably faster compared with others I’ve tested. Tilt-scroll Holding down ZL and ZR while tilting the screen activates an Instapaper-style tilt to scroll for going up and down the page quickly, useful for navigating very long pages. Second screen The TV mirrors most of what’s on the gamepad, although the TV screen just displays the contents of the browser window, while the gamepad displays the site along with the browser toolbar. When the user with the gamepad is typing, the keyboard is hidden from the TV screen – there’s just a bit of text at the top indicating what’s happening on the gamepad. Pressing X draws an on-screen curtain over the TV, hiding the content that’s on the gamepad from the TV. Pressing X again opens the curtains, revealing what’s on the gamepad. Holding the button down plays a drumroll before it’s released and the curtains are opened. I can imagine this being used in meetings as a fun presentation tool. In a sense, browsing is a personal activity, but you get the idea that people will be coming and going through the room. When I first saw the curtain function, it made a huge impression on me. I walked around with it all over the company saying, “They’ve really come up with something amazing!” Iwata – Iwata Asks on Nintendo.com Text Writing text Unlike the capacitive screens on smartphones, the Wii U’s resistive screen needs to be pressed harder than you’re probably used to for registering a touch event. The gamepad screen is big, which makes it much easier to type on this device than other handheld consoles, even without the stylus. It’s still more fiddly than a full-sized keyboard though. When you’re designing forms, consider the extra difficulty console users experience. Although TV screens are physically big, they are typically viewed from further away than desktop screens. This makes readability an issue, so Nintendo have provided not one, but four ways to zoom in and out: Double-tapping on the screen. Tapping the on-screen zoom icons in the browser toolbar. Pressing the + and - buttons on the device. Moving the right analogue stick up and down. As well as making it easy to zoom in and out, Nintendo have done a few other things to improve the reading experience on the TV. System font One thing you’ll notice pretty quickly is that the browser lacks all the fonts we’re used to falling back to. Serif fonts are replaced with the system’s sans-serif font. I couldn’t get Typekit’s font loading method to work but Fontdeck, which works slightly differently, does display custom fonts. The system font has been optimised for reading at a distance and is easy to distinguish because the lowercase e has a quirky little tilt. Don’t lose :focus Using the D-pad to navigate is similar to using a keyboard. Individual links are focused on, with a blue outline drawn around them. The recently redesigned An Event Apart site is an example that improves the experience for keyboard and D-pad users. They’ve added a yellow background colour to links on focus. It feels nicer than the default blue outline on its own. Media This year, television overtook PCs as the primary way to watch online video content. TV is the natural environment for video, and 42% of online TVs in the US are connected to the internet via a console. Unfortunately, the <video> tag isn’t supported in most console browsers, and those that have Flash installed often have such an old version that the video won’t play. I suspect this has been a big driver in getting console browsers to support web standards. The Wii U is designed with video content in mind. It doesn’t support Flash but it does support the HTML5 <video> tag. Some video formats can’t be played, but those that are supported bring up an optimised interface with a custom scrub bar. This is where the device switches from mirroring the TV to being a second screen. The full-screen video is displayed on the TV, and the interface on the gamepad. The really clever bit is that while a video is playing, the gamepad user can keep the video playing on the TV screen while searching for another video or browsing the web. This is the same for images too. On the left, the video is being shown full-screen on the TV and gamepad. Only the gamepad gets the scrub bar. Clicking the slide up/down button (circled) lets the gamepad user browse the web while the video on the TV continues to play full-screen, as shown in the image on the right. There’s support for SVG images, and they look great on a high-definition TV screen. However, there’s currently no way to save or download files. Preparing for console users I wasn’t expecting to be quite as impressed as I am by this browser. It’s encouraging to see console makers investing time into improving the experience as well as the standards support. In the same way there was an explosion in mobile browser use as the experience got better, I’m sure we’ll see the same with console browsers as the experience improves. The value of detection Consoles offer a range of inputs including gesture, voice and controller buttons. That means we have to think about more diverse methods of input than just touch and click. This is where I could tell you to add some detection methods such as user agent string sniffing to target a different experience for console users. But the majority of the time, that really isn’t necessary. TV console browsers are getting a lot better at compensating for the living room environment, and they’re designed to work with websites that haven’t been optimised for this context. Rather than tighten our grip on optimising experiences for every device out there, we’ve got to be pragmatic. There are so many new devices coming out every week, our designs need to be future-proof rather than fixed to a particular device in time. Even fuzzy device detection isn’t reliable – the PS Vita declares itself to be mobile, a mobile device and a Kindle Fire tablet, while the two DS devices state they’re neither mobile nor mobile phones nor tablets, but computers. They’re weird outliers, but they’re still important devices to consider. Thinking broadly about how our designs will be interacted with and viewed on a TV screen can help improve that experience for everyone. This is about accessibility. Considering how someone uses a site with a D-pad, we can improve the experience for keyboard users. When we think about colour contrast and text legibility on TV screens, we can apply that for anyone who reads content on the web. So why just offer this to the TV users? Playing with the browser …we want to prove to them through this Wii U Internet Browser that browsing itself can be an entertainment. Iwata – Iwata Asks on Nintendo.com Although I’m cautious about designing experiences for specific devices, it’s fun to experiment with the technology available. Nintendo have promised web developers access to the Wii U’s buttons and sensors. There’s already some JavaScript documentation, and a demo for you to try. If you’re interested in making your own games, thanks to web standards, a lot of HTML5 games work already on the device. Matt Hackett wrote up his experience of testing the game he built, and he talks about some of features the browser lacks. There’s certainly an incentive there for console manufacturers to improve their HTML5 support so more games can be played in their browser. What excites me about consoles is that it’s like looking at what might be available to us in future browsers. As well as thinking about how our sites work on small screens, we should also consider big screens. We’re already figuring out how images should work at different screen widths and connection speeds, but we’ve also got some interesting challenges ahead of us catering for second screen experiences and 3D-enabled devices. So, this Christmas, if you’re huddled round the game console or a smart TV, give the browser in it a try. 2012 Anna Debenham annadebenham 2012-12-22T00:00:00+00:00 https://24ways.org/2012/unwrapping-the-wii-u-browser/ ux
71 Upping Your Web Security Game When I started working in web security fifteen years ago, web development looked very different. The few non-static web applications were built using a waterfall process and shipped quarterly at best, making it possible to add security audits before every release; applications were deployed exclusively on in-house servers, allowing Info Sec to inspect their configuration and setup; and the few third-party components used came from a small set of well-known and trusted providers. And yet, even with these favourable conditions, security teams were quickly overwhelmed and called for developers to build security in. If the web security game was hard to win before, it’s doomed to fail now. In today’s web development, every other page is an application, accepting inputs and private data from users; software is built continuously, designed to eliminate manual gates, including security gates; infrastructure is code, with servers spawned with little effort and even less security scrutiny; and most of the code in a typical application is third-party code, pulled in through open source repositories with rarely a glance at who provided them. Security teams, when they exist at all, cannot solve this problem. They are vastly outnumbered by developers, and cannot keep up with the application’s pace of change. For us to have a shot at making the web secure, we must bring security into the core. We need to give it no less attention than that we give browser compatibility, mobile design or web page load times. More broadly, we should see security as an aspect of quality, expecting both ourselves and our peers to address it, and taking pride when we do it well. Where To Start? Embracing security isn’t something you do overnight. A good place to start is by reviewing things you’re already doing – and trying to make them more secure. Here are three concrete steps you can take to get going. HTTPS Threats begin when your system interacts with the outside world, which often means HTTP. As is, HTTP is painfully insecure, allowing attackers to easily steal and manipulate data going to or from the server. HTTPS adds a layer of crypto that ensures the parties know who they’re talking to, and that the information exchanged can be neither modified nor sniffed. HTTPS is relevant to any site. If your non-HTTPS site holds opinions, reading it may get your users in trouble with employers or governments. If your users believe what you say, attackers can modify your non-HTTPS to take advantage of and abuse that trust. If you want to use new browser technologies like HTTP2 and service workers, your site will need to be HTTPS. And if you want to be discovered on the web, using HTTPS can help your Google ranking. For more details on why I think you should make the switch to HTTPS, check out this post, these slides and this video. Using HTTPS is becoming easier and cheaper. Here are a few free tools that can help: Get free and easy HTTPS delivery from Cloudflare (be sure to use “Full SSL”!) Get a free and automation-friendly certificate from Let’s Encrypt (now in open beta). Test how well your HTTPS is set up using SSLTest. Other vendors and platforms are rapidly simplifying and reducing the cost of their HTTPS offering, as demand and importance grows. Two-Factor Authentication The most sensitive data is usually stored behind a login, and the authentication process is the primary gate in front of this data. Making this process secure has many aspects, including using HTTPS when accepting credentials, having a strong password policy, never storing the password, and more. All of these are important, but the best single step to boost your authentication security is to introduce two-factor authentication (2FA). Adding 2FA usually means prompting users for an additional one-time code when logging in, which they get via SMS or a mobile app (e.g. Google Authenticator). This code is short-lived and is extremely hard for a remote attacker to guess, thus vastly reducing the risk a leaked or easily guessed password presents. The typical algorithm for 2FA is based on an IETF standard called the time-based one-time password (TOTP) algorithm, and it isn’t that hard to implement. Joel Franusic wrote a great post on implementing 2FA; modules like speakeasy make it even easier; and you can swap SMS with Google Authenticator or your own app if you prefer. If you don’t want to build 2FA support yourself, you can purchase two/multi-factor authentication services from vendors such as DuoSecurity, Auth0, Clef, Hypr and others. If implementing 2FA still feels like too much work, you can also choose to offload your entire authentication process to an OAuth-based federated login. Many companies offer this today, including Facebook, Google, Twitter, GitHub and others. These bigger players tend to do authentication well and support 2FA, but you should consider what data you’re sharing with them in the process. Tracking Known Vulnerabilities Most of the code in a modern application was actually written by third parties, and pulled into your app as frameworks, modules and libraries. While using these components makes us much more productive, along with their functionality we also adopt their security flaws. To make things worse, some of these flaws are well-known vulnerabilities, making it easy for hackers to take advantage of them in an attack. This is a real problem and happens on pretty much every platform. Do you develop in Java? In 2014, over 6% of Java modules downloaded from Maven had a known severe security issue, the typical Java applications containing 24 flaws. Are you coding in Node.js? Roughly 14% of npm packages carry a known vulnerability, and over 60% of dev shops find vulnerabilities in their code. 30% of Docker Hub containers include a high priority known security hole, and 60% of the top 100,000 websites use client-side libraries with known security gaps. To find known security issues, take stock of your dependencies and match them against language-specific lists such as Snyk’s vulnerability DB for Node.js, rubysec for Ruby, victims-db for Python and OWASP’s Dependency Check for Java. Once found, you can fix most issues by upgrading the component in question, though that may be tricky for indirect dependencies. This process is still way too painful, which means most teams don’t do it. The Snyk team and I are hoping to change that by making it as easy as possible to find, fix and monitor known vulnerabilities in your dependencies. Snyk’s wizard will help you find and fix these issues through guided upgrades and patches, and adding Snyk’s test to your continuous integration and deployment (CI/CD) will help you stay secure as your code evolves. Note that newly disclosed vulnerabilities usually impact old code – the one you’re running in production. This means you have to stay alert when new vulnerabilities are disclosed, so you can fix them before attackers can exploit them. You can do so by subscribing to vulnerability lists like US-CERT, OSVDB and NVD. Snyk’s monitor will proactively let you know about new disclosures relevant to your code, but only for Node.js for now – you can register to get updated when we expand. Securing Yourself In addition to making your application secure, you should make the contributors to that application secure – including you. Earlier this year we’ve seen attackers target mobile app developers with a malicious Xcode. The real target, however, wasn’t these developers, but rather the users of the apps they create. That you create. Securing your own work environment is a key part of keeping your apps secure, and your users from being compromised. There’s no single step that will make you fully secure, but here are a few steps that can make a big impact: Use 2FA on all the services related to the application, notably source control (e.g. GitHub), cloud platform (e.g. AWS), CI/CD, CDN, DNS provider and domain registrar. If an attacker compromises any one of those, they could modify or replace your entire application. I’d recommend using 2FA on all your personal services too. Use a password manager (e.g. 1Password, LastPass) to ensure you have a separate and complex password for each service. Some of these services will get hacked, and passwords will leak. When that happens, don’t let the attackers access your other systems too. Secure your workstation. Be careful what you download, lock your screen when you walk away, change default passwords on services you install, run antivirus software, etc. Malware on your machine can translate to malware in your applications. Be very wary of phishing. Smart attackers use ‘spear phishing’ techniques to gain access to specific systems, and can trick even security savvy users. There are even phishing scams targeting users with 2FA. Be alert to phishy emails. Don’t install things through curl <somewhere-on-the-web> | sudo bash, especially if the URL is on GitHub, meaning someone else controls it. Don’t do it on your machines, and definitely don’t do it in your CI/CD systems. Seriously. Staying secure should be important to you personally, but it’s doubly important when you have privileged access to an application. Such access makes you a way to reach many more users, and therefore a more compelling target for bad actors. A Culture of Security Using HTTPS, enabling two-factor authentication and fixing known vulnerabilities are significant steps in building security at your core. As you implement them, remember that these are just a few steps in a longer journey. The end goal is to embrace security as an aspect of quality, and accept we all share the responsibility of keeping ourselves – and our users – safe. 2015 Guy Podjarny guypodjarny 2015-12-11T00:00:00+00:00 https://24ways.org/2015/upping-your-web-security-game/ code
107 Using Google App Engine as Your Own Content Delivery Network Do you remember, years ago, when hosting was expensive, domain names were the province of the rich, and you hosted your web pages on Geocities? It seems odd to me now that there was a time when each and every geek didn’t have his own top-level domain and super hosting setup. But as the parts became more and more affordable a man could become an outcast if he didn’t have his own slightly surreal-sounding TLD. And so it will be in the future when people realise with surprise there was a time before affordable content delivery networks. A content delivery network, or CDN, is a system of servers spread around the world, serving files from the nearest physical location. Instead of waiting for a file to find its way from a server farm in Silicon Valley 8,000 kilometres away, I can receive it from London, Dublin, or Paris, cutting down the time I wait. The big names — Google, Yahoo, Amazon, et al — use CDNs for their sites, but they’ve always been far too expensive for us mere mortals. Until now. There’s a service out there ready for you to use as your very own CDN. You have the company’s blessing, you won’t need to write a line of code, and — best of all — it’s free. The name? Google App Engine. In this article you’ll find out how to set up a CDN on Google App Engine. You’ll get the development software running on your own computer, tell App Engine what files to serve, upload them to a web site, and give everyone round the world access to them. Creating your first Google App Engine project Before we do anything else, you’ll need to download the Google App Engine software development kit (SDK). You’ll need Python 2.5 too — you won’t be writing any Python code but the App Engine SDK will need it to run on your computer. If you don’t have Python, App Engine will install it for you (if you use Mac OS X 10.5 or a Linux-based OS you’ll have Python; if you use Windows you won’t). Done that? Excellent, because that’s the hardest step. The rest is plain sailing. You’ll need to choose a unique ‘application id’ — nothing more than a name — for your project. Make sure it consists only of lowercase letters and numbers. For this article I’ll use 24ways2008, but you can choose anything you like. On your computer, create a folder named after your application id. This folder can be anywhere you want: your desktop, your documents folder, or wherever you usually keep your web files. Within your new folder, create a folder called assets, and within that folder create three folders called images, css, and javascript. These three folders are the ones you’ll fill with files and serve from your content delivery network. You can have other folders too, if you like. That will leave you with a folder structure like this: 24ways2008/ assets/ css/ images/ javascript/ Now you need to put a few files in these folders, so we can later see our CDN in action. You can put anything you want in these folders, but for this example we’ll include an HTML file, a style sheet, an image, and a Javascript library. In the top-level folder (the one I’ve called 24ways2008), create a file called index.html. Fill this with any content you want. In the assets/css folder, create a file named core.css and throw in a couple of CSS rules for good measure. In the assets/images directory save any image that takes your fancy — I’ve used the silver badge from the App Engine download page. Finally, to fill the JavaScript folder, add in this jQuery library file. If you’ve got the time and the inclination, you can build a page that uses all these elements. So now we should have a set of files and folders that look something like this: 24ways2008/ assets/ index.html css/ core.css images/ appengine-silver-120x30.gif javascript/ jquery-1.2.6.min.js Which leaves us with one last file to create. This is the important one: it tells App Engine what to do with your files. It’s named app.yaml, it sits at the top-level (inside the folder I’ve named 24ways2008), and it needs to include these lines: application: 24ways2008 version: 1 runtime: python api_version: 1 handlers: - url: / static_files: assets/index.html upload: assets/index.html - url: / static_dir: assets You need to make sure you change 24ways2008 on the first line to whatever you chose as your application id, but otherwise the content of your app.yaml file should be identical. And with that, you’ve created your first App Engine project. If you want it, you can download a zip file containing my project. Testing your project As it stands, your project is ready to be uploaded to App Engine. But we couldn’t call ourselves professionals if we didn’t test it, could we? So, let’s put that downloaded SDK to good use and run the project from your own computer. One of the files you’ll find App Engine installed is named dev_appserver.py, a Python script used to simulate App Engine on your computer. You’ll find lots of information on how to do this in the documentation on the development web server, but it boils down to running the script like so (the space and the dot at the end are important): dev_appserver.py . You’ll need to run this from the command-line: Mac users can run the Terminal application, Linux users can run their favourite shell, and Windows users will need to run it via the Command Prompt (open the Start menu, choose ‘Run…’, type ‘cmd‘, and click ‘OK’). Before you run the script you’ll need to make sure you’re in the project folder — in my case, as I saved it to my desktop I can go there by typing cd ~/Desktop/24ways2008 in my Mac’s Terminal app; if you’re using Windows you can type cd "C:\Documents and Settings\username\Desktop\24ways2008" If that’s successful, you’ll see a few lines of output, the last looking something like this: INFO 2008-11-22 14:35:00,830 dev_appserver_main.py] Running application 24ways2008 on port 8080: http://localhost:8080 Now you can power up your favourite browser, point it to http://localhost:8080/, and you’ll see the page you saved as index.html. You’ll also find your CSS file at http://localhost:8080/css/core.css. In fact, anything you put inside the assets folder in the project will be accessible from this domain. You’re running our own App Engine web server! Note that no-one else will be able to see your files: localhost is a special domain that you can only see from your computer — and once you stop the development server (by pressing Control–C) you’ll not be able to see the files in your browser until you start it again. You might notice a new file has turned up in your project: index.yaml. App Engine creates this file when you run the development server, and it’s for internal App Engine use only. If you delete it there are no ill effects, but it will reappear when you next run the development server. If you’re using version control (e.g. Subversion) there’s no need to keep a copy in your repository. So you’ve tested your project and you’ve seen it working on your own machine; now all you need to do is upload your project and the world will be able to see your files too. Uploading your project If you don’t have a Google account, create one and then sign in to App Engine. Tell Google about your new project by clicking on the ‘Create an Application’ button. Enter your application id, give the application a name, and agree to the terms and conditions. That’s it. All we need do now is upload the files. Open your Mac OS X Terminal, Windows Command Prompt, or Linux shell window again, move to the project folder, and type (again, the space and the dot at the end are important): appcfg.py update . Enter your email address and password when prompted, and let App Engine do it’s thing. It’ll take no more than a few seconds, but in that time App Engine will have done the equivalent of logging in to an FTP server and copying files across. It’s fairly understated, but you now have your own project up and running. You can see mine at http://24ways2008.appspot.com/, and everyone can see yours at http://your-application-id.appspot.com/. Your files are being served up over Google’s content delivery network, at no cost to you! Benefits of using Google App Engine The benefits of App Engine as a CDN are obvious: your own server doesn’t suck up the bandwidth, while your visitors will appreciate a faster site. But there are also less obvious benefits. First, once you’ve set up your site, updating it is an absolute breeze. Each time you update a file (or a batch of files) you need only run appcfg.py to see the changes appear on your site. To paraphrase Joel Spolsky, a good web site must be able to be updated in a single step. Many designers and developers can’t make that claim, but with App Engine, you can. App Engine also allows multiple people to work on one application. If you want a friend to be able to upload files to your site you can let him do so without giving him usernames and passwords — all he needs is his own Google account. App Engine also gives you a log of all actions taken by collaborators, so you can see who’s made updates, and when. Another bonus is the simple version control App Engine offers. Do you remember the file named app.yaml you created a while back? The second line looked like this: version: 1 If you change the version number to 2 (or 3, or 4, etc), App Engine will keep a copy of the last version you uploaded. If anything goes wrong with your latest version, you can tell App Engine to revert back to that last saved version. It’s no proper version control system, but it could get you out of a sticky situation. One last thing to note: if you’re not happy using your-application-id.appspot.com as your domain, App Engine will quite happily use any domain you own. The weak points of Google App Engine In the right circumstances, App Engine can be a real boon. I run my own site using the method I’ve discussed above, and I’m very happy with it. But App Engine does have its disadvantages, most notably those discussed by Aral Balkan in his post ‘Why Google App Engine is broken and what Google must do to fix it‘. Aral found the biggest problems while using App Engine as a web application platform; I wouldn’t recommend using it as such either (at least for now) but for our purposes as a CDN for static files, it’s much more worthy. Still, App Engine has two shortcomings you should be aware of. The first is that you can’t host a file larger than one megabyte. If you want to use App Engine to host that 4.3MB download for your latest-and-greatest desktop software, you’re out of luck. The only solution is to stick to smaller files. The second problem is the quota system. Google’s own documentation says you’re allowed 650,000 requests a day and 10,000 megabytes of bandwidth in and out (20,000 megabytes in total), which should be plenty for most sites. But people have seen sites shut down temporarily for breaching quotas — in some cases after inexplicable jumps in Google’s server CPU usage. Aral, who’s seen it happen to his own sites, seemed genuinely frustrated by this, and if you measure your hits in the hundreds of thousands and don’t want to worry about uptime, App Engine isn’t for you. That said, for most of us, App Engine offers a fantastic resource: the ability to host files on Google’s own content delivery network, at no charge. Conclusion If you’ve come this far, you’ve seen how to create a Google App Engine project and host your own files on Google’s CDN. You’ve seen the great advantages App Engine offers — an excellent content delivery network, the ability to update your site with a single command, multiple authors, simple version control, and the use of your own domain — and you’ve come across some of its weaknesses — most importantly the limit on file sizes and the quota system. All that’s left to do is upload those applications — but not before you’ve finished your Christmas shopping. 2008 Matt Riggott mattriggott 2008-12-06T00:00:00+00:00 https://24ways.org/2008/using-google-app-engine-as-your-own-cdn/ process
207 Want to Break Out of Comparison Syndrome? Do a Media Detox “Comparison is the thief of joy.” —Theodore Roosevelt I grew up in an environment of perpetual creativity and inventiveness. My father Dennis built and flew experimental aircraft as a hobby. During my entire childhood, there was an airplane fuselage in the garage instead of a car. My mother Deloria was a self-taught master artisan who could quickly acquire any skills that it took to work with fabric and weaving. She could sew any garment she desired, and was able to weave intricate wall hangings just by looking at a black and white photos in magazines. My older sister Diane blossomed into a consummate fine artist who drew portraits with uncanny likeness, painted murals, and studied art and architecture. In addition, she loved good food and had a genius for cooking and baking, which converged in her creating remarkable art pieces out of cake that were incredibly delicious to boot. Yes. This was the household in which I grew up. While there were countless positives to being surrounded by people who were compelled to create, there was also a downside to it. I incessantly compared myself to my parents and older sister and always found myself lacking. It wasn’t a fair comparison, but tell that to a sensitive kid who wanted to fit in to her family by being creative as well. From my early years throughout my teens, I convinced myself that I would never understand how to build an airplane or at least be as proficient with tools as my father, the aeronautical engineer. Even though my sister was six years older than I was, I lamented that I would never be as good a visual artist as she was. And I marveled at my mother’s seemingly magical ability to make and tailor clothes and was certain that I would never attain her level of mastery. This habit of comparing myself to others grew over the years, continuing to subtly and effectively undermine my sense of self. I had almost reached an uneasy truce with my comparison habit when social media happened. As an early adopter of Twitter, I loved staying connected to people I met at tech conferences. However, as I began to realize my aspirations of being an author and a speaker, Twitter became a dreaded hall of mirrors where I only saw distorted reflections of my lack of achievement in other people’s success. Every person announcing a publishing deal caused me to drown under waves of envy over the imagined size of her or his book advance as I struggled to pay my mortgage. Every announcement I read of someone speaking at a conference led to thoughts of, “I wish I were speaking at that conference – I must not be good enough to be invited.” Twitter was fertile ground for my Inner Critic to run rampant. One day in 2011, my comparisons to people who I didn’t even know rose to a fever pitch. I saw a series of tweets that sparked a wave of self-loathing so profound that I spent the day sobbing and despondent, as I chastised myself for being a failure. I had fallen into the deep pit of Comparison Syndrome, and to return to anything close to being productive took a day or two of painstakingly clawing my way out. Comparison Syndrome Takes Deficiency Anxiety to Eleven Do any of these scenarios ring true? You frequently feel like a failure when viewing the success of others. You feel dispirited and paralyzed in moving forward with your own work because it will never measure up to what others have done. You discount your ideas because you fear that they aren’t as good as those of your colleagues or industry peers. Are you making yourself miserable by thinking thoughts like these? “I’m surrounded by people who are so good at what they do, how can I possibly measure up?” “Compared to my partner, my musical ability is childish – and music is no longer fun.” “Why haven’t I accomplished more by now? My peers are so much more successful than I am.” Unenviable Envy Many people use the terms envy and jealousy interchangeably, but they are two distinct emotions. Jealousy is the fear of losing someone to a perceived rival: a threat to an important relationship and the parts of the self that are served by that relationship. Jealousy is always about the relationship between three people. Envy is wanting what another has because of a perceived shortcoming on your part. Envy is always based on a social comparison to another.1 Envy is a reaction to the feeling of lacking something. Envy always reflects something we feel about ourselves, about how we are somehow deficient in qualities, possessions, or success.2 It’s based on a scarcity mentality: the idea that there is only so much to go around, and another person got something that should rightfully be yours.3 A syndrome is a condition characterized by a set of associated symptoms. I call it Comparison Syndrome because a perceived deficiency of some sort – in talent, accomplishments, success, skills, etc. – is what initially sparks it. While at the beginning you may merely feel inadequate, the onset of the syndrome will bring additional symptoms. Lack of self-trust and feelings of low self-worth will fuel increased thoughts of not-enoughness and blindness to your unique brilliance. If left unchecked, Deficiency Anxieties can escalate to full-blown Comparison Syndrome: a form of the Inner Critic in which we experience despair from envy and define ourselves as failures in light of another’s success. The irony is that when we focus so much on what we lack, we can’t see what we have in abundance that the other person doesn’t have. And in doing so, we block what is our birthright: our creative expression. Envy shackles our creativity, keeps us trapped in place, and prevents forward movement. The Inner Critic in the form of Comparison Syndrome caused by envy blocks us from utilizing our gifts, seeing our path clearly, and reveling in our creative power. In order to keep a grip on reality and not fall into the abyss of Comparison Syndrome, we’ll quell the compulsion to compare before it happens: we will free the mental bandwidth to turn our focus inward so we can start to see ourselves clearly. Break the Compulsion to Compare “Why compare yourself with others? No one in the entire world can do a better job of being you than you.” — Krystal Volney, poet and author At some point in time, many of us succumb to moments of feeling that we are lacking and comparing ourselves unfavorably to others. As social animals, much of our self-definition comes from comparison with others. This is how our personalities develop. We learn this behavior as children, and we grow up being compared to siblings, peers, and kids in the media. Because of this, the belief that somehow, someway, we aren’t good enough becomes deeply ingrained. The problem is that whenever we deem ourselves to be “less than,” our self-esteem suffers. This creates a negative feedback loop where negative thoughts produce strong emotions that result in self-defeating behaviors that beget more negative thoughts. Couple this cycle with the messages we get from society that only “gifted” people are creative, and it’s no wonder that many of us will fall down the rabbit hole of Comparison Syndrome like I did on that fated day while reading tweets. Comparing ourselves to others is worse than a zero-sum game, it’s a negative-sum game. No one wins, our self-esteem deteriorates, and our creative spark dies out. With effort, we can break the compulsion to compare and stop the decline into Comparison Syndrome by turning the focus of comparison inward to ourselves and appreciating who we’ve become. But first, we need to remove some of the instances that trigger our comparisons in the first place. Arrest: Stop the Triggers “Right discipline consists, not in external compulsion, but in the habits of mind which lead spontaneously to desirable rather than undesirable activities.” — Bertrand Russell, philosopher After my Twitter post meltdown, I knew had to make a change. While bolstering my sense of self was clearly a priority, I also knew that my ingrained comparison habit was too strong to resist and that I needed to instill discipline. I decided then and there to establish boundaries with social media. First, to maintain my sanity, I took this on as my mantra: “I will not compare myself to strangers on the Internet or acquaintances on Facebook.” If you find yourself sliding down the slippery slope of social media comparison, you can do the same: repeat this mantra to yourself to help put on the brakes. Second, in order to reduce my triggers, I stopped reading the tweets of the people I followed. However, I continued to be active on Twitter through sharing information, responding to mentions, crowdsourcing, and direct messaging people. It worked! The only time I’d start to slip into darkness were the rare instances when I would break my rules and look at my Twitstream. But we can do even more than calm ourselves with helpful mantras. Just like my example of modifying my use of Twitter, and more recently, of separating myself from Facebook, you can get some distance from the media that activates your comparison reflex and start creating the space for other habits that are more supportive to your being to take its place. Creative Dose: Trigger-free and Happy Purpose: To stop comparison triggers in their tracks Mindfulness is a wonderful tool, but sometimes you have to get hardcore and do as much as you can to eliminate distractions so that you can first hear your own thoughts in order to know which ones you need to focus on. Here are four steps to becoming trigger-free and happier. Step 1: Make a List Pay attention when you get the most triggered and hooked. Is it on Twitter, Facebook, Instagram, or Snapchat? Is it YouTube, TV shows, or magazines? Make list of your top triggers. My primary trigger is:______________________________________ My second trigger is:______________________________________ My third trigger is:______________________________________ Now that you have your list, you need to get an idea just how often you’re getting triggered. Step 2: Monitor It’s easy to think that we should track our activity on the computer, but these days, it’s no longer our computer use that is the culprit: most of us access social media and news from our phones. Fortunately, there are apps that will track the usage for both. Seeing just how much you consume media from either or both will show you how much of an accomplice the use of devices is to your comparison syndrome, and how much you need to modify your behavior accordingly. For tracking both computer use and tablet use, this app works great: RescueTime.com tracks app usage and sends a productivity report at the end of the week via email. For your phone, there are many for either platform.4 Although I recommend fully researching what is available and will work for you best, here are a few recommendations: For both platforms: Offtime, Breakfree, Checky For Android only: Flipd, AppDetox, QualityTime, Stay On Task For iOS only: Moment Install your app of choice, and see what you find. How much time are you spending on sites or apps that compel you to compare? Step 3: Just Say No Now that you know what your triggers are and how much you’re exposing yourself to them, it’s time to say No. Put yourself on a partial social media and/or media detox for a specified period of time; consider even going for a full media detox.5 I recommend starting with one month. To help you to fully commit, I recommend writing this down and posting it where you can see it. I, ___________________, commit to avoiding my comparison triggers of ___________________, ___________________, and ___________________ for the period of ___________________, starting on ___________________ and ending on ___________________ . To help you out, I’ve created a social media detox commitment sheet for you. Step 4: Block When I decided to reduce my use of Twitter and Facebook to break my comparison habit, initially I tried to rely solely on self-discipline, which was only moderately successful. Then I realized that I could use the power of technology to help. Don’t think you have to rely upon sheer willpower to block, or at least limit, your exposure to known triggers. If your primary access to the items that cause you to compare yourself to others is via computers and other digitalia, use these devices to help maintain your mental equilibrium. Here are some apps and browser extensions that you can use during your media detox to help keep yourself sane and stay away from sites that could throw you into a comparison tailspin. These apps are installed onto your computer: RescueTime.com works on both computer and mobile devices, and does a lot more than just prevent you from going to sites that will ruin your concentration, it will also track your apps usage and give you a productivity report at the end of the week. Focus and SelfControl (Mac-only) To go right to the source and prevent you from visiting sites through your browser, there are browser extensions. Not only can you put in the list of the URLs that are your points of weakness, but you can also usually set the times of the day you need the self-control the most. Google Chrome: StayFocusd, Strict Workflow, and Website Blocker Firefox: Idderall and Leechblock Safari: WasteNoTime and MindfulBrowsing Edge (or Explorer): Unfortunately, there are currently no website blocking extensions for these browsers. I currently use a browser extension to block me from using Facebook between 9:00am – 6:00pm. It’s been a boon for my sanity: I compare tons less. A bonus is that it’s been terrific for my productivity as well. Which tool will you use for your media detox time? Explore them all and then settle upon the one(s) that will work the best for you. Install it and put it to work. Despite the tool, you will still need to exercise discipline. Resist the urge to browse Instagram or Facebook while waiting for your morning train. You can do it! Step 5: Relax Instead of panicking from FOMO (Fear of Missing Out), take comfort from this thought: what you don’t know won’t affect you. Start embracing JOMO (Joy of Missing Out), and the process of rebuilding and maintaining your sanity. What will you do instead of consuming the media that compels you to compare? Here are some ideas: Read a book Go for a walk Have dinner with a friend Go watch a movie Learn how to play the harmonica Take an improv class Really, you could do anything. And depending on how much of your time and attention you’ve devoted to media, you could be recapturing a lot of lost moments, minutes, hours, and days. Step 6: Reconnect Use your recovered time and attention to focus on your life and reconnect with your true value-driven goals, higher aspirations, and activities that you’ve always wanted to do. This article is an excerpt from the book Banish Your Inner Critic by Denise Jacobs, and has been reprinted with permission. If you’d like to read more, you can find the book on Amazon. Shane Parrish, “Mental Model: Bias from Envy and Jealousy,” Farnam Street, accessed February 9, 2017. ↩ Parrish, “Mental Model: Bias from Envy and Jealousy.” ↩ Henrik Edberg, “How to Overcome Envy: 5 Effective Tips,” Practical Happiness Advice That Works | The Positivity Blog, accessed February 9, 2017. ↩ Jeremy Golden, “6 Apps to Stop Your Smartphone Addiction,” Inc.com, accessed February 10, 2017. ↩ Emily Nickerson, “How to Silence the Voice of Doubt,” The Muse, accessed February 8, 2017. ↩ 2017 Denise Jacobs denisejacobs 2017-12-19T00:00:00+00:00 https://24ways.org/2017/do-a-media-detox/ process
292 Watch Your Language! I’m bilingual. My first language is French. I learned English in my early 20s. Learning a new language later in life meant that I was able to observe my thought processes changing over time. It made me realize that some concepts can’t be expressed in some languages, while other languages express these concepts with ease. It also helped me understand the way we label languages. English: business. French: romance. Here’s an example of how words, or the absence thereof, can affect the way we think: In French we love everything. There’s no straightforward way to say we like something, so we just end up loving everything. I love my sisters, I love broccoli, I love programming, I love my partner, I love doing laundry (this is a lie), I love my mom (this is not a lie). I love, I love, I love. It’s no wonder French is considered romantic. When I first learned English I used the word love rather than like because I hadn’t grasped the difference. Needless to say, I’ve scared away plenty of first dates! Learning another language made me realize the limitations of my native language and revealed concepts I didn’t know existed. Without the nuances a given language provides, we fail to express what we really think. The absence of words in our vocabulary gets in the way of effectively communicating and considering ideas. When I lived in Montréal, most people in my circle spoke both French and English. I could switch between them when I could more easily express an idea in one language or the other. I liked (or should I say loved?) those conversations. They were meaningful. They were efficient. I’m quadrilingual. I code in Ruby, HTML/CSS, JavaScript, Python. In the past couple of years I have been lucky enough to write code in these languages at a massive scale. In learning Ruby, much like learning English, I discovered the strengths and limitations of not only the languages I knew but the language I was learning. It taught me to choose the right tool for the job. When I started working at Shopify, making a change to a view involved copy/pasting HTML and ERB from one view to another. The CSS was roughly structured into modules, but those modules were not responsive to different screen sizes. Our HTML was complete mayhem, and we didn’t consider accessibility. All this made editing views a laborious process. Grep. Replace all. Test. Ship it. Repeat. This wasn’t sustainable at Shopify’s scale, so the newly-formed front end team was given two missions: Make the app responsive (AKA Let’s Make This Thing Responsive ASAP) Make the view layer scalable and maintainable (AKA Let’s Build a Pattern Library… in Ruby) Let’s make this thing responsive ASAP The year was 2015. The Shopify admin wasn’t mobile friendly. Our browser support was set to IE10. We had the wind in our sails. We wanted to achieve complete responsiveness in the shortest amount of time. Our answer: container queries. It seemed like the obvious decision at the time. We would be able to set rules for each component in isolation and the component would know how to lay itself out on the page regardless of where it was rendered. It would save us a ton of development time since we wouldn’t need to change our markup, it would scale well, and we would achieve complete component autonomy by not having to worry about page layout. By siloing our components, we were going to unlock the ultimate goal of componentization, cutting the tie to external dependencies. We were cool. Writing the JavaScript handling container queries was my first contribution to Shopify. It was a satisfying project to work on. We could drop our components in anywhere and they would magically look good. It took us less than a couple weeks to push this to production and make our app mostly responsive. But with time, it became increasingly obvious that this was not as performant as we had hoped. It wasn’t performant at all. Components would jarringly jump around the page before settling in on first paint. It was only when we started using the flex-wrap: wrap CSS property to build new components that we realized we were not using the right language for the job. So we swapped out JavaScript container queries for CSS flex-wrapping. Even though flex wasn’t yet as powerful as we wanted it to be, it was still a good compromise. Our components stayed independent of the window size but took much less time to render. Best of all: they used CSS instead of relying on JavaScript for layout. In other words: we were using the wrong language to express our layout to the browser, when another language could do it much more simply and elegantly. Let’s build a pattern library… in Ruby In order to make our view layer maintainable, we chose to build a comprehensive library of helpers. This library would generate our markup from a single source of truth, allowing us to make changes system-wide, in one place. No. More. Grepping. When I joined Shopify it was a Rails shop freshly wounded by a JavaScript framework (See: Batman.js). JavaScript was like Voldemort, the language that could not be named. Because of this baggage, the only way for us to build a pattern library that would get buyin from our developers was to use Rails view helpers. And for many reasons using Ruby was the right choice for us. The time spent ramping developers up on the new UI Components would be negligible since the Ruby API felt familiar. The transition would be simple since we didn’t have to introduce any new technology to the stack. The components would be fast since they would be rendered on the server. We had a plan. We put in place a set of Rails tools to make it easy to build components, then wrote a bunch of sweet, sweet components using our shiny new tools. To document our design, content and front end patterns we put together an interactive styleguide to demonstrate how every component works. Our research and development department loved it (and still do)! We continue to roll out new components, and generally the project has been successful, though it has had its drawbacks. Since the Shopify admin is mostly made up of a huge number of forms, most of the content is static. For this reason, using server-rendered components didn’t seem like a problem at the time. With new app features increasing the amount of DOM manipulation needed on the client side, our early design decisions mean making requests to the server for each re-paint. This isn’t going to cut it. I don’t know the end of this story, because we haven’t written it yet. We’ve been exploring alternatives to our current system to facilitate the rendering of our components on the client, including React, Vue.js, and Web Components, but we haven’t determined the winner yet. Only time (and data gathering) will tell. Ruby is great but it doesn’t speak the browser’s language efficiently. It was not the right language for the job. Learning a new spoken language has had an impact on how I write code. It has taught me that you don’t know what you don’t know until you have the language to express it. Understanding the strengths and limitations of any programming language is fundamental to making good design decisions. At the end of the day, you make the best choices with the information you have. But if you still feel like you’re unable to express your thoughts to the fullest with what you know, it might be time to learn a new language. 2016 Annie-Claude Côté annieclaudecote 2016-12-10T00:00:00+00:00 https://24ways.org/2016/watch-your-language/ code
245 Web Content Accessibility Guidelines 2.1—for People Who Haven’t Read the Update Happy United Nations International Day of Persons with Disabilities 2018! The United Nations chose “Empowering persons with disabilities and ensuring inclusiveness and equality” as this year’s theme. We’ve seen great examples of that in 2018; for example, Paul Robert Lloyd has detailed how he improved the accessibility of this very website. On social media, US Congressmember-Elect Alexandria Ocasio-Cortez started using the Clipomatic app to add live captions to her Instagram live stories, conforming to success criterion 1.2.4, “Captions (Live)” of the Web Content Accessibility Guidelines (figure 1) …and British Vogue Contributing Editor Sinéad Burke has used the split-screen feature of Instagram live stories to invite an interpreter to provide live Sign Language interpretation, going above and beyond success criterion 1.2.6, “Sign Language (Prerecorded)” of the Web Content Accessibility Guidelines (figure 2). Figure 1: Screenshot of Alexandria Ocasio-Cortez’s Instagram story with live captionsFigure 2: Screenshot of Sinéad Burke’s Instagram story with Sign Language Interpretation That theme chimes with this year’s publication of the World Wide Web Consortium (W3C)’s Web Content Accessibility Guidelines (WCAG) 2.1. In last year’s “Web Content Accessibility Guidelines—for People Who Haven’t Read Them”, I mentioned the scale of the project to produce this update during 2018: “the editors have to update the guidelines to cover all the new ways that people interact with new technologies, while keeping the guidelines backwards-compatible”. The WCAG working group have added 17 success criteria to the 61 that they released way back in 2008—for context, that was 1½ years before Apple released their first iPad! These new criteria make it easier than ever for us web geeks to produce work that is more accessible to people using mobile devices and touchscreens, people with low vision, and people with cognitive and learning disabilities. Once again, let’s rip off all the legalese and ambiguous terminology like wrapping paper, and get up to date. Can your users perceive the information on your website? The first guideline has criteria that help you prevent your users from asking, “What the **** is this thing here supposed to be?” We’ve seven new criteria for this guideline. 1.3.4 Some people can’t easily change the orientation of the device that they use to browse the web, and so you should make sure that your users can use your website in portrait orientation and in landscape orientation. Consider how people slowly twirl presents that they have plucked from under the Christmas tree, to find the appropriate orientation—and expect your users to do likewise with your websites and apps. We’ve had 18½ years since John Allsopp’s revelatory Dao of Web Design enlightened us to “embrace the fact that the web doesn’t have the same constraints” as printed pages, and to “design for this flexibility”. So, even though this guideline doesn’t apply to websites where “a specific display orientation is essential,” such as a piano tutorial, always ask yourself, “What would John Allsopp do?” 1.3.5 You should help the user’s browser to automatically complete–or not complete–form fields, to save the user some time and effort. The surprisingly powerful and flexible autocomplete attribute for input elements should prove most useful here. If you’ve used microformats or microdata to mark up information about a person, the autocomplete attribute’s range of values should seem familiar. I like how the W3’s “Using HTML 5.2 autocomplete attributes” says that autocompleted values in forms help “those with dexterity disabilities who have trouble typing, those who may need more time, and anyone who wishes to reduce effort to fill out a form” (emphasis mine). Um…🙋‍♂️ 1.3.6 I like this one a lot, because it can help a huge audience to overcome difficulties that might prevent them from ever using the web. Some people have cognitive difficulties that affect their memory, focus, attention, language processing, and/or decision-making. Those users often rely on assistive technologies that present information through proprietary symbols, summaries of content, and keyboard shortcuts. You could use ARIA landmarks to identify the regions of each webpage. You could also keep an eye on the W3C’s ongoing work on Personalisation Semantics. 1.4.10 If you were to find a Nintendo Switch and “Super Mario Odyssey” under your Christmas tree, you would have many hours of enjoyably scrolling horizontally and vertically to play the game. On the other hand, if you had to zoom a webpage to 400% so that you could read the content, you might have many hours of frustratedly scrolling horizontally and vertically to read the content. Learned reader, I assume you understand the purpose and the core techniques of Responsive Web Design. I also assume you’re getting up to speed with the new Grid, Flexbox, and Box Alignment techniques for layout, and overflow-wrap. Using those skills, you should make sure that all content and functionality remain available when the browser is 320px wide, without your user needing to scroll horizontally. (For vertical text, you should make sure that all content and functionality remain available when the browser is 256px high, without your user needing to scroll vertically.) You don’t have to do this for anything that would lose meaning if you restructured it into one narrow column. That includes some images, maps, diagrams, video, games, presentations, and data tables. Remember to check how your media queries affect font size: your user might find that text becomes smaller as they zoom into the webpage. So, test this one on real devices, or—better yet—test it with real users. 1.4.11 In “Web Content Accessibility Guidelines—for People Who Haven’t Read Them”, I recommended bookmarking Lea Verou’s Contrast Ratio calculator for checking that text contrasts enough with its background (for success criteria 1.4.3 and 1.4.6), so that more people can read it more easily. For this update, you should make sure that form elements and their focus states have a 3:1 contrast ratio with the colour around them. This doesn’t apply to controls that use the browser’s default styling. Also, you should make sure that graphics that convey information have a 3:1 contrast ratio with the colour around them. 1.4.12 Some people, due to low vision or dyslexia, might need to modify the typography that you agonised over. Research indicates that you should make sure that all content and functionality would remain available if a user were to set: line height to at least 1½ × the font size; space below paragraphs to at least 2 × the font size; letter spacing to at least 0.12 × the font size; word spacing to at least 0.16 × the font size. To test this, check for text overlapping, text hiding behind other elements, or text disappearing. 1.4.13 Sometimes when visiting a website, you hover over—or tab on to—something that unleashes a newsletter subscription pop-up, some suggested “related content”, and/or a GDPR-related pop-up. On a well-designed website, you can press the Esc key on your keyboard or click a prominent “Close” button or “X” button to vanquish such intrusions. If the Esc key fails you, or if you either can’t see or can’t click the “Close” button…well, you’ll probably just close that browser tab. This situation can prove even more infuriating for users with low vision or cognitive disabilities. So, if new content appears when your user hovers over or tabs on to some element, you should make sure that: your user can dismiss that content without needing to move their pointer or tab on to some other element (this doesn’t apply to error warnings, or well-behaved content that doesn’t obscure or replace other content); the new content remains visible while your user moves their cursor over it; the new content remains visible as long as the user hovers over that element or dismisses that content—or until the new content is no longer valid. This doesn’t apply to situations such as hovering over an element’s title attribute, where the user’s browser controls the display of the content that appears. Can users operate the controls and links on your website? The second guideline has criteria that help you prevent your users from asking, “How the **** does this thing work?” We’ve nine new criteria for this guideline. 2.1.4 Some websites offer keyboard shortcuts for users. For example, the keyboard shortcuts for Gmail allow the user to press the ⇧ key and u to mark a message as unread. Usually, shortcuts on websites include modifier keys, such as Ctrl, along with a letter, number, or punctuation symbol. Unfortunately, users who have dexterity challenges sometimes trigger those shortcuts by accident, and that can make a website impossible to use. Also, speech input technology can sometimes trigger those shortcuts. If your website offers single-character keyboard shortcuts, you must allow your user to turn off or remap those shortcuts. This doesn’t apply to single-character keyboard shortcuts that only work when a control, such as drop-down list, has focus. 2.2.6 If your website uses a timeout for some process, you could store the user’s data for at least 20 hours, so that users with cognitive disabilities can take a break or take longer than usual to complete the process without losing their place or losing their data. Alternatively, you could warn the user, at the start of the process, about that the website will timeout after whatever amount of time you have chosen. 2.3.3 If your website has some non-essential animation (such as parallax scrolling) that starts when the user does some particular action, you could allow the user to turn off that animation so that you avoid harming users with vestibular disorders. The prefers-reduced-motion media query currently has limited browser support, but you can start using it now to avoid showing animations to users who select the “Reduce Motion” setting (or equivalent) in their device’s operating system: @media (prefers-reduced-motion: reduce) { .MrFancyPants { animation: none; } } 2.5.1 Some websites let users use multi-touch gestures on touchscreen devices. For example, Google Maps allows users to pinch with two fingers to zoom out and “unpinch” with two fingers to zoom in. Also, some websites allow users to drag a finger to do some action, such as changing the value on an input element with type="range", or swiping sideways to the next photograph in a gallery. Some users with dexterity challenges, and some users who use a head pointer, an eye-gaze system, or speech-controlled mouse emulation, might find multi-touch gestures or dragging impossible. You must make sure that your website supports single-tap alternatives to any multi-touch gestures or dragging actions that it provides. For example, if your website lets someone pinch and unpinch a map to zoom in and out, you must also provide buttons that a user can tap to zoom in and out. 2.5.2 This might be my favourite accessibility criterion ever! Did you ever touch or press a “Send” button but then immediately realise that you really didn’t want to send the message, and so move your finger or cursor away from the “Send” button before lifting your finger?! Imagine how many arguments that functionality has prevented. 😌 You must make sure that touching or pressing does not cause anything to happen before the user raises their finger or cursor, or make sure that the user can move their finger or cursor away to prevent the action. In JavaScript, prefer onclick to onmousedown, unless your website has actions that need onmousedown. Also, this doesn’t apply to actions that need to happen as soon as the user clicks or touches. For example, a user playing a “Whac-A-Mole” game or a piano emulator needs the action to happen as soon as they click or touch the screen. 2.5.3 Recently, entrepreneur and social media guru Gary Vaynerchuk has emphasised the rise of audio and voice as output and input. He quotes a Google statistic that says one in five search queries use voice input. Once again, users with disabilities have been ahead of the curve here, having used screen readers and/or dictation software for many years. You must make sure that the text that appears on a form control or image matches how your HTML identifies that form control or image. Use proper semantic HTML to achieve this: use the label element to pair text with the corresponding input element; use an alt attribute value that exactly matches any text that appears in an image; use an aria-labelledby attribute value that exactly matches the text that appears in any complex component. 2.5.4 Modern Web APIs allow web developers to specify how their website will react to the user shaking, tilting, or gesturing towards their device. Some users might find those actions difficult, impossible, or embarrassing to perform. If you make any functionality available when the user shakes, tilts, or gestures towards their device, you must provide form controls that make that same functionality available. As usual, this doesn’t apply to websites that require shaking, tilting, or gesturing; this includes some games and music programmes. John Gruber describes the iPhone’s “Shake to Undo” gesture as “dreadful — impossible to discover through exploration of the on-screen [user interface], bad for accessibility, and risks your phone flying out of your hand”. This accessibility criterion seems to empathise with John: you must make sure that your user can prevent your website from responding to shaking, tilting and/or gesturing towards their device. 2.5.5 Homer Simpson’s telephone famously complained, “The fingers you have used to dial are too fat.” I think we’ve all felt like that when using phones and tablets, particularly when trying to dismiss pop-ups and ads. You could make interactive elements at least 44px wide × 44px high. Apple’s “Human Interface Guidelines” agree: “Provide ample touch targets for interactive elements. Try to maintain a minimum tappable area of 44pt x 44pt for all controls.” This doesn’t apply to links within inline text, or to unsoiled elements. 2.5.6 Expect your users to use a variety of input devices they want, and to change from one to another whenever they please. For example, a user with a tablet and keyboard might jab icons on the screen while typing on the keyboard, or a user might dictate text while alone and then type on a keyboard when a colleague arrives. You could make sure that your website allows your users to use whichever available input modality they choose. Once again, this doesn’t apply to websites that require a specific modality; this includes typing tutors and music programmes. Can users understand your content? The third guideline has criteria that help you prevent your users from asking, “What the **** does this mean?” We’ve no new criteria for this guideline. Have you made your website robust enough to work on your users’ browsers and assistive technologies? The fourth and final guideline has criteria that help you prevent your users from asking, “Why the **** doesn’t this work on my device?” We’ve one new criterion for this guideline. 4.1.3 Sometimes you need to let your user know the status of something: “Did it work OK? What was the error? How far through it are we?” However, you should avoid making your user lose their place on the webpage, and so you should let them know the status without opening a new window, focusing on another element, or submitting a form. To do this properly for assistive technology users, choose the appropriate ARIA role for the new content; for example: if your user needs to know, “Did it work OK?”, add role="status”; if your user needs to know, “What was the error?”, add role="alert”; if you user needs to know, “How far through it are we?”, add role="log" (for a chat window) or role="progressbar" (for, well, a progress bar). Better design for humans My favourite of Luke Wroblewski’s collection of Design Quotes is, “Design is the art of gradually applying constraints until only one solution remains,” from that most prolific author, “Unknown”. I’ve always viewed the Web Content Accessibility Guidelines as people-based constraints, and liked how they help the design process. With these 17 new web content accessibility criteria, go forth and create solutions that more people than ever before can use. Spending those book vouchers you got for Christmas What next? If you’re looking for something to do to keep you busy this Christmas, I thoroughly recommend these four books for increasing your accessibility expertise: “Pro HTML5 Accessibility” by Joshue O Connor (Head of Accessibility (Interim) at the UK Government Digital Service, Director of InterAccess, and one of the editors of the Web Content Accessibility Guidelines 2.1): Although this book is six years old—a long time in web design—I find it an excellent go-to resource. It begins by explaining how people with disabilities use the web, and then expertly explains modern HTML in that context. “A Web for Everyone—Designing Accessible User Experiences” by Sarah Horton (the Paciello Group’s UX Strategy Lead) and Whitney Quesenbery (the Center for Civic Design’s co-director): This book covers the Web Content Accessibility Guidelines 2.0, the principles of Universal Design, and design thinking. Its personas for Accessible UX and its profiles of well-known industry figures—including some 24ways authors—keep its content practical and relevant throughout. “Accessibility For Everyone” by Laura Kalbag (Ind.ie’s co-founder and designer, and 24ways author): This book is just over a year old, and so serves as a great resource for up-to-date coverage of guidelines, laws, and accessibility features of operating systems—as well as content, design, coding, and testing. The audiobook, which Laura narrates, can help you and your colleagues go from having little or no understanding of web accessibility, to becoming familiar with all aspects of web accessibility—in less than four hours. “Just Ask: Integrating Accessibility Throughout Design” by Shawn Lawton Henry (the World Wide Web Consortium (W3C)’s Web Accessibility Initiative (WAI)’s Outreach Coordinator): Although this book is 11½ years old, the way it presents accessibility as part of the User-Centered Design process is timeless. I found its section on Usability Testing with people with disabilities particularly useful. 2018 Alan Dalton alandalton 2018-12-03T00:00:00+00:00 https://24ways.org/2018/wcag-for-people-who-havent-read-the-update/ ux
193 Web Content Accessibility Guidelines—for People Who Haven't Read Them I’ve been a huge fan of the Web Content Accessibility Guidelines 2.0 since the World Wide Web Consortium (W3C) published them, nine years ago. I’ve found them practical and future-proof, and I’ve found that they can save a huge amount of time for designers and developers. You can apply them to anything that you can open in a browser. My favourite part is when I use the guidelines to make a website accessible, and then attend user-testing and see someone with a disability easily using that website. Today, the United Nations International Day of Persons with Disabilities, seems like a good time to re-read Laura Kalbag’s explanation of why we should bother with accessibility. That should motivate you to devour this article. If you haven’t read the Web Content Accessibility Guidelines 2.0, you might find them a bit off-putting at first. The editors needed to create a single standard that countries around the world could refer to in legislation, and so some of the language in the guidelines reads like legalese. The editors also needed to future-proof the guidelines, and so some terminology—such as “time-based media” and “programmatically determined”—can sound ambiguous. The guidelines can seem lengthy, too: printing the guidelines, the Understanding WCAG 2.0 document, and the Techniques for WCAG 2.0 document would take 1,200 printed pages. This festive season, let’s rip off that legalese and ambiguous terminology like wrapping paper, and see—in a single article—what gifts the Web Content Accessibility Guidelines 2.0 editors have bestowed upon us. Can your users perceive the information on your website? The first guideline has criteria that help you prevent your users from asking “What the **** is this thing here supposed to be?” 1.1.1 Text is the most accessible format for information. Screen readers—such as the “VoiceOver” setting on your iPhone or the “TalkBack” app on your Android phone—understand text better than any other format. The same applies for other assistive technology, such as translation apps and Braille displays. So, if you have anything on your webpage that’s not text, you must add some text that gives your user the same information. You probably know how to do this already; for example: for images in webpages, put some alternative text in an alt attribute to tell your user what the image conveys to the user; for photos in tweets, add a description to make the images accessible; for Instagram posts, write a caption that conveys the photo’s information. The alternative text should allow the user to get the same information as someone who can see the image. For websites that have too many images for someone to add alternative text to, consider how machine learning and Dynamically Generated Alt Text might—might—be appropriate. You can probably think of a few exceptions where providing text to describe an image might not make sense. Remember I described these guidelines as “practical”? They cover all those exceptions: User interface controls such as buttons and text inputs must have names or labels to tell your user what they do. If your webpage has video or audio (more about these later on!), you must—at least—have text to tell the user what they are. Maybe your webpage has a test where your user has to answer a question about an image or some audio, and alternative text would give away the answer. In that case, just describe the test in text so your users know what it is. If your webpage features a work of art, tell your user the experience it evokes. If you have to include a Captcha on your webpage—and please avoid Captchas if at all possible, because some users cannot get past them—you must include text to tell your user what it is, and make sure that it doesn’t rely on only one sense, such as vision. If you’ve included something just as decoration, you must make sure that your user’s assistive technology can ignore it. Again, you probably know how to do this. For example, you could use CSS instead of HTML to include decorative images, or you could add an empty alt attribute to the img element. (Please avoid that recent trend where developers add empty alt attributes to all images in a webpage just to make the HTML validate. You’re better than that.) (Notice that the guidelines allow you to choose how to conform to them, with whatever technology you choose. To make your website conform to a guideline, you can either choose one of the techniques for WCAG 2.0 for that guideline or come up with your own. Choosing a tried-and-tested technique usually saves time!) 1.2.1 If your website includes a podcast episode, speech, lecture, or any other recorded audio without video, you must include a transcription or some other text to give your user the same information. In a lot of cases, you might find this easier than you expect: professional transcription services can prove relatively inexpensive and fast, and sometimes a speaker or lecturer can provide the speech or lecture notes that they read out word-for-word. Just make sure that all your users can get the same information and the same results, whether they can hear the audio or not. For example, David Smith and Marco Arment always publish episode transcripts for their Under the Radar podcast. Similarly, if your website includes recorded video without audio—such as an animation or a promotional video—you must either use text to detail what happens in the video or include an audio version. Again, this might work out easier then you perhaps fear: for example, you could check to see whether the animation started life as a list of instructions, or whether the promotional video conveys the same information as the “About Us” webpage. You want to make sure that all your users can get the same information and the same results, whether they can see that video or not. 1.2.2 If your website includes recorded videos with audio, you must add captions to those videos for users who can’t hear the audio. Professional transcription services can provide you with time-stamped text in caption formats that YouTube supports, such as .srt and .sbv. You can upload those to YouTube, so captions appear on your videos there. YouTube can auto-generate captions, but the quality varies from impressively accurate to comically inaccurate. If you have a text version of what the people in the video said—such as the speech that a politician read or the bedtime story that an actor read—you can create a transcript file in .txt format, without timestamps. YouTube then creates captions for your video by synchronising that text to the audio in the video. If you host your own videos, you can ask a professional transcription service to give you .vtt files that you can add to a video element’s track element—or you can handcraft your own. (A quick aside: if your website has more videos than you can caption in a reasonable amount of time, prioritise the most popular videos, the most important videos, and the videos most relevant to people with disabilities. Then make sure your users know how to ask you to caption other videos as they encounter them.) 1.2.3 If your website has recorded videos that have audio, you must add an “audio description” narration to the video to describe important visual details, or add text to the webpage to detail what happens in the video for users who cannot see the videos. (I like to add audio files from videos to my Huffduffer account so that I can listen to them while commuting.) Maybe your home page has a video where someone says, “I’d like to explain our new TPS reports” while “Bill Lumbergh, division Vice President of Initech” appears on the bottom of the screen. In that case, you should add an audio description to the video that announces “Bill Lumbergh, division Vice President of Initech”, just before Bill starts speaking. As always, you can make life easier for yourself by considering all of your users, before the event: in this example, you could ask the speaker to begin by saying, “I’m Bill Lumbergh, division Vice President of Initech, and I’d like to explain our new TPS reports”—so you won’t need to spend time adding an audio description afterwards. 1.2.4 If your website has live videos that have some audio, you should get a stenographer to provide real-time captions that you can include with the video. I’ll be honest: this can prove tricky nowadays. The Web Content Accessibility Guidelines 2.0 predate YouTube Live, Instagram live Stories, Periscope, and other such services. If your organisation creates a lot of live videos, you might not have enough resources to provide real-time captions for each one. In that case, if you know the contents of the audio beforehand, publish the contents during the live video—or failing that, publish a transcription as soon as possible. 1.2.5 Remember what I said about the recorded videos that have audio? If you can choose to either add an audio description or add text to the webpage to detail what happens in the video, you should go with the audio description. 1.2.6 If your website has recorded videos that include audio information, you could provide a sign language version of the audio information; some people understand sign language better than written language. (You don’t need to caption a video of a sign language version of audio information.) 1.2.7 If your website has recorded videos that have audio, and you need to add an audio description, but the audio doesn’t have enough pauses for you to add an “audio description” narration, you could provide a separate version of that video where you have added pauses to fit the audio description into. 1.2.8 Let’s go back to the recorded videos that have audio once more! You could add text to the webpage to detail what happens in the video, so that people who can neither read captions nor hear dialogue and audio description can use braille displays to understand your video. 1.2.9 If your website has live audio, you could get a stenographer to provide real-time captions. Again, if you know the contents of the audio beforehand, publish the contents during the live audio or publish a transcription as soon as possible. (Congratulations on making it this far! I know that seems like a lot to remember, but keep in mind that we’ve covered a complex area: helping your users to understand multimedia information that they can’t see and/or hear. Grab a mince pie to celebrate, and let’s keep going.) 1.3.1 You must mark up your website’s content so that your user’s browser, and any assistive technology they use, can understand the hierarchy of the information and how each piece of information relates to the rest. Once again, you probably know how to do this: use the most appropriate HTML element for each piece of information. Mark up headings, lists, buttons, radio buttons, checkboxes, and links with the most appropriate HTML element. If you’re looking for something to do to keep you busy this Christmas, scroll through the list of the elements of HTML. Do you notice any elements that you didn’t know, or that you’ve never used? Do you notice any elements that you could use on your current projects, to mark up the content more accurately? Also, revise HTML table advanced features and accessibility, how to structure an HTML form, and how to use the native form widgets—you might be surprised at how much you can do with just HTML! Once you’ve mastered those, you can make your website much more usable for your all of your users. 1.3.2 If your webpage includes information that your user has to read in a certain order, you must make sure that their browser and assistive technology can present the information in that order. Don’t rely on CSS or whitespace to create that order visually. Check that the order of the information makes sense when CSS and whitespace aren’t formatting it. Also, try using the Tab key to move the focus through the links and form widgets on your webpage. Does the focus go where you expect it to? Keep this in mind when using order in CSS Grid or Flexbox. 1.3.3 You must not presume that your users can identify sensory characteristics of things on your webpage. Some users can’t tell what you’ve positioned where on the screen. For example, instead of asking your users to “Choose one of the options on the left”, you could ask them to “Choose one of our new products” and link to that section of the webpage. 1.4.1 You must not rely on colour as the only way to convey something to your users. Some of your users can’t see, and some of your users can’t distinguish between colours. For example, if your webpage uses green to highlight the products that your shop has in stock, you could add some text to identify those products, or you could group them under a sub-heading. 1.4.2 If your webpage automatically plays a sound for more than 3 seconds, you must make sure your users can stop the sound or change its volume. Don’t rely on your user turning down the volume on their computer; some users need to hear the screen reader on their computer, and some users just want to keep listening to whatever they were listening before your webpage interrupted them! 1.4.3 You should make sure that your text contrasts enough with its background, so that your users can read it. Bookmark Lea Verou’s Contrast Ratio calculator now. You can enter the text colour and background colour as named colours, or as RGB, RGBa, HSL, or HSLa values. You should make sure that: normal text that set at 24px or larger has a ratio of at least 3:1; bold text that set at 18.75px or larger has a ratio of at least 3:1; all other text has a ratio of at least 4½:1. You don’t have to do this for disabled form controls, decorative stuff, or logos—but you could! 1.4.4 You should make sure your users can resize the text on your website up to 200% without using their assistive technology—and still access all your content and functionality. You don’t have to do this for subtitles or images of text. 1.4.5 You should avoid using images of text and just use text instead. In 1998, Jeffrey Veen’s first Hot Design Tip said, “Text is text. Graphics are graphics. Don’t confuse them.” Now that you can apply powerful CSS text-styling properties, use CSS Grid to precisely position text, and choose from thousands of web fonts (Jeffrey co-founded Typekit to help with this), you pretty much never need to use images of text. The guidelines say you can use images of text if you let your users specify the font, size, colour, and background of the text in the image of text—but I’ve never seen that on a real website. Also, this doesn’t apply to logos. 1.4.6 Let’s go back to colour contrast for a second. You could make your text contrast even more with its background, so that even more of your users can read it. To do that, use Lea Verou’s Contrast Ratio calculator to make sure that: normal text that is 24px or larger has a ratio of at least 4½:1; bold text that 18.75px or larger has a ratio of at least 4½:1; all other text has a ratio of at least 7:1. 1.4.7 If your website has recorded speech, you could make sure there are no background sounds, or that your users can turn off any background sounds. If that’s not possible, you could make sure that any background sounds that last longer than a couple of seconds are at least four times quieter than the speech. This doesn’t apply to audio Captchas, audio logos, singing, or rapping. (Yes, these guidelines mention rapping!) 1.4.8 You could make sure that your users can reformat blocks of text on your website so they can read them better. To do this, make sure that your users can: specify the colours of the text and the background, and make the blocks of text less than 80-characters wide, and align text to the left (or right for right-to-left languages), and set the line height to 150%, and set the vertical distance between paragraphs to 1½ times the line height of the text, and resize the text (without using their assistive technology) up to 200% and still not have to scroll horizontally to read it. By the way, when you specify a colour for text, always specify a colour for its background too. Don’t rely on default background colours! 1.4.9 Let’s return to images of text for a second. You could make sure that you use them only for decoration and logos. Can users operate the controls and links on your website? The second guideline has criteria that help you prevent your users from asking, “How the **** does this thing work?” 2.1.1 You must make sure that you users can carry out all of your website’s activities with just their keyboard, without time limits for pressing keys. (This doesn’t apply to drawing or anything else that requires a pointing device such as a mouse.) Again, if you use the most appropriate HTML element for each piece of information and for each form element, this should prove easy. 2.1.2 You must make sure that when the user uses the keyboard to focus on some part of your website, they can then move the focus to some other part of your webpage without needing to use a mouse or touch the screen. If your website needs them to do something complex before they can move the focus elsewhere, explain that to your user. These “keyboard traps” have become rare, but beware of forms that move focus from one text box to another as soon as they receive the correct number of characters. 2.1.3 Let’s revisit making sure that you users can carry out all of your website’s activities with just their keyboard, without time limits for pressing keys. You could make sure that your user can do absolutely everything on your website with just the keyboard. 2.2.1 Sometimes people need more time than you might expect to complete a task on your website. If any part of your website imposes a time limit on a task, you must do at least one of these: let your users turn off the time limit before they encounter it; or let your users increase the time limit to at least 10 times the default time limit before they encounter it; or warn your users before the time limit expires and give them at least 20 seconds to extend it, and let them extend it at least 10 times. Remember: these guidelines are practical. They allow you to enforce time limits for real-time events such as auctions and ticket sales, where increasing or extending time limits wouldn’t make sense. Also, the guidelines allow you to enforce a maximum time limit of 20 hours. The editors chose 20 hours because people need to go to sleep at some stage. See? Practical! 2.2.2 In my experience, this criterion remains the least well-known—even though some users can only use websites that conform to it. If your website presents content alongside other content that can distract users by automatically moving, blinking, scrolling, or updating, you must make sure that your users can: pause, stop, or hide the other content if it’s not essential and lasts more than 5 seconds; and pause, stop, hide, or control the frequency of the other content if it automatically updates. It’s OK if your users miss live information such as stock price updates or football scores; you can’t do anything about that! Also, this doesn’t apply to animations such as progress bars that you put on a website to let all users know that the webpage isn’t frozen. (If this one sounds complex, just add a pause button to anything that might distract your users.) 2.2.3 Let’s go back to time limits on tasks on your website. You could make your website even easier to use by removing all time limits except those on real-time events such as auctions and ticket sales. That would mean your user wouldn’t need to interact with a timer at all. 2.2.4 You could let your users turn off all interruptions—server updates, promotions, and so on—apart from any emergency information. 2.2.5 This is possibly my favourite of these criteria! After your website logs your user out, you could make sure that when they log in again, they can continue from where they were without having lost any information. Do that, and you’ll be on everyone’s Nice List this Christmas. 2.3.1 You must make sure that nothing flashes more than three times a second on your website, unless you can make sure that the flashes remain below the acceptable general flash and red flash thresholds… 2.3.2 …or you could just make sure that nothing flashes more than three times per second on your website. This is usually an easier goal. 2.4.1 You must make sure that your users can jump past any blocks of content, such as navigation menus, that are repeated throughout your website. You know the drill here: using HTML’s sectioning elements such as header, nav, main, aside, and footer allows users with assistive technology to go straight to the content they need, and adding “Skip Navigation” links allows everyone to get to your main content faster. 2.4.2 You must add a proper title to describe each webpage’s topic. Your webpage won’t even validate without a title element, so make it a useful one. 2.4.3 If your users can focus on links and native form widgets, you must make sure that they can focus on elements in an order that makes sense. 2.4.4 You must make sure that your users can understand the purpose of a link when they read: the text of the link; or the text of the paragraph, list item, table cell, or table header for the cell that contains the link; or the heading above the link. You don’t have to do that for games and quizzes. 2.4.5 You should give your users multiple ways to find any webpage within a set of webpages. Add site-wide search and a site map and you’re done! This doesn’t apply for a webpage that is part of a series of actions (like a shopping cart and checkout flow) or to a webpage that is a result of a series of actions (like a webpage confirming that the user has bought what was in the shopping cart). 2.4.6 You should help your users to understand your content by providing: headings that describe the topics of you content; labels that describe the purpose of the native form widgets on the webpage. 2.4.7 You should make sure that users can see which element they have focussed on. Next time you use your website, try hitting the Tab key repeatedly. Does it visually highlight each item as it moves focus to it? If it doesn’t, search your CSS to see whether you’ve applied outline: 0; to all elements—that’s usually the culprit. Use the :focus pseudo-element to define how elements should appear when they have focus. 2.4.8 You could help your user to understand where the current webpage is located within your website. Add “breadcrumb navigation” and/or a site map and you’re done. 2.4.9 You could make links even easier to understand, by making sure that your users can understand the purpose of a link when they read the text of the link. Again, you don’t have to do that for games and quizzes. 2.4.10 You could use headings to organise your content by topic. Can users understand your content? The third guideline has criteria that help you prevent your users from asking, “What the **** does this mean?” 3.1.1 Let’s start this section with the criterion that possibly takes the least time to implement; you must make sure that the user’s browser can identify the main language that your webpage’s content is written in. For a webpage that has mainly English content, use <html lang="en">. 3.1.2 You must specify when content in another language appears in your webpage, like so: <q>I wish you a <span lang="fr">Joyeux Noël</span>.</q>. You don’t have to do this for proper names, technical terms, or words that you can’t identify a language for. You also don’t have to do it for words from a different language that people consider part of the language around those words; for example, <q>Come to our Christmas rendezvous!</q> is OK. 3.1.3 You could make sure that your users can find out the meaning of any unusual words or phrases, including idioms like “stocking filler” or “Bah! Humbug!” and jargon such as “VoiceOver” and “TalkBack”. Provide a glossary or link to a dictionary. 3.1.4 You could make sure that your users can find out the meaning of any abbreviation. For example, VoiceOver pronounces “Xmas” as “Smas” instead of “Christmas”. Using the abbr element and linking to a glossary can help. (Interestingly, VoiceOver pronounces “abbr” as “abbreviation”!) 3.1.5 Do your users need to be able to read better than a typically educated nine-year-old, to read your content (apart from proper names and titles)? If so, you could provide a version that doesn’t require that level of reading ability, or you could provide images, videos, or audio to explain your content. (You don’t have to add captions or audio description to those videos.) 3.1.6 You could make sure that your users can access the pronunciation of any word in your content if that word’s meaning depends on its pronunciation. For example, the word “close” could have one of two meanings, depending on pronunciation, in a phrase such as, “Ready for Christmas? Close now!” 3.2.1 Some users need to focus on elements to access information about them. You must make sure that focusing on an element doesn’t trigger any major changes, such as opening a new window, focusing on another element, or submitting a form. 3.2.2 Webpages are easier for users when the controls do what they’re supposed to do. Unless you have warned your users about it, you must make sure that changing the value of a control such as a text box, checkbox, or drop-down list doesn’t trigger any major changes, such as opening a new window, focusing on another element, or submitting a form. 3.2.3 To help your users to find the content they want on each webpage, you should put your navigation elements in the same place on each webpage. (This doesn’t apply when your user has changed their preferences or when they use assistive technology to change how your content appears.) 3.2.4 When a set of webpages includes things that have the same functionality on different webpages, you should name those things consistently. For example, don’t use the word “Search” for the search box on one webpage and “Find” for the search box on another webpage within that set of webpages. 3.2.5 Let’s go back to major changes, such as a new window opening, another element taking focus, or a form being submitted. You could make sure that they only happen when users deliberately make them happen, or when you have warned users about them first. For example, you could give the user a button for updating some content instead of automatically updating that content. Also, if a link will open in a new window, you could add the words “opens in new window” to the link text. 3.3.1 Users make mistakes when filling in forms. Your website must identify each mistake to your user, and must describe the mistake to your users in text so that the user can fix it. One way to identify mistakes reliably to your users is to set the aria-invalid attribute to true in the element that has a mistake. That makes sure that users with assistive technology will be alerted about the mistake. Of course, you can then use the [aria-invalid="true"] attribute selector in your CSS to visually highlight any such mistakes. Also, look into how certain attributes of the input element such as required, type, and list can help prevent and highlight mistakes. 3.3.2 You must include labels or instructions (and possibly examples) in your website’s forms, to help your users to avoid making mistakes. 3.3.3 When your user makes a mistake when filling in a form, your webpage should suggest ways to fix that mistake, if possible. This doesn’t apply in scenarios where those suggestions could affect the security of the content. 3.3.4 Whenever your user submits information that: has legal or financial consequences; or affects information that they have previously saved in your website; or is part of a test …you should make sure that they can: undo it; or correct any mistakes, after your webpage checks their information; or review, confirm, and correct the information before they finally submit it. 3.3.5 You could help prevent your users from making mistakes by providing obvious, specific help, such as examples, animations, spell-checking, or extra instructions. 3.3.6 Whenever your user submits any information, you could make sure that they can: undo it; or correct any mistakes, after your webpage checks their information; or review, confirm, and correct the information before they finally submit it. Have you made your website robust enough to work on your users’ browsers and assistive technologies? The fourth and final guideline has criteria that help you prevent your users from asking, “Why the **** doesn’t this work on my device?” 4.1.1 You must make sure that your website works as well as possible with current and future browsers and assistive technology. Prioritise complying with web standards instead of relying on the capabilities of currently popular devices and browsers. Web developers didn’t expect their users to be unwrapping the Wii U Browser five years ago—who knows what browsers and assistive technologies our users will be unwrapping in five years’ time? Avoid hacks, and use the W3C Markup Validation Service to make sure that your HTML has no errors. 4.1.2 If you develop your own user interface components, you must make their name, role, state, properties, and values available to your user’s browsers and assistive technologies. That should make them almost as accessible as standard HTML elements such as links, buttons, and checkboxes. “…and a partridge in a pear tree!” …as that very long Christmas song goes. We’ve covered a lot in this article—because your users have a lot of different levels of ability. Hopefully this has demystified the Web Content Accessibility Guidelines 2.0 for you. Hopefully you spotted a few situations that could arise for users on your website, and you now know how to tackle them. To start applying what we’ve covered, you might like to look at Sarah Horton and Whitney Quesenbery’s personas for Accessible UX. Discuss the personas, get into their heads, and think about which aspects of your website might cause problems for them. See if you can apply what we’ve covered today, to help users like them to do what they need to do on your website. How to know when your website is perfectly accessible for everyone LOL! There will never be a time when your website becomes perfectly accessible for everyone. Don’t aim for that. Instead, aim for regularly testing and making your website more accessible. Web Content Accessibility Guidelines (WCAG) 2.1 The W3C hope to release the Web Content Accessibility Guidelines (WCAG) 2.1 as a “recommendation” (that’s what the W3C call something that we should start using) by the middle of next year. Ten years may seem like a long time to move from version 2.0 to version 2.1, but consider the scale of the task: the editors have to update the guidelines to cover all the new ways that people interact with new technologies, while keeping the guidelines backwards-compatible. Keep an eye out for 2.1! You’ll go down in history One last point: I’ve met a surprising number of web designers and developers who do great work to make their websites more accessible without ever telling their users about it. Some of your potential customers have possibly tried and failed to use your website in the past. They probably won’t try again unless you let them know that things have improved. A quick Twitter search for your website’s name alongside phrases like “assistive technology”, “doesn’t work”, or “#fail” can let you find frustrated users—so you can tell them about how you’re making your website more accessible. Start making your websites work better for everyone—and please, let everyone know. 2017 Alan Dalton alandalton 2017-12-03T00:00:00+00:00 https://24ways.org/2017/wcag-for-people-who-havent-read-them/ code
67 What I Learned about Product Design This Year 2015 was a humbling year for me. In September of 2014, I joined a tiny but established startup called SproutVideo as their third employee and first designer. The role interests me because it affords the opportunity to see how design can grow a solid product with a loyal user-base into something even better. The work I do now could also have a real impact on the brand and user experience of our product for years to come, which is a thrilling prospect in an industry where much of what I do feels small and temporary. I got in on the ground floor of something special: a small, dedicated, useful company that cares deeply about making video hosting effortless and rewarding for our users. I had (and still have) grand ideas for what thoughtful design can do for a product, and the smaller-scale product design work I’ve done or helped manage over the past few years gave me enough eager confidence to dive in head first. Readers who have experience redesigning complex existing products probably have a knowing smirk on their face right now. As I said, it’s been humbling. A year of focused product design, especially on the scale we are trying to achieve with our small team at SproutVideo, has taught me more than any projects in recent memory. I’d like to share a few of those lessons. Product design is very different from marketing design The majority of my recent work leading up to SproutVideo has been in marketing design. These projects are so fun because their aim is to communicate the value of the product in a compelling and memorable way. In order to achieve this goal, I spent a lot of time thinking about content strategy, responsive design, and how to create striking visuals that tell a story. These are all pursuits I love. Product design is a different beast. When designing a homepage, I can employ powerful imagery, wild gradients, and somewhat-quirky fonts. When I began redesigning the SproutVideo product, I wanted to draw on all the beautiful assets I’ve created for our marketing materials, but big gradients, textures, and display fonts made no sense in this new context. That’s because the product isn’t about us, and it isn’t about telling our story. Product design is about getting out of the way so people can do their job. The visual design is there to create a pleasant atmosphere for people to work in, and to help support the user experience. Learning to take “us” out of the equation took some work after years of creating gorgeous imagery and content for the sales-driven side of businesses. I’ve learned it’s very valuable to design both sides of the experience, because marketing and product design flex different muscles. If you’re currently in an environment where the two are separate, consider switching teams in 2016. Designing for product when you’ve mostly done marketing, or vice versa, will deepen your knowledge as a designer overall. You’ll face new unexpected challenges, which is the only way to grow. Product design can not start with what looks good on Dribbble I have an embarrassing confession: when I began the redesign, I had a secret goal of making something that would look gorgeous in my portfolio. I have a collection of product shots that I admire on Dribbble; examples of beautiful dashboards and widgets and UI elements that look good enough to frame. I wanted people to feel the same way about the final outcome of our redesign. Mistakenly, this was a factor in my initial work. I opened Photoshop and crafted pixel-perfect static buttons and form elements and color palettes that — when applied to our actual product — looked like a toddler beauty pageant. It added up to a lot of unusable shininess, noise, and silliness. I was disappointed; these elements seemed so lovely in isolation, but in context, they felt tacky and overblown. I realized: I’m not here to design the world’s most beautiful drop down menu. Good design has nothing to do with ego, but in my experience designers are, at least a little bit, secret divas. I’m no exception. I had to remind myself that I am not working in service of a bigger Dribbble following or to create the most Pinterest-ing work. My function is solely to serve the users — to make life a little better for the good people who keep my company in business. This meant letting go of pixel-level beauty to create something bigger and harder: a system of elements that work together in harmony in many contexts. The visual style exists to guide the users. When done well, it becomes a language that users understand, so when they encounter a new feature or have a new goal, they already feel comfortable navigating it. This meant stripping back my gorgeous animated menu into something that didn’t detract from important neighboring content, and could easily fit in other parts of the app. In order to know what visual style would support the users, I had to take a wider view of the product as a whole. Just accept that designing a great product – like many worthwhile pursuits – is initially laborious and messy Once I realized I couldn’t start by creating the most Dribbble-worthy thing, I knew I’d have to begin with the unglamorous, frustrating, but weirdly wonderful work of mapping out how the product’s content could better be structured. Since we’re redesigning an existing product, I assumed this would be fairly straightforward: the functionality was already in place, and my job was just to structure it in a more easily navigable way. I started by handing off a few wireframes of the key screens to the developer, and that’s when the questions began rolling in: “If we move this content into a modal, how will it affect this similar action here?” “What happens if they don’t add video tags, but they do add a description?” “What if the user has a title that is 500 characters long?” “What if they want their video to be private to some users, but accessible to others?”. How annoying (but really, fantastic) that people use our product in so many ways. Turns out, product design isn’t about laying out elements in the most ideal scenario for the user that’s most convenient for you. As product designers, we have to foresee every outcome, and anticipate every potential user need. Which brings me to another annoying epiphany: if you want to do it well, and account for every user, product design is so much more snarly and tangled than you’d expect going in. I began with a simple goal: to improve the experience on just one of our key product pages. However, every small change impacts every part of the product to some degree, and that impact has to be accounted for. Every decision is based on assumptions that have to be tested; I test my assumptions by observing users, talking to the team, wireframing, and prototyping. Many of my assumptions are wrong. There are days when it’s incredibly frustrating, because an elegant solution for users with one goal will complicate life for users with another goal. It’s vital to solve as many scenarios as possible, even though this is slow, sometimes mind-bending work. As a side bonus, wireframing and prototyping every potential state in a product is tedious, but your developers will thank you for it. It’s not their job to solve what happens when there’s an empty state, error, or edge case. Showing you’ve accounted for these scenarios will win a developer’s respect; failing to do so will frustrate them. When you’ve created and tested a system that supports user needs, it will be beautiful Remember what I said in the beginning about wanting to create a Dribbble-worthy product? When I stopped focusing on the visual details of the design (color, spacing, light and shadow, font choices) and focused instead on structuring the content to maximize usability and delight, a beautiful design began to emerge naturally. I began with grayscale, flat wireframes as a strategy to keep me from getting pulled into the visual style before the user experience was established. As I created a system of elements that worked in harmony, the visual style choices became obvious. Some buttons would need to be brighter and sit off the page to help the user spot important actions. Some elements would need line separators to create a hierarchy, where others could stand on their own as an emphasized piece of content. As the user experience took shape, the visual style emerged naturally to support it. The result is a product that feels beautiful to use, because I was thoughtful about the experience first. A big takeaway from this process has been that my assumptions will often be proven wrong. My assumptions about how to design a great product, and how users will interact with that product, have been tested and revised repeatedly. At SproutVideo we’re about to undertake the biggest test of our work; we’re going to launch a small part of the product redesign to our users. If I’ve learned anything, it’s that I will continue to be humbled by the ongoing effort of making the best product I can, which is a wonderful thing. Next year, I hope you all get to do work that takes you out of our comfort zone. Be regularly confounded and embarrassed by your wrong assumptions, learn from them, and come back and tell us what you learned in 2016. 2015 Meagan Fisher meaganfisher 2015-12-14T00:00:00+00:00 https://24ways.org/2015/what-i-learned-about-product-design-this-year/ design
41 What Is Vagrant and Why Should I Care? If you run a web server, a database server and your scripting language(s) of choice on your main machine and you have not yet switched to using virtualisation in your workflow then this essay may be of some value to you. I know you exist because I bump into you daily: freelancers coming in to work on our projects; internet friends complaining about reinstalling a development environment because of an operating system upgrade; fellow agency owners who struggle to brief external help when getting a particular project up and running; or even hardcore back-end developers who “don’t do ops” and prefer to run their development stack of choice locally. There are many perfectly reasonable arguments as to why you may not have already made the switch, from being simply too busy, all the way through to a distrust of the new. I’ll admit that there are many new technologies or workflows that I hear of daily and instantly disregard because I have tool overload, that feeling I get when I hear about a new shiny thing and think “Well, what I do now works – I’ll leave it for others to play with.” If that’s you when it comes to Vagrant then I hope you’ll hear me out. The business case is compelling enough for you to make that switch; as a bonus it’s also really easy to get going. In this article we’ll start off by going through the high level, the tools available and how it all fits together. Then we’ll touch on the justification for making the switch, providing a few use cases that might resonate with you. Finally, I’ll provide a very simple example that you can follow to get yourself up and running. What? You already know what virtualisation is. You use the ability to run an operating system within another operating system every day. Whether that’s Parallels or VMware on your laptop or similar server-based tools that drive the ‘cloud’, squeezing lots of machines on to physical hardware and making it really easy to copy servers and even clusters of servers from one place to another. It’s an amazing technology which has changed the face of the internet over the past fifteen years. Simply put, Vagrant makes it really easy to work with virtual machines. According to the Vagrant docs: If you’re a designer, Vagrant will automatically set everything up that is required for that web app in order for you to focus on doing what you do best: design. Once a developer configures Vagrant, you don’t need to worry about how to get that app running ever again. No more bothering other developers to help you fix your environment so you can test designs. Just check out the code, vagrant up, and start designing. While I’m not sure I agree with the implication that all designers would get others to do the configuring, I think you’ll agree that the “Just check out the code… and start designing” premise is very compelling. You don’t need Vagrant to develop your web applications on virtual machines. All you need is a virtualisation software package, something like VMware Workstation or VirtualBox, and some code. Download the half-gigabyte operating system image that you want and install it. Then download and configure the stack you’ll be working with: let’s say Apache, MySQL, PHP. Then install some libraries, CuRL and ImageMagick maybe, and finally configure the ability to easily copy files from your machine to the new virtual one, something like Samba, or install an FTP server. Once this is all done, copy the code over, import the database, configure Apache’s virtual host, restart and cross your fingers. If you’re a bit weird like me then the above is pretty easy to do and secretly quite fun. Indeed, the amount of traffic to one of my more popular blog posts proves that a lot of people have been building themselves development servers from scratch for some time (or at least trying to anyway), whether that’s on virtual or physical hardware. Or you could use Vagrant. It allows you, or someone else, to specify in plain text how the machine’s virtual hardware should be configured and what should be installed on it. It also makes it insanely easy to get the code on the server. You check out your project, type vagrant up and start work. Why? It’s worth labouring the point that Vagrant makes it really easy; I mean look-no-tangle-of-wires-or-using-vim-and-loads-of-annoying-command-line-stuff easy to run a development environment. That’s all well and good, I hear you say, but there’s a steep learning curve, an overhead to switch. You’re busy and this all sounds great but you need to get on; you’ve got a career to build or a business to run and you don’t have time to learn new stuff right now. In short, what’s the business case? The business case involves saved time, a very low barrier to entry and the ability to give the exact same environment to somebody else. Getting your first development virtual machine running will take minutes, not counting download time. Seriously, use pre-built Vagrant files and provisioners (we’ll touch on this below) and you can start developing immediately. Once you’ve finished developing you can check in your changes, ask a colleague or freelancer to check them out, and then they run the code on the exact same machine – even if they are on the other side of the world and regardless of whether they are on Windows, Linux or Apple OS X. The configuration to build the machine isn’t a huge binary disk image that’ll take ages to download from Git; it’s two small text files that can be version controlled too, so you can see any changes made to the config and roll back if needed. No more ‘It works for me’ reports; no ‘Oh, I was using PHP 5.3.3, not PHP 5.3.11’ – you’re both working on exact same copies of the development environment. With a tested and verified provisioning file you’ll have the confidence that when you brief your next freelancer in to your team there won’t be that painful to and fro of getting the system up and running, where you’re on a Skype call and they are uttering the immortal words, ‘It still doesn’t work’. You know it works because you can run it too. This portability becomes even more important when you’re working on larger sites and systems. Need a load balancer? Multiple front-end servers and a clustered database back-end? No problem. Add each server into the same Vagrant file and a single command will build all of them. As you’ll know if you work on larger, business critical systems, keeping the operating systems in sync is a real problem: one server with a slightly different library causing sporadic and hard to trace issues is a genuine time black hole. Well, the good news is that you can use the same provisioning files to keep test and production machines in sync using your current build workflow. Let’s also not forget the most simple use case: a single developer with multiple websites running on a single machine. If that’s you and you switch to using Vagrant-managed virtual machines then the next time you upgrade your operating system or do a fresh install there’s no chance that things will all stop working. The server config is all tucked away in version control with your code. Just pull it down and carry on coding. OK, got it. Show me already If you want to try this out you’ll need to install the latest VirtualBox and Vagrant for your platform. If you already have VMware Workstation or another supported virtualisation package installed you can use that instead but you may need to tweak my Vagrant file below. Depending on your operating system, a reboot might also be wise. Note: the commands below were executed on my MacBook, but should also work on Windows and Linux. If you’re using Windows make sure to run the command prompt as Administrator or it’ll fall over when trying to update the hosts file. As a quick sanity check let’s just make sure that we have the vagrant command in our path, so fire up a terminal and check the version number: $ vagrant -v Vagrant 1.6.5 We’ve one final thing to install and that’s the vagrant-hostsupdater plugin. Once again, in your terminal: $ vagrant plugin install vagrant-hostsupdater Installing the 'vagrant-hostsupdater' plugin. This can take a few minutes... Installed the plugin 'vagrant-hostsupdater (0.0.11)'! Hopefully that wasn’t too painful for you. There are two things that you need to manage a virtual machine with Vagrant: a Vagrant file: this tells Vagrant what hardware to spin up a provisioning file: this tells Vagrant what to do on the machine To save you copying and pasting I’ve supplied you with a simple example (ZIP) containing both of these. Unzip it somewhere sensible and in your terminal make sure you are inside the Vagrant folder: $ cd where/you/placed/it/24ways $ ls -l -rw-r--r--@ 1 bealers staff 11055 9 Nov 09:16 bealers-24ways.md -rw-r--r--@ 1 bealers staff 118152 9 Nov 10:08 it-works.png drwxr-xr-x 5 bealers staff 170 8 Nov 22:54 vagrant $ cd vagrant/ $ ls -l -rw-r--r--@ 1 bealers staff 1661 8 Nov 21:50 Vagrantfile -rwxr-xr-x@ 1 bealers staff 3841 9 Nov 08:00 provision.sh The Vagrant file tells Vagrant how to configure the virtual hardware of your development machine. Skipping over some of the finer details, here’s what’s in that Vagrant file: www.vm.box = "ubuntu/trusty64" Use Ubuntu 14.04 for the VM’s OS. Vagrant will only download this once. If another project uses the same OS, Vagrant will use a cached version. www.vm.hostname = "bealers-24ways.dev" Set the machine’s hostname. If, like us, you’re using the vagrant-hostsupdater plugin, this will also get added to your hosts file, pointing to the virtual machine’s IP address. www.vm.provider :virtualbox do |vb| vb.customize ["modifyvm", :id, "--cpus", "2" ] end Here’s an example of configuring the virtual machine’s hardware on the fly. In this case we want two virtual processors. Note: this is specific for the VirtualBox provider, but you could also have a section for VMware or other supported virtualisation software. www.vm.network "private_network", ip: "192.168.13.37" This specifies that we want a private networking link between your computer and the virtual machine. It’s probably best to use a reserved private subnet like 192.168.0.0/16 or 10.0.0.0/8 www.vm.synced_folder "../", "/var/www/24ways", owner: "www-data", group: "www-data" A particularly handy bit of Vagrant magic. This maps your local 24ways parent folder to /var/www/24ways on the virtual machine. This means the virtual machine already has direct access to your code and so do you. There’s no messy copying or synchronisation – just edit your files and immediately run them on the server. www.vm.provision :shell, :path => "provision.sh" This is where we specify the provisioner, the script that will be executed on the machine. If you open up the provisioner you’ll see it’s a bash script that does things like: install Apache, PHP, MySQL and related libraries configure the libraries: set permissions, enable logging create a database and grant some access rights set up some code for us to develop on; in this case, fire up a vanilla WordPress installation To get this all up and running you simply need to run Vagrant from within the vagrant folder: $ vagrant up You should now get a Matrix-like stream of stuff shooting up the screen. If this is the first time Vagrant has used this particular operating system image – remember we’ve specified the latest version of Ubuntu – it’ll download the disc image and cache it for future reuse. Then all the packages are downloaded and installed and finally all our configuration steps occur incluing the download and configuration of WordPress. Halfway through proceedings it’s likely that the process will halt at a prompt something like this: ==> www: adding to (/etc/hosts) : 192.168.13.37 bealers-24ways.dev # VAGRANT: 2dbfbced1b1e79d2a0942728a0a57ece (www) / 899bd80d-4251-4f6f-91a0-d30f2d9918cc Password: You need to enter your password to give vagrant sudo rights to add the IP address and hostname mapping to your local hosts file. Once finished, fire up your browser and go to http://bealers-24ways.dev. You should see a default WordPress installation. The username for wp-admin is admin and the password is 24ways. If you take a look at your local filesystem the 24ways folder should now look like: $ cd ../ $ ls -l -rw-r--r--@ 1 bealers staff 13074 9 Nov 10:14 bealers-24ways.md drwxr-xr-x 21 bealers staff 714 9 Nov 10:06 code drwxr-xr-x 3 bealers staff 102 9 Nov 10:06 etc -rw-r--r--@ 1 bealers staff 118152 9 Nov 10:08 it-works.png drwxr-xr-x 5 bealers staff 170 9 Nov 10:03 vagrant -rwxr-xr-x 1 bealers staff 1315849 9 Nov 10:06 wp-cli $ cd vagrant/ $ ls -l -rw-r--r--@ 1 bealers staff 1661 9 Nov 09:41 Vagrantfile -rwxr-xr-x@ 1 bealers staff 3836 9 Nov 10:06 provision.sh The code folder contains all the WordPress files. You can edit these directly and refresh that page to see your changes instantly. Staying in the vagrant folder, we’ll now SSH to the machine and have a quick poke around. $ vagrant ssh Welcome to Ubuntu 14.04.1 LTS (GNU/Linux 3.13.0-39-generic x86_64) * Documentation: https://help.ubuntu.com/ System information as of Sun Nov 9 10:03:38 UTC 2014 System load: 1.35 Processes: 102 Usage of /: 2.7% of 39.34GB Users logged in: 0 Memory usage: 16% IP address for eth0: 10.0.2.15 Swap usage: 0% Graph this data and manage this system at: https://landscape.canonical.com/ Get cloud support with Ubuntu Advantage Cloud Guest: http://www.ubuntu.com/business/services/cloud 0 packages can be updated. 0 updates are security updates. vagrant@bealers-24ways:~$ You’re now logged in as the Vagrant user; if you want to become root this is easy: vagrant@bealers-24ways:~$ sudo su - root@bealers-24ways:~# Or you could become the webserver user, which is a good idea if you’re editing the web files directly on the server: root@bealers-24ways:~# su - www-data www-data@bealers-24ways:~$ www-data’s home directory is /var/www so we should be able to see our magically mapped files: www-data@bealers-24ways:~$ ls -l total 4 drwxr-xr-x 1 www-data www-data 306 Nov 9 10:09 24ways drwxr-xr-x 2 root root 4096 Nov 9 10:05 html www-data@bealers-24ways:~$ cd 24ways/ www-data@bealers-24ways:~/24ways$ ls -l total 1420 -rw-r--r-- 1 www-data www-data 13682 Nov 9 10:19 bealers-24ways.md drwxr-xr-x 1 www-data www-data 714 Nov 9 10:06 code drwxr-xr-x 1 www-data www-data 102 Nov 9 10:06 etc -rw-r--r-- 1 www-data www-data 118152 Nov 9 10:08 it-works.png drwxr-xr-x 1 www-data www-data 170 Nov 9 10:03 vagrant -rwxr-xr-x 1 www-data www-data 1315849 Nov 9 10:06 wp-cli We can also see some of our bespoke configurations: www-data@bealers-24ways:~/24ways$ cat /etc/php5/mods-available/siftware.ini upload_max_filesize = 15M log_errors = On display_errors = On display_startup_errors = On error_log = /var/log/apache2/php.log memory_limit = 1024M date.timezone = Europe/London www-data@bealers-24ways:~/24ways$ ls -l /etc/apache2/sites-enabled/ total 0 lrwxrwxrwx 1 root root 43 Nov 9 10:06 bealers-24ways.dev.conf -> /var/www/24ways/etc/bealers-24ways.dev.conf If you want to leave the server, simply type Ctrl+D a few times and you’ll be back where you started. www-data@bealers-24ways:~/24ways$ logout root@bealers-24ways:~# logout vagrant@bealers-24ways:~$ logout Connection to 127.0.0.1 closed. $ You can now halt the machine: $ vagrant halt ==> www: Attempting graceful shutdown of VM... ==> www: Removing hosts Bonus level The example I’ve provided isn’t very realistic. In the real world I’d expect the Vagrant file and provisioner to be included with the project and for it not to create the directory structure, which should already exist in your project. The same goes for the Apache VirtualHost file. You’ll also probably have a default SQL script to populate the database. As you work with Vagrant you might start to find bash provisioning to be quite limiting, especially if you are working on larger projects which use more than one server. In that case I would suggest you take a look at Ansible, Puppet or Chef. We use Ansible because we like YAML but they all do the same sort of thing. The main benefit is being able to use the same Vagrant provisioning scripts to also provision test, staging and production environments using your build workflows. Having to supply a password so the hosts file can be updated gets annoying very quicky so you can give Vagrant sudo rights: $ sudo visudo Add these lines to the bottom (Shift+G then i then Ctrl+V then Esc then :wq) Cmnd_Alias VAGRANT_HOSTS_ADD = /bin/sh -c echo "*" >> /etc/hosts Cmnd_Alias VAGRANT_HOSTS_REMOVE = /usr/bin/sed -i -e /*/ d /etc/hosts %staff ALL=(root) NOPASSWD: VAGRANT_HOSTS_ADD, VAGRANT_HOSTS_REMOVE Vagrant caches the operating system images that you download but it’ll download the installed software packages every time. You can get around this by using a plugin like vagrant-cachier or, if you’re really keen, maintain local Apt repositories (or whatever the equivalent is for your server architecture). At some point you might start getting a large number of virtual machines running on your poor hardware all at the same time, especially if you’re switching between projects a lot and each of those projects use lots of servers. We’re just getting to that stage now, so are considering a medium-term move to a containerised option like Docker, which seems to be maturing now. If you are keen not to use any command line tools whatsoever and you’re on OS X then you could check out Vagrant Manager as it looks quite shiny. Finally, there are a huge amount of resources to give you pre-built Vagrant machines from the likes of VVV for Wordpress, something similar for Perch, PuPHPet for generating various configurations, and a long list of pre-built operating systems at VagrantBox.es. Wrapping up Hopefully you can now see why it might be worthwhile to add Vagrant to your development workflow. Whether you’re an agency drafting in freelancers or a one-person band running lots of sites on your laptop using MAMP or something similar. Vagrant makes it easy to launch exact copies of the same machine in a repeatable and version controlled way. The learning curve isn’t too steep and, once configured, you can forget about it and focus on getting your work done. 2014 Darren Beale darrenbeale 2014-12-05T00:00:00+00:00 https://24ways.org/2014/what-is-vagrant-and-why-should-i-care/ process
29 What It Takes to Build a Website In 1994 we lost Kurt Cobain and got the world wide web as a weird consolation prize. In the years that followed, if you’d asked me if I knew how to build a website I’d have said yes, I know HTML, so I know how to build a website. If you’d then asked me what it takes to build a website, I’d have had to admit that HTML would hardly feature. Among the design nerdery and dev geekery it’s easy to think that the nuts and bolts of building a page just need to be multiplied up and Ta-da! There’s your website. That can certainly be true with weekend projects and hackery for fun. It works for throwing something together on GitHub or experimenting with ideas on your personal site. But what about working professionally on client projects? The web is important, so we need to build it right. It’s 2015 – your job involves people paying you money for building websites. What does it take to build a website and to do it right? What practices should we adopt to make really great, successful and professional web projects in 2015? I put that question to some friends and 24 ways authors to see what they thought. Getting the tech right Inevitably, it all starts with the technology. We work in a technical medium, after all. From Notepad and WinFTP through to continuous integration and deployment – how do you build sites? Create a stable development environment There’s little more likely to send a web developer into a wild panic and a client into a wild rage than making a new site live and things just not working. That’s why it’s important to have realistic development and staging environments that mimic the live server as closely as possible. Are you in the habit of developing new sites right on the client’s server? Or maybe in a subfolder on your local machine? It’s time to reconsider. Charlie Perrins writes: Don’t work on a live server – this feels like one of those gear-changing moments for a developer’s growth. Build something that works just as well locally on your own machine as it does on a live server, and capture the differences in the code between the local and live version in a single config file. Ultimately, if you can get all the differences between environments down to a config level then you’ll be in a really good position to automate the deployment process at some point in the future. Anything that creates a significant difference between the development and the live environments has the potential to cause problems you won’t know about until the site goes live – and at that point the problems are very public and very embarrassing, not to mention unprofessional. A reasonable solution is to use a tool like MAMP PRO which enables you to set up an individual local website for each project you work on. Importantly, individual sites give you both consistency of paths between development and live, but also the ability to configure server options (like PHP versions and configuration, for example) to match the live site. Better yet is to use a virtual machine, managed with a tool such as Vagrant. If you’re interested in learning more about that, we have an article on that subject later in the series. Use source control Trent Walton writes: We use source control, and it’s become the centerpiece for how we handle collaboration, enhancements, and issues. It drives our process. I’m hoping by now that you’re either using source control for all your work, or feeling a nagging guilt that you should be. Be it Git, Mercurial, Subversion (name your poison), a revision control system enables you to keep track of changes, revert anything that breaks, and keep rolling backups of your project. The benefits only start there, and Charlie Perrins recommends using source control “not just as a personal backup of your code, but as a way to play nicely with other developers.“ Noting the benefits when collaborating with other developers, he adds: Graduating from being the sole architect of your codebase to contributing to a shared codebase is a huge leap for a developer. Perhaps a practical way for people who tend to work on their own to do that would be to submit a pull request or a patch to an open source project or plugin.” Richard Rutter of Clearleft sees clear advantages for the client, too. He recommends using source control “preferably in some sort of collaborative environment that you can open up or hand over to the client” – a feature found with hosted services such as GitHub. If you’d like to hone your Git skills, Emma Jane Westby wrote Git for Grown-ups in last year’s 24 ways. Don’t repeat, automate! Tim Kadlec is a big proponent of automating your build process: I’ve been hammering that home to every client I’ve had this year. It’s amazing how many companies don’t really have a formal build/deployment process in place. So many issues on the web (performance, accessibility, etc.) can be greatly improved just by having a layer of automation involved. For example, graphic editing software spits out ridiculously bloated images. Very frequently, that’s what ends up getting put on a site. If you have a build process, you can have the compression automated and start seeing immediate gains for no effort. On a recent project, they were able to shave around 1.5MB from their site weight simply by automating compression. Once you have your code in source control, some of that automation can be made easier. Brian Suda writes: We have a few bash scripts that run on git commit: they compile the less, jslint and remove white-space, basically the 3 Cs, Compress, Concatenate, Combine. This is now part of our workflow without even realising it. One great way to get started with a build process is to use a tool like Grunt, and a great way to get started with Grunt is to read Chris Coyier’s Grunt for People Who Think Things Like Grunt are Weird and Hard. Tim reinforces: Issues like [image compression] — or simple accessibility issues like alt tags on images — should never be able to hit a live server. If you can detect it, you can automate it. And if you can automate it, you can free up time for designers and developers to focus on more challenging — and interesting — problems. A clear call to arms to tighten up and formalise development and deployment practices. The less that has to be done manually or is susceptible to change, the less that can go wrong when a site is built and deployed. Any procedures that are automated are no longer dependant on a single person’s knowledge, making it easier to build your team or just cope when someone important is out of the office or leaves. If you’re interested in kicking the FTP habit and automating your site deployments, we have an article later in the series just for you. Build systems, not sites One big theme arising this year was that of building websites as systems, not as individual pages. Brad Frost: For me, teams making websites in 2015 shouldn’t be working on just-another-redesign redesign. People are realizing that in order to make stable, future-friendly, scalable, extensible web experiences they’re going to need to think more systematically. That means crafting deliberate and thoughtful design systems. That means establishing front-end style guides. That means killing the out-dated, siloed, assembly-line waterfall process and getting cross-disciplinary teams working together in meaningful ways. That means treating development as design. That means treating performance as design. That means taking the time out of the day to establish the big picture, rather than aimlessly crawling along quarter by quarter. Designer and developer Jina Bolton also advocates the use of style guides, and recommends making the guide a project deliverable: Consider adding on a style guide/UI library to your project as a deliverable for maintainability and thinking through all UI elements and components. Val Head agrees: “build and maintain a style guide for each project” she wrote. On the subject of approaching a redesign, she added: A UI inventory goes a long way to helping get your head around what a design system needs in the early stages of a redesign project. So what about that old chestnut, responsive web design? Should we be making sites responsive by default? How about mobile first? Richard Rutter: Think mobile first unless you have a very good reason not to. Remember to take the client with you on this principle, otherwise it won’t work as a convincing piece of design. Trent Walton adds: The more you can test and sort of skew your perception for what is typical on the web, the better. 4k displays hooked up to 100Mbps connections can make one extremely unsympathetic. The value of testing with real devices is something Ruth John appreciates. She wrote: I still have my own small device lab at home, even though I work permanently for a well-established company (which has a LOT of devices at its disposal) – it just means I can get a good overview of how things are looking during development. And speaking of systems, Mark Norman Francis recommends the use of measuring tools to aid the design process; “[U]se analytics and make decisions from actual data” he suggests, rather than relying totally on intuition. Tim Kadlec adds a word on performance planning: I think having a performance budget in place should now be a given on any project. We’ve proven pretty conclusively through a hundred and one case studies that performance matters. And over the last year or so, we’ve really seen a lot of great tools emerge to help track and enforce performance budgets. There’s not really a good excuse for not using one any more. It’s clear that in the four years since Ethan Marcotte’s Responsive Web Design article the diversity of screen sizes, network connection speeds and input methods has only increased. New web projects should presume visitors will be using anything from a watch up to a big screen desktop display, and from being offline, through to GPRS, 3G and fast broadband. Will it take more time to design and build for those constraints? Yes, it most likely will. If Internet Explorer is brave enough to ask to be your default browser, you can be brave enough to tell your client they need to build responsively. Working collaboratively A big part of delivering a successful website project is how we work together, both as a design team and a wider project team with the client. Val Head recommends an open line of communication: Keep conversations going. With clients, with teammates. Talking is so important with the way we work now. A good team conversation place, like Slack, is slowly becoming invaluable for me too. Ruth John agrees: We’ve recently opened up our lines of communication by using Slack. It has transformed the way we work. We’re easily more productive and collaborative on projects, as well as making it a lot easier for us all to work remotely (including freelancers). She goes on to point out how tools can be combined to ease team communication without adding further complications: We have a private GitHub organisation (which everyone who works with us is granted access to), which not only holds all our project code but also a team wiki. This has lots of information to get you set up within the team, as well as coding guidelines and best practices and other admin info, like contact numbers/emails for the team. Small-A agile is also the theme of the day, with Mark Norman Francis suggesting an approach of “small iterations with constant feedback around individual features, not spec-it-all-first”. He also encourages you to review as you go, at each stage of the project: Always reflect on what went well and what went badly, and how you can learn from that, even if not Doing Agile™. Ultimately “best practices” should come from learning lessons (both good and bad). Richard Rutter echoes this, warning against working in isolation from the client for too long: Avoid big reveals. Your engagement with the client should be participatory. In business no one likes surprises. This experience rings true for Ruth John who recommends involving real users in the feedback loop, not just the client: We also try and get feedback on what we’re building as soon and as often as we can with our stakeholders/clients and real users. We should also remember that our role is to serve the client’s needs, not just bill them for whatever we can. Brian Suda adds: Don’t sell clients on things they don’t need. We can spout a lot of jargon and scare clients into thinking you are a god. We can do things few can now, but you can’t rip people off because they are unknowledgeable. But do clients know what they’re getting, even when they see it? Trent Walton has an interesting take: We focus on prototypes over image-based comps at all costs, especially when meetings are involved. It’s much easier to assess a prototype, and too often with image-based comps, discussions devolve into how something might feel when actually live, or how a layout could change to fit a given viewport. Val Head also likes to get work into the browser: Sketch design ideas with any software you like, but get to the browser as soon as possible. Beyond your immediate team, Emma Jane Westby has advice for looking further afield: Invest time into building relationships within your (technical) community. You never know when you might be able to lend a hand; or benefit from someone who’s able to lend theirs. And when things don’t go according to plan, Brian Suda has the following advice: If something doesn’t work out, be professional and don’t burn bridges. It will always come back to you. The best work comes from working collaboratively, not just as a team within an agency or department, but with the client and stakeholders too. If doing your job and chucking it over the fence ever worked, it certainly doesn’t fly any more. You can work in isolation, but doing really great work requires collaboration. The business end When you’re building sites professionally, every team member has to think about the business aspects. Estimating time, setting billing rates, and establishing deliverables are all part of the job. In 2008, Andrew Clarke gave us the Contract Killer sample contract we could use to establish a working agreement for a web design project. Richard Rutter agrees that contracts are still an essential part of business: They are there for both parties’ protection. Make sure you know what will happen if you decide you don’t want to work with the client any more (it happens) and, of course, what circumstances mean they can stop taking your services. Having a contract is one thing, but does it adequately protect both you and the client? Emma Jane Westby adds: Find a good IP lawyer/legal counsel. I routinely had an IP lawyer read all of my contracts to find loopholes I wouldn’t have noticed. I didn’t always change the contract, but at least I knew what might come back to bite me. So, you have a contract in place, and know what the project is. Brian Suda recommends keeping track of time and making sure you bill fairly for the hours the project costs you: If I go to a meeting and they are 15 minutes late, the billing clock has already started. They can’t expect me to be in the 1h meeting and not bill for the extra 15–30 minutes they wasted. It goes both ways too. You need to do your best to respect their deadlines and time frame – this is always hard to get right. As ever, it’s good business to do good business. Perhaps we can at last shed the old image of web designers being snowboarding layabouts and demonstrate to clients that we care as much about conducting professional business as they do. Time to review It’s a lot to take in. Some of these ideas and practices will be familiar, others new and yet to be evaluated. The web moves at a fast pace, and we need to be constantly reexamining our tools, techniques and working practices. The most important thing is not to blindly adopt any and all suggestions, but to carefully look at what the benefits might be and decide how they apply to your work. Could you benefit from more formalised development and deployment procedures? Would your design projects run more smoothly and have a longer maintainable life if you approached the solution as a componentised system rather than a series of pages? Are your teams structured in a way that enables the most fluid communication, or are there changes you could make? Are your billing procedures and business agreements serving you and your clients in the best way possible? The new year is a good time to look at your working practices and see what can be improved, and maybe this time next year you’ll look back and think “thank goodness we don’t work like that any more”. 2014 Drew McLellan drewmclellan 2014-12-01T00:00:00+00:00 https://24ways.org/2014/what-it-takes-to-build-a-website/ business
299 What the Heck Is Inclusive Design? Naming things is hard. And I don’t just mean CSS class names and JSON properties. Finding the right term for what we do with the time we spend awake and out of bed turns out to be really hard too. I’ve variously gone by “front-end developer”, “user experience designer”, and “accessibility engineer”, all clumsy and incomplete terms for labeling what I do as an… erm… see, there’s the problem again. It’s tempting to give up entirely on trying to find the right words for things, but this risks summarily dispensing with thousands of years spent trying to qualify the world around us. So here we are again. Recently, I’ve been using the term “inclusive design” and calling myself an “inclusive designer” a lot. I’m not sure where I first heard it or who came up with it, but the terminology feels like a good fit for the kind of stuff I care to do when I’m not at a pub or asleep. This article is about what I think “inclusive design” means and why I think you might like it as an idea. Isn’t ‘inclusive design’ just ‘accessibility’ by another name? No, I don’t think so. But that’s not to say the two concepts aren’t related. Note the ‘design’ part in ‘inclusive design’ — that’s not just there by accident. Inclusive design describes a design activity; a way of designing things. This sets it apart from accessibility — or at least our expectations of what ‘accessibility’ entails. Despite every single accessibility expert I know (and I know a lot) recommending that accessibility should be integrated into design process, it is rarely ever done. Instead, it is relegated to an afterthought, limiting its effect. The term ‘accessibility’ therefore lacks the power to connote design process. It’s not that we haven’t tried to salvage the term, but it’s beginning to look like a lost cause. So maybe let’s use a new term, because new things take new names. People get that. The ‘access’ part of accessibility is also problematic. Before we get ahead of ourselves, I don’t mean access is a problem — access is good, and the more accessible something is the better. I mean it’s not enough by itself. Imagine a website filled with poorly written and lackadaisically organized information, including a bunch of convoluted and confusing functionality. To make this site accessible is to ensure no barriers prevent people from accessing the content. But that doesn’t make the content any better. It just means more people get to suffer it. Whoopdidoo. Access is certainly a prerequisite of inclusion, but accessibility compliance doesn’t get you all the way there. It’s possible to check all the boxes but still be left with an unusable interface. And unusable interfaces are necessarily inaccessible ones. Sure, you can take an unusable interface and make it accessibility compliant, but that only placates stakeholders’ lawyers, not users. Users get little value from it. So where have we got to? Access is important, but inclusion is bigger than access. Inclusive design means making something valuable, not just accessible, to as many people as we can. So inclusive design is kind of accessibility + UX? Closer, but there are some problems with this definition. UX is, you will have already noted, a broad term encompassing activities ranging from conducting research studies to optimizing the perceived affordance of interface elements. But overall, what I take from UX is that it’s the pursuit of making interfaces understandable. As it happens, WCAG 2.0 already contains an ‘Understandable’ principle covering provisions such as readability, predictability and feedback. So you might say accessibility — at least as described by WCAG — already covers UX. Unfortunately, the criteria are limited, plus some really important stuff (like readability) is relegated to the AAA level; essentially “bonus points if you get the time (you won’t).” So better to let UX folks take care of this kind of thing. It’s what they do. Except, therein lies a danger. UX professionals don’t tend to be well versed in accessibility, so their ‘solutions’ don’t tend to work for that many people. My friend Billy Gregory coined the term SUX, or “Some UX”: if it doesn’t work for different users, it’s only doing part of the job it should be. SUX won’t do, but it’s not just a disability issue. All sorts of user circumstances go unchecked when you’re shooting straight for what people like, and bypassing what people need: device type, device settings, network quality, location, native language, and available time to name just a few. In short, inclusive design means designing things for people who aren’t you, in your situation. In my experience, mainstream UX isn’t very good at that. By bolting accessibility onto mainstream UX we labor under the misapprehension that most people have a ‘normal’ experience, a few people are exceptions, and that all of the exceptions pertain to disability directly. So inclusive design isn’t really about disability? It is about disability, but not in the same way as accessibility. Accessibility (as it is typically understood, anyway) aims to make sure things work for people with clinically recognized disabilities. Inclusive design aims to make sure things work for people, not forgetting those with clinically recognized disabilities. A subtle, but not so subtle, difference. Let’s go back to discussing readability, because that’s a good example. Now: everyone benefits from readable text; text with concise sentences and widely-understood words. It certainly helps people with cognitive impairments, but it doesn’t hinder folks who have less trouble with comprehension. In fact, they’ll more than likely be thankful for the time saved and the clarity. Readable text covers the whole gamut. It’s — you’ve got it — inclusive. Legibility is another one. A clear, well-balanced typeface makes the reading experience less uncomfortable and frustrating for all concerned, including those who have various forms of visual dyslexia. Again, everyone’s happy — so why even contemplate a squiggly, sketchy typeface? Leave well alone. Contrast too. No one benefits from low contrast; everyone benefits from high contrast. Simple. There’s no more work involved, it just entails better decision making. And that’s what design is really: decision making. How about zoom support? If you let your users pinch zoom on their phones they can compensate for poor eyesight, but they can also increase the touch area of controls, inspect detail in images, and compose better screen shots. Unobtrusively supporting options like zoom makes interfaces much more inclusive at very little cost. And when it comes to the underlying HTML code, you’re in luck: it has already been designed, from the outset, to be inclusive. HTML is a toolkit for inclusion. Using the right elements for the job doesn’t just mean the few who use screen readers benefit, but keyboard accessibility comes out-of-the-box, you can defer to browser behavior rather than writing additional scripts, the code is easier to read and maintain, and editors can create content that is effortlessly presentable. Wait… are you talking about universal design? Hmmm. Yes, I guess some folks might think of “universal design” and “inclusive design” as synonymous. I just really don’t like the term universal in this context. The thing is, it gives the impression that you should be designing for absolutely everyone in the universe. Though few would adopt a literal interpretation of “universal” in this context, there are enough developers who would deliberately misconstrue the term and decry universal design as an impossible task. I’ve actually had people push back by saying, “what, so I’ve got to make it work for people who are allergic to computers? What about people in comas?” For everyone’s sake, I think the term ‘inclusive’ is less misleading. Of course you can’t make things that everybody can use — it’s okay, that’s not the aim. But with everything that’s possible with web technologies, there’s really no need to exclude people in the vast numbers that we usually are. Accessibility can never be perfect, but by thinking inclusively from planning, through prototyping to production, you can cast a much wider net. That means more and happier users at very little if any more effort. If you like, inclusive design is the means and accessibility is the end — it’s just that you get a lot more than just accessibility along the way. Conclusion That’s inclusive design. Or at least, that’s a definition for a thing I think is a good idea which I identify as inclusive design. I’ll leave you with a few tips. Involve code early Web interfaces are made of code. If you’re not working with code, you’re not working on the interface. That’s not to say there’s anything wrong with sketching or paper prototyping — in fact, I recommend paper prototyping in my book on inclusive design. Just work with code as soon as you can, and think about code even before that. Maintain a pattern library of coded solutions and omit any solutions that don’t adhere to basic accessibility guidelines. Respect conventions Your content should be fresh, inventive, radical. Your interface shouldn’t. Adopt accepted conventions in the appearance, placement and coding of interface elements. Users aren’t there to experience interface design; they’re there to use an interface. In other words: stop showing off (unless, of course, the brief is to experiment with new paradigms in interface design, for an audience of interface design researchers). Don’t be exact “Perfection is the enemy of good”. But the pursuit of perfection isn’t just to be avoided because nothing ever gets finished. Exacting design also makes things inflexible and brittle. If your design depends on elements retaining precise coordinates, they’ll break easily when your users start adjusting font settings or zooming. Choose not to position elements exactly or give them fixed, “magic number” dimensions. Make less decisions in the interface so your users can make more decisions for it. Enforce simplicity The virtue of simplicity is difficult to overestimate. The simpler an interface is, the easier it is to use for all kinds of users. Simpler interfaces require less code to make too, so there’s an obvious performance advantage. There are many design decisions that require user research, but keeping things simple is always the right thing to do. Not simplified or simple-seeming or simplistic, but simple. Do a little and do it well, for as many people as you can. 2016 Heydon Pickering heydonpickering 2016-12-07T00:00:00+00:00 https://24ways.org/2016/what-the-heck-is-inclusive-design/ process
60 What’s Ahead for Your Data in 2016? Who owns your data? Who decides what can you do with it? Where can you store it? What guarantee do you have over your data’s privacy? Where can you publish your work? Can you adapt software to accommodate your disability? Is your tiny agency subject to corporate regulation? Does another country have rights over your intellectual property? If you aren’t the kind of person who is interested in international politics, I hate to break it to you: in 2016 the legal foundations which underpin our work on the web are being revisited in not one but three major international political agreements, and every single one of those questions is up for grabs. These agreements – the draft EU Data Protection Regulation (EUDPR), the Trans-Pacific Partnership (TPP), and the draft Transatlantic Trade and Investment Partnership (TTIP) – stand poised to have a major impact on your data, your workflows, and your digital rights. While some proposed changes could protect the open web for the future, other provisions would set the internet back several decades. In this article we will review the issues you need to be aware of as a digital professional. While each of these agreements covers dozens of topics ranging from climate change to food safety, we will focus solely on the aspects which pertain to the work we do on the web. The Trans-Pacific Partnership The Trans-Pacific Partnership (TPP) is a free trade agreement between the US, Japan, Malaysia, Vietnam, Singapore, Brunei, Australia, New Zealand, Canada, Mexico, Chile and Peru – a bloc comprising 40% of the world’s economy. The agreement is expected to be signed by all parties, and thereby to come into effect, in 2016. This agreement is ostensibly about the bloc and its members working together for their common interests. However, the latest draft text of the TPP, which was formulated entirely in secret, has only been made publicly available on a Medium blog published by the U.S. Trade Representative which features a patriotic banner at the top proclaiming “TPP: Made in America.” The message sent about who holds the balance of power in this agreement, and whose interests it will benefit, is clear. By far the most controversial area of the TPP has centred around the provisions on intellectual property. These include copyright terms of up to 120 years, mandatory takedowns of allegedly infringing content in response to just one complaint regardless of that complaint’s validity, heavy and disproportionate penalties for alleged violations, and – most frightening of all – government seizures of equipment allegedly used for copyright violations. All of these provisions have been raised without regard for the fact that a trade agreement is not the appropriate venue to negotiate intellectual property law. Other draft TPP provisions would restrict the digital rights of people with disabilities by banning the workarounds they use every day. These include no exemptions for the adaptations of copywritten works for use in accessible technology (such as text-to-speech in ebook readers), a ban on circumventing DRM or digital locks in order to convert a file to an accessible format, and requiring the takedown of adapted works, such as a video with added subtitles, even if that adaptation would normally have fallen under the definition of fair use. The e-commerce provisions would prohibit data localisation, the practice of requiring data to be physically stored on servers within a country’s borders. Data localisation is growing in popularity following the Snowden revelations, and some of your own personal data may have been recently “localised” in response to the Safe Harbor verdict. Prohibiting data localisation through the TPP would address the symptom but not the cause. The Electronic Frontier Foundation has published an excellent summary of the digital rights issues raised by the agreement along with suggested actions American readers can take to speak out. Transatlantic Trade and Investment Partnership TTIP stands for the Transatlantic Trade and Investment Partnership, a draft free trade agreement between the United States and the EU. The plan has been hugely controversial and divisive, and the internet and digital provisions of the draft form just a small part of that contention. The most striking digital provision of TTIP is an attempt to circumvent and override European data protection law. As EDRI, a European digital rights organisation, noted: “the US proposal would authorise the transfer of EU citizens’ personal data to any country, trumping the EU data protection framework, which ensures that this data can only be transferred in clearly defined circumstances. For years, the US has been trying to bypass the default requirement for storage of personal data in the EU. It is therefore not surprising to see such a proposal being {introduced} in the context of the trade negotiations.” This draft provision was written before the Safe Harbor data protection agreement between the EU and US was invalidated by the Court of Justice of the European Union. In other words, there is no longer any protective agreement in place, and our data is as vulnerable as this political situation. However, data protection is a matter of its own law, the acting Data Protection Directive and the draft EU Data Protection Reform. A trade agreement, be it the TTIP or the TPP, is not the appropriate place to revamp a law on data protection. Other digital law issues raised by TTIP include the possibility of renegotiating standards on encryption (which in practice means lowering them) and renegotiating intellectual property rights such as copyright. The spectre of net neutrality has even put in an appearance, with an attempt to introduce rules on access to the internet itself being introduced as provisions. TTIP is still under discussion, and this month the EU trade representative said that “we agreed to further intensify our work during 2016 to help negotiations move forward rapidly.” This has been cleverly worded: this means the agreement has little chance of being passed or coming into effect in 2016, which buys civil society more precious time to speak out. The EU Data Protection Regulation On 15 December 2015 the European Commission announced their agreement on the text of the draft General Data Protection Regulation. This law will replace its predecessor, the EU Data Protection Regulation of 1995, which has done a remarkable job of protecting data privacy across the continent throughout two decades of constant internet evolution. The goal of the reform process has been to return power over data, and its uses, to citizens. Users will have more control over what data is captured about them, how it is used, how it is retained, and how it can be deleted. Businesses and digital professionals, in turn, will have to restructure their relationships with client and customer data. Compliance obligations will increase, and difficult choices will have to be made. However, this time should be seen as an opportunity to rethink our relationship with data. After Snowden, Schrems, and Safe Harbor, it is clear that we cannot go back to the way things were before. In an era of where every one of our heartbeats is recorded on a wearable device and uploaded to a surveilled data centre in another country, the need for reform has never been more acute. While texts of the draft GDPR are available, there is not enough mulled wine in the world that will help you get through them. Instead, the law firm Fieldfisher Waterhouse has produced this helpful infographic which will give you a good idea of the changes we can expect to see (view full size): The most surprising outcome announced on 15 December was the new regulation’s teeth. Under the new law, companies that fail to heed the updated data protection rules will face fines of up to 4% of their global turnover. Additionally, the law expands the liability for data protection to both the controller (the company hosting the data) and the data processor (the company using the data). The new law will also introduce a one-stop shop for resolving concerns over data misuse. Companies will no longer be able to headquarter their European operations in countries which are perceived to have relatively light-touch data protection enforcement (that means you, Ireland) as a means of automatically rejecting any complaints filed by citizens outside that country. For digital professionals, the most immediate concern is analytics. In fact, I am going to make a prediction: in 2016 we will begin to see the same misguided war on analytics that we saw on cookies. By increasing the legal liabilities for both data processors and controllers – in other words, the company providing the analytics as well as the site administrator studying them – the new regulation risks creating disproportionate burdens as well as the same “guilt by association” risks we saw in 2012. There have already been statements made by some within the privacy community that analytics are tracking, and tracking is surveillance, therefore analytics are evil. Yet “just don’t use analytics,” as was suggested by one advocate, is simply not an option. European regulators should consult with the web community to gain a clear understanding of why analytics are vital to everyday site administrators, and must find a happy medium that protects users’ data without criminalising every website by default. No one wants a repeat of the crisis of consent, as well as the scaremongering, caused by the cookie law. Assuming the text is adopted in 2016, the new EU Data Protection Regulation would not come into effect until 2018. We have a considerable challenge ahead, but we also have plenty of time to get it right. 2015 Heather Burns heatherburns 2015-12-21T00:00:00+00:00 https://24ways.org/2015/whats-ahead-for-your-data-in-2016/ business
1 Why Bother with Accessibility? Web accessibility (known in other fields as inclusive design or universal design) is the degree to which a website is available to as many people as possible. Accessibility is most often used to describe how people with disabilities can access the web. How we approach accessibility In the web community, there’s a surprisingly inconsistent approach to accessibility. There are some who are endlessly dedicated to accessible web design, and there are some who believe it so intrinsic to the web that it shouldn’t be considered a separate topic. Still, of those who are familiar with accessibility, there’s an overwhelming number of designers, developers, clients and bosses who just aren’t that bothered. Over the last few months I’ve spoken to a lot of people about accessibility, and I’ve heard the same reasons to ignore it over and over again. Let’s take a look at the most common excuses. Excuse 1: “People with disabilities don’t really use the web” Accessibility will make your site available to more people — the inclusion case In the same way that the accessibility of a building isn’t just about access for wheelchair users, web accessibility isn’t just about blind users and screen readers. We can affect positively the lives of many people by making their access to the web easier. There are four main types of disability that affect use of the web: Visual Blindness, low vision and colour-blindness Auditory Profoundly deaf and hard of hearing Motor The inability to use a mouse, slow response time, limited fine motor control Cognitive Learning difficulties, distractibility, the inability to focus on large amounts of information None of these disabilities are completely black and white Examining deafness, it’s clear from the medical scale that there are many grey areas between full hearing and total deafness: mild moderate moderately severe severe profound totally deaf For eyesight, and brain conditions that affect what users see, there is a huge range of conditions and challenges: astigmatism colour blindness akinetopsia (motion blindness) scotopic visual sensitivity (visual stress related to light) visual agnosia (impaired recognition or identification of objects) While we might have medical and government-recognised definitions that tell us what makes a disability, day-to-day life is not so straightforward. People experience varying degrees of different conditions, and often one or more conditions at a time, creating a false divide when you view disability in terms of us and them. Impairments aren’t always permanent As we age, we’re more likely to experience different levels of visual, auditory, motor and cognitive impairments. We might have an accident or illness that affects us temporarily. We might struggle more earlier or later in the day. There are so many little physiological factors that affect the way people interact with the web that we can’t afford to make any assumptions based on our own limited experiences. Impairments might be somewhere between the user and the website There are also impairments that aren’t directly related to the user. Environmental factors have a huge effect on the way people interact with the web. These could be: Low bandwidth, or intermittent internet connection Bright light, rain, or other weather-based conditions Noisy environments, or a location where the user doesn’t want to disturb their neighbours with sound Browsing with mobile devices, games consoles and other non-desktop devices Browsing with legacy browsers or operating systems Such environmental factors show that it’s not just those with physical impairments who benefit from more accessible websites. We started designing responsive websites so we could be more future-friendly, and with a shared goal of better optimised experiences, accessibility should be at the core of responsive web design. Excuse 2: “We don’t want to affect the experience for the majority of our users” Accessibility will improve your site for all your users — the usability case On a basic level, the different disability groups, as shown in the inclusion case, equate to simple usability goals: Visual – make it easy to read Auditory – make it easy to hear Motor – make it easy to interact Cognitive – make it easy to understand and focus Taking care to ensure good usability in these areas will also have an impact on accessibility. Unless your site is catering specifically to a particular disability, where extreme optimisation is most beneficial, taking care to design with accessibility in mind will rarely negatively affect the experience of your wider audience. Excuse 3: “We don’t have the budget for accessibility” Accessibility will make you money — the business case By reducing your audience through ignoring accessibility, you’re potentially excluding the income from those users. Designing with accessibility in mind from the beginning of a project makes it easier to make small inexpensive optimisations as part of the design and development process, rather than bolting on costly updates to increase your potential audience later on. The following are excerpts from a white paper about companies that increased the accessibility of their websites to comply with government regulation. Improvements in accessibility doubled Legal and General’s life insurance sales online. Improvements in accessibility increased Tesco’s grocery home delivery sales by £13 million in 2005… To their surprise they found that many normal visitors preferred the ease of navigation and improved simplicity of the [parallel] accessible site and switched to use it. Tesco have replaced their ‘normal’ site with their accessible version and expect a further increase in revenues. Improvements in accessibility increased Virgin.net sales by 68%. Statistics all from WSI white paper: Improve your website’s usability and accessibility to increase sales (PDF). Excuse 4: “Accessible websites are ugly” Accessibility won’t stop your site from being beautiful — the beauty case Many people use ugly accessible websites as proof that all accessible websites are ugly. This just isn’t the case. I’ve compiled some examples of beautiful and accessible websites with screenshots of how they look through the Color Oracle simulator and how they perform when run through Webaim’s Wave accessibility checker tool. While automated tools are no substitute for real users, they can help you learn more about good practices, and give you guidance on where your site needs improvements to make it more accessible. Amazon.co.uk It may not be a decorated beauty, but Amazon is often first in functional design. It’s a huge website with a lot of interactive content, but it generates just five errors on the Wave test, and is easy to read under a Color Oracle filter. Screenshot of Amazon website Screenshot of Amazon’s Wave results – five errors Screenshot of Amazon through a Color Oracle filter 24 ways When Tim Van Damme redesigned 24 ways back in 2007, it was a striking and unusual design that showed what could be achieved with CSS and some imagination. Despite the complexity of the design, it gets an outstanding zero errors on the Wave test, and is still readable under a Color Oracle filter. Screenshot of pre-2013 24 ways website design Screenshot of 24 ways Wave results – zero errors Screenshot of 24ways through a Color Oracle filter Opera’s Shiny Demos Demos and prototypes are notorious for ignoring accessibility, but Opera’s Shiny Demos site shows how exploring new technologies doesn’t have to exclude anyone. It only gets one error on the Wave test, and looks fine under a Color Oracle filter. Screenshot of Opera’s Shiny Demos website Screenshot of Opera’s Shiny Demos Wave results – 1 error Screenshot of Opera’s Shiny Demos through a Color Oracle filter SoundCloud When a site is more app-like, relying on more interaction from the user, accessibility can be more challenging. However, SoundCloud only gets one error on the Wave test, and the colour contrast holds up well under a Color Oracle filter. Screenshot of SoundCloud website Screenshot of SoundCloud’s Wave results – one error Screenshot of SoundCloud through a Color Oracle filter Education and balance As with most web design, doing accessibility well is about combining your knowledge of accessibility with your project’s context to create a balance that serves your users’ needs. Your types of content and interactions will dictate one set of constraints. Your users’ needs and goals will dictate another. In broad terms, web design as a practice is finding the equilibrium between these constraints. And then there’s just caring. The web as a platform is open, affordable and available to many. Accessibility is our way to ensure that nobody gets shut out. 2013 Laura Kalbag laurakalbag 2013-12-10T00:00:00+00:00 https://24ways.org/2013/why-bother-with-accessibility/ design
205 Why Design Systems Fail Design systems are so hot right now, and for good reason. They promote a modular approach to building a product, and ensure organizational unity and stability via reusable code snippets and utility styles. They make prototyping a breeze, and provide a common language for both designers and developers. A design system is a culmination of several individual components, which can include any or all of the following (and more): Style guide or visual pattern library Design tooling (e.g. Sketch Library) Component library (where the components live in code) Code usage guidelines and documentation Design usage documentation Voice and tone guideline Animation language guideline Design systems are standalone (internal or external) products, and have proven to be very effective means of design-driven development. However, in order for a design system to succeed, everyone needs to get on board. I’d like to go over a few considerations to ensure design system success and what could hinder that success. Organizational Support Put simply, any product, including internal products, needs support. Something as cross-functional as a design system, which spans every vertical project team, needs support from the top and bottom levels of your organization. What I mean by that is that there needs to be top-level support from project managers up through VP’s to see the value of a design system, to provide resources for its implementation, and advocate for its use company-wide. This is especially important in companies where such systems are being put in place on top of existing, crufty codebases, because it may mean there needs to be some time and effort put in the calendar for refactoring work. Support from the bottom-up means that designers and engineers of all levels also need to support this system and feel responsibility for it. A design system is an organization’s product, and everyone should feel confident contributing to it. If your design system supports external clients as well (such as contractors), they too can become valuable teammates. A design system needs support and love to be nurtured and to grow. It also needs investment. Investment To have a successful design system, you need to make a continuous effort to invest resources into it. I like to compare this to working out. You can work out intensely for 3 months and see some gains, but once you stop working out, those will slowly fade away. If you continue to work out, even if its less often than the initial investment, you’ll see yourself maintaining your fitness level at a much higher rate than if you stopped completely. If you invest once in a design system (say, 3 months of overhauling it) but neglect to keep it up, you’ll face the same situation. You’ll see immediate impact, but that impact will fade as it gets out of sync with new designs and you’ll end up with strange, floating bits of code that nobody is using. Your engineers will stop using it as the patterns become outdated, and then you’ll find yourself in for another round of large investment (while dreading going through the process since its fallen so far out of shape). With design systems, small incremental investments over time lead to big gains overall. With this point, I also want to note that because of how they scale, design systems can really make a large impact across the platform, making it extremely important to really invest in things like accessibility and solid architecture from the start. You don’t want to scale a brittle system that’s not easy to use. Take care of your design systems, and keep working on them to ensure their effectiveness. One way to ensure this is to have a dedicated team working on this design system, managing tickets and styling updates that trickle out to the rest of your company. Responsibility With some kind of team to act as an owner of a design system, whether it be the design team, engineering team, or a new team made of both designers and engineers (the best option), your company is more likely to keep a relevant, up-to-date system that doesn’t break. This team is responsible for a few things: Helping others get set up on the system (support) Designing and building components (development) Advocating for overall UI consistency and adherence (evangelism) Creating a rollout plan and update system (product management) As you can see, these are a lot of roles, so it helps to have multiple people on this team, at least part of the time, if you can. One thing I’ve found to be effective in the past is to hold office hours for coworkers to book slots within to help them get set up and to answer any questions about using the system. Having an open Slack channel also helps for this sort of thing, as well as for bringing up bugs/issues/ideas and being an channel for announcements like new releases. Communication Once you have resources and a plan to invest in a design system, its really important that this person or team acts as a bridge between design and engineering. Continuous communication is really important here, and the way you communicate is even more important. Remember that nobody wants to be told what to do or prescribed a solution, especially developers, who are used to a lot of autonomy (usually they get to choose their own tools at work). Despite how much control the other engineers have on the process, they need to feel like they have input, and feel heard. This can be challenging, especially since ultimately, some party needs to be making a final decision on direction and execution. Because it’s a hard balance to strike, having open communication channels and being as transparent as possible as early as possible is a good start. Buy-in For all of the reasons we’ve just looked over, good communication is really important for getting buy-in from your users (the engineers and designers), as well as from product management. Building and maintaining a design system is surprisingly a lot of people-ops work. To get buy-in where you don’t have a previous concensus that this is the right direction to take, you need to make people want to use your design system. A really good way to get someone to want to use a product is to make it the path of least resistance, to show its value. Gather examples and usage wins, because showing is much more powerful than telling. If you can, have developers use your product in a low-stakes situation where it provides clear benefits. Hackathons are a great place to debut your design system. Having a hackathon internally at DigitalOcean was a perfect opportunity to: Evangelize for the design system See what people were using the component library for and what they were struggling with (excellent user testing there) Get user feedback afterward on how to improve it in future iterations Let people experience the benefits of using it themselves These kinds of moments, where people explore on their own are where you can really get people on your side and using the design system, because they can get their hands on it and draw their own conclusions (and if they don’t love it — listen to them on how to improve it so that they do). We don’t always get so lucky as to have this sort of instantaneous user feedback from our direct users. Architecture I briefly mentioned the scalable nature of design systems. This is exactly why it’s important to develop a solid architecture early on in the process. Build your design system with growth and scalability in mind. What happens if your company acquires a new product? What happens when it develops a new market segment? How can you make sure there’s room for customization and growth? A few things we’ve found helpful include: Namespacing Use namespacing to ensure that the system doesn’t collide with existing styles if applying it to an existing codebase. This means prefixing every element in the system to indicate that this class is a part of the design system. To ensure that you don’t break parts of the existing build (which may have styled base elements), you can namespace the entire system inside of a parent class. Sass makes this easy with its nested structure. This kind of namespacing wouldn’t be necessary per se on new projects, but it is definitely useful when integrating new and old styles. Semantic Versioning I’ve used Semantic Versioning on all of the design systems I’ve ever worked on. Semantic versioning uses a system of Major.Minor.Patch for any updates. You can then tag released on Github with versioned updates and ensure that someone’s app won’t break unintentionally when there is an update, if they are anchored to a specific version (which they should be). We also use this semantic versioning as a link with our design system assets at DigitalOcean (i.e. Sketch library) to keep them in sync, with the same version number corresponding to both Sketch and code. Our design system is served as a node module, but is also provided as a series of built assets using our CDN for quick prototyping and one-off projects. For these built assets, we run a deploy script that automatically creates folders for each release, as well as a latest folder if someone wanted the always-up-to-date version of the design system. So, semantic versioning for the system I’m currently building is what links our design system node module assets, sketch library assets, and statically built file assets. The reason we have so many ways of consuming our design system is to make adoption easier and to reduce friction. Friction A while ago, I posed the question of why design systems become outdated and unused, and a major conclusion I drew from the conversation was: “If it’s harder for people to use than their current system, people just won’t use it” You have to make your design system the path of least resistance, lowering cognitive overhead of development, not adding to it. This is vital. A design system is intended to make development much more efficient, enforce a consistent style across sites, and allow for the developer to not worry as much about small decisions like naming and HTML semantics. These are already sorted out for them, meaning they can focus on building product. But if your design system is complicated and over-engineered, they may find it frustrating to use and go back to what they know, even if its not the best solution. If you’re a Sass expert, and base your system on complex mixins and functions, you better hope your user (the developer) is also a Sass expert, or wants to learn. This is often not the case, however. You need to talk to your audience. With the DigitalOcean design system, we provide a few options: Option 1 Users can implement the component library into a development environment and use Sass, select just the components they want to include, and extend the system using a hook-based system. This is the most performant and extensible output. Only the components that are called upon are included, and they can be easily extended using mixins. But as noted earlier, not everyone wants to work this way (including Sass a dependency and potentially needing to set up a build system for it and learn a new syntax). There is also the user who just wants to throw a link onto their page and have it look nice, and thats where our versioned built assets come in. Option 2 With Option 2, users pull in links that are served via a CDN that contain JS, CSS, and our SVG icon library. The code is a bit bigger than the completely customized version, but often this isn’t the aim when people are using Option 2. Reducing friction for adoption should be a major goal of your design system rollout. Conclusion Having a design system is really beneficial to any product, especially as it grows. In order to have an effective system, it’s important to primarily always keep your user in mind and garner support from your entire company. Once you have support and acceptance, this system will flourish and grow. Make sure someone is responsible for it, and make sure its built with a solid foundation from the start which will be carefully maintained toward the future. Good luck, and happy holidays! 2017 Una Kravets unakravets 2017-12-14T00:00:00+00:00 https://24ways.org/2017/why-design-systems-fail/ process
28 Why You Should Design for Open Source Let’s be honest. Most designers don’t like working for nothing. We rally against spec work and make a stand for contracts and getting paid. That’s totally what you should do as a professional designer in the industry. It’s your job. It’s your hard-working skill. It’s your bread and butter. Get paid. However, I’m going to make a case for why you could also consider designing for open source. First, I should mention that not all open source work is free work. Some companies hire open source contributors to work on their projects full-time, usually because that project is used by said company. There are other companies that encourage open source contribution and even offer 20%-time for these projects (where you can spend one day a week contributing to open source). These are super rad situations to be in. However, whether you’re able to land a gig doing this type of work, or you’ve decided to volunteer your time and energy, designing for open source can be rewarding in many other ways. Portfolio building New designers often find themselves in a catch-22 situation: they don’t have enough work experience showcased in their portfolio, which leads to them not getting much work because their portfolio is bare. These new designers often turn to unsolicited redesigns to fill their portfolio. An unsolicited redesign is a proof of concept in which a designer attempts to redesign a popular website. You can see many of these concepts on sites like Dribbble and Behance and there are even websites dedicated to showcasing these designs, such as Uninvited Designs. There’s even a subreddit for them. There are quite a few negative opinions on unsolicited redesigns, though some people see things from both sides. If you feel like doing one or two of these to fill your portfolio, that’s of course up to you. But here’s a better suggestion. Why not contribute design for an open source project instead? You can easily find many projects in great need of design work, from branding to information design, documentation, and website or application design. The benefits to doing this are far better than an unsolicited redesign. You get a great portfolio piece that actually has greater potential to get used (especially if the core team is on board with it). It’s a win-win situation. Not all designers are in need of portfolio filler, but there are other benefits to contributing design. Giving back to the community My first experience with voluntary work was when I collaborated with my friend, Vineet Thapar, on a pro bono project for the W3C’s Web Accessibility Initiative redesign project back in 2004. I was very excited to contribute CSS to a website that would get used by the W3C! Unfortunately, it decided to go a different direction and my work did not get used. However, it was still pretty exciting to have the opportunity, and I don’t regret a moment of that work. I learned a lot about accessibility from this experience and it helped me land some of the jobs I’ve had since. Almost a decade later, I got super into Sass. One of the core maintainers, Chris Eppstein, lamented on Twitter one day that the Sass website and brand was in dire need of design help. That led to the creation of an open source task force, Team Sass Design, and we revived the brand and the website, which launched at SassConf in 2013. It helped me in my current job. I showed it during my portfolio review when I interviewed for the role. Then I was able to use inspiration from a technique I’d tried on the Sass website to help create the more feature-rich design system that my team at work is building. But most importantly, I soon learned that it is exhilarating to be a part of the Sass community. This is the biggest benefit of all. It feels really good to give back to the technology I love and use for getting my work done. Ben Werdmuller writes about the need for design in open source. It’s great to see designers contributing to open source in awesome ways. When A List Apart’s website went open source, Anna Debenham contributed by helping build its pattern library. Bevan Stephens worked with FontForge on the design of its website. There are also designers who have created their own open source projects. There’s Dan Cederholm’s Pears, which shares common patterns in markup and style. There’s also Brad Frost’s Pattern Lab, which shares his famous method of atomic design and applies it to a design system. These systems and patterns have been used in real-world projects, such as RetailMeNot, so designers have contributed to the web in an even larger way simply by putting their work out there for others to use. That’s kind of fun to think about. How to get started So are you stoked about getting into the open source community? That’s great! Initially, you might get worried or uncomfortable in getting involved. That’s okay. But first consider that the project is open source for a reason. Your contribution (no matter how large or small) can help in a big way. If you find a project you’re interested in helping, make sure you do your research. Sometimes project team members will be attached to their current design. Is there already a designer on the core team? Reach out to that designer first. Don’t be too aggressive with why you think your design is better than theirs. Rather, offer some constructive feedback and a proposal of what would make the design better. Chances are, if the designer cares about the project, and you make a strong case, they’ll be up for it. Are there contribution guidelines? It’s proper etiquette to read these and follow the community’s rules. You’ll have a better chance of getting your work accepted, and it shows that you take the time to care and add to the overall quality of the project. Does the project lack guidelines? Consider starting a draft for that before getting started in the design. When contributing to open source, use your initiative to solve problems in a manageable way. Huge pull requests are hard to review and will often either get neglected or rejected. Work in small, modular, and iterative contributions. So this is my personal take on what I’ve learned from my experience and why I love open source. I’d love to hear from you if you have your own experience in doing this and what you’ve learned along the way as well. Please share in the comments! Thanks Drew McLellan, Eric Suzanne, Kyle Neath for sharing their thoughts with me on this! 2014 Jina Anne jina 2014-12-19T00:00:00+00:00 https://24ways.org/2014/why-you-should-design-for-open-source/ design
233 Wrapping Things Nicely with HTML5 Local Storage HTML5 is here to turn the web from a web of hacks into a web of applications – and we are well on the way to this goal. The coming year will be totally and utterly awesome if you are excited about web technologies. This year the HTML5 revolution started and there is no stopping it. For the first time all the browser vendors are rallying together to make a technology work. The new browser war is fought over implementation of the HTML5 standard and not over random additions. We live in exciting times. Starting with a bang As with every revolution there is a lot of noise with bangs and explosions, and that’s the stage we’re at right now. HTML5 showcases are often CSS3 showcases, web font playgrounds, or video and canvas examples. This is great, as it gets people excited and it gives the media something to show. There is much more to HTML5, though. Let’s take a look at one of the less sexy, but amazingly useful features of HTML5 (it was in the HTML5 specs, but grew at such an alarming rate that it warranted its own spec): storing information on the client-side. Why store data on the client-side? Storing information in people’s browsers affords us a few options that every application should have: You can retain the state of an application – when the user comes back after closing the browser, everything will be as she left it. That’s how ‘real’ applications work and this is how the web ones should, too. You can cache data – if something doesn’t change then there is no point in loading it over the Internet if local access is so much faster You can store user preferences – without needing to keep that data on your server at all. In the past, storing local data wasn’t much fun. The pain of hacky browser solutions In the past, all we had were cookies. I don’t mean the yummy things you get with your coffee, endorsed by the blue, furry junkie in Sesame Street, but the other, digital ones. Cookies suck – it isn’t fun to have an unencrypted HTTP overhead on every server request for storing four kilobytes of data in a cryptic format. It was OK for 1994, but really neither an easy nor a beautiful solution for the task of storing data on the client. Then came a plethora of solutions by different vendors – from Microsoft’s userdata to Flash’s LSO, and from Silverlight isolated storage to Google’s Gears. If you want to know just how many crazy and convoluted ways there are to store a bit of information, check out Samy’s evercookie. Clearly, we needed an easier and standardised way of storing local data. Keeping it simple – local storage And, lo and behold, we have one. The local storage API (or session storage, with the only difference being that session data is lost when the window is closed) is ridiculously easy to use. All you do is call a few methods on the window.localStorage object – or even just set the properties directly using the square bracket notation: if('localStorage' in window && window['localStorage'] !== null){ var store = window.localStorage; // valid, API way store.setItem(‘cow’,‘moo’); console.log( store.getItem(‘cow’) ); // => ‘moo’ // shorthand, breaks at keys with spaces store.sheep = ‘baa’ console.log( store.sheep ); // ‘baa’ // shorthand for all store[‘dog’] = ‘bark’ console.log( store[‘dog’] ); // => ‘bark’ } Browser support is actually pretty good: Chrome 4+; Firefox 3.5+; IE8+; Opera 10.5+; Safari 4+; plus iPhone 2.0+; and Android 2.0+. That should cover most of your needs. Of course, you should check for support first (or use a wrapper library like YUI Storage Utility or YUI Storage Lite). The data is stored on a per domain basis and you can store up to five megabytes of data in localStorage for each domain. Strings attached By default, localStorage only supports strings as storage formats. You can’t store results of JavaScript computations that are arrays or objects, and every number is stored as a string. This means that long, floating point numbers eat into the available memory much more quickly than if they were stored as numbers. var cowdesc = "the cow is of the bovine ilk, "+ "one end is for the moo, the "+ "other for the milk"; var cowdef = { ilk“bovine”, legs, udders, purposes front“moo”, end“milk” } }; window.localStorage.setItem(‘describecow’,cowdesc); console.log( window.localStorage.getItem(‘describecow’) ); // => the cow is of the bovine… window.localStorage.setItem(‘definecow’,cowdef); console.log( window.localStorage.getItem(‘definecow’) ); // => [object Object] = bad! This limits what you can store quite heavily, which is why it makes sense to use JSON to encode and decode the data you store: var cowdef = { "ilk":"bovine", "legs":4, "udders":4, "purposes":{ "front":"moo", "end":"milk" } }; window.localStorage.setItem(‘describecow’,JSON.stringify(cowdef)); console.log( JSON.parse( window.localStorage.getItem(‘describecow’) ) ); // => Object { ilk=“bovine”, more…} You can also come up with your own formatting solutions like CSV, or pipe | or tilde ~ separated formats, but JSON is very terse and has native browser support. Some use case examples The simplest use of localStorage is, of course, storing some data: the current state of a game; how far through a multi-form sign-up process a user is; and other things we traditionally stored in cookies. Using JSON, though, we can do cooler things. Speeding up web service use and avoiding exceeding the quota A lot of web services only allow you a certain amount of hits per hour or day, and can be very slow. By using localStorage with a time stamp, you can cache results of web services locally and only access them after a certain time to refresh the data. I used this technique in my An Event Apart 10K entry, World Info, to only load the massive dataset of all the world information once, and allow for much faster subsequent visits to the site. The following screencast shows the difference: For use with YQL (remember last year’s 24 ways entry?), I’ve built a small script called YQL localcache that wraps localStorage around the YQL data call. An example would be the following: yqlcache.get({ yql: 'select * from flickr.photos.search where text="santa"', id: 'myphotos', cacheage: ( 60*60*1000 ), callback: function(data) { console.log(data); } }); This loads photos of Santa from Flickr and stores them for an hour in the key myphotos of localStorage. If you call the function at various times, you receive an object back with the YQL results in a data property and a type property which defines where the data came from – live is live data, cached means it comes from cache, and freshcache indicates that it was called for the first time and a new cache was primed. The cache will work for an hour (60×60×1,000 milliseconds) and then be refreshed. So, instead of hitting the YQL endpoint over and over again, you hit it once per hour. Caching a full interface Another use case I found was to retain the state of a whole interface of an application by caching the innerHTML once it has been rendered. I use this in the Yahoo Firehose search interface, and you can get the full story about local storage and how it is used in this screencast: The stripped down code is incredibly simple (JavaScript with PHP embed): // test for localStorage support if(('localStorage' in window) && window['localStorage'] !== null){ var f = document.getElementById(‘mainform’); // test with PHP if the form was sent (the submit button has the name “sent”) // get the HTML of the form and cache it in the property “state” localStorage.setItem(‘state’,f.innerHTML); // if the form hasn’t been sent… // check if a state property exists and write back the HTML cache if(‘state’ in localStorage){ f.innerHTML = localStorage.getItem(‘state’); } } Other ideas In essence, you can use local storage every time you need to speed up access. For example, you could store image sprites in base-64 encoded datasets instead of loading them from a server. Or you could store CSS and JavaScript libraries on the client. Anything goes – have a play. Issues with local and session storage Of course, not all is rainbows and unicorns with the localStorage API. There are a few niggles that need ironing out. As with anything, this needs people to use the technology and raise issues. Here are some of the problems: Inadequate information about storage quota – if you try to add more content to an already full store, you get a QUOTA_EXCEEDED_ERR and that’s it. There’s a great explanation and test suite for localStorage quota available. Lack of automatically expiring storage – a feature that cookies came with. Pamela Fox has a solution (also available as a demo and source code) Lack of encrypted storage – right now, everything is stored in readable strings in the browser. Bigger, better, faster, more! As cool as the local and session storage APIs are, they are not quite ready for extensive adoption – the storage limits might get in your way, and if you really want to go to town with accessing, filtering and sorting data, real databases are what you’ll need. And, as we live in a world of client-side development, people are moving from heavy server-side databases like MySQL to NoSQL environments. On the web, there is also a lot of work going on, with Ian Hickson of Google proposing the Web SQL database, and Nikunj Mehta, Jonas Sicking (Mozilla), Eliot Graff (Microsoft) and Andrei Popescu (Google) taking the idea beyond simply replicating MySQL and instead offering Indexed DB as an even faster alternative. On the mobile front, a really important feature is to be able to store data to use when you are offline (mobile coverage and roaming data plans anybody?) and you can use the Offline Webapps API for that. As I mentioned at the beginning, we have a very exciting time ahead – let’s make this web work faster and more reliably by using what browsers offer us. For more on local storage, check out the chapter on Dive into HTML5. 2010 Christian Heilmann chrisheilmann 2010-12-06T00:00:00+00:00 https://24ways.org/2010/html5-local-storage/ code
276 Your jQuery: Now With 67% Less Suck Fun fact: more websites are now using jQuery than Flash. jQuery is an amazing tool that’s made JavaScript accessible to developers and designers of all levels of experience. However, as Spiderman taught us, “with great power comes great responsibility.” The unfortunate downside to jQuery is that while it makes it easy to write JavaScript, it makes it easy to write really really f*&#ing bad JavaScript. Scripts that slow down page load, unresponsive user interfaces, and spaghetti code knotted so deep that it should come with a bottle of whiskey for the next sucker developer that has to work on it. This becomes more important for those of us who have yet to move into the magical fairy wonderland where none of our clients or users view our pages in Internet Explorer. The IE JavaScript engine moves at the speed of an advancing glacier compared to more modern browsers, so optimizing our code for performance takes on an even higher level of urgency. Thankfully, there are a few very simple things anyone can add into their jQuery workflow that can clear up a lot of basic problems. When undertaking code reviews, three of the areas where I consistently see the biggest problems are: inefficient selectors; poor event delegation; and clunky DOM manipulation. We’ll tackle all three of these and hopefully you’ll walk away with some new jQuery batarangs to toss around in your next project. Selector optimization Selector speed: fast or slow? Saying that the power behind jQuery comes from its ability to select DOM elements and act on them is like saying that Photoshop is a really good tool for selecting pixels on screen and making them change color – it’s a bit of a gross oversimplification, but the fact remains that jQuery gives us a ton of ways to choose which element or elements in a page we want to work with. However, a surprising number of web developers are unaware that all selectors are not created equal; in fact, it’s incredible just how drastic the performance difference can be between two selectors that, at first glance, appear nearly identical. For instance, consider these two ways of selecting all paragraph tags inside a <div> with an ID. $("#id p"); $("#id").find("p"); Would it surprise you to learn that the second way can be more than twice as fast as the first? Knowing which selectors outperform others (and why) is a pretty key building block in making sure your code runs well and doesn’t frustrate your users waiting for things to happen. There are many different ways to select elements using jQuery, but the most common ways can be basically broken down into five different methods. In order, roughly, from fastest to slowest, these are: $("#id"); This is without a doubt the fastest selector jQuery provides because it maps directly to the native document.getElementbyId() JavaScript method. If possible, the selectors listed below should be prefaced with an ID selector in conjunction with jQuery’s .find() method to limit the scope of the page that has to be searched (as in the $("#id").find("p") example shown above). $("p");, $("input");, $("form"); and so on Selecting elements by tag name is also fast, since it maps directly to the native document.getElementsByTagname() method. $(".class"); Selecting by class name is a little trickier. While still performing very well in modern browsers, it can cause some pretty significant slowdowns in IE8 and below. Why? IE9 was the first IE version to support the native document.getElementsByClassName() JavaScript method. Older browsers have to resort to using much slower DOM-scraping methods that can really impact performance. $("[attribute=value]"); There is no native JavaScript method for this selector to use, so the only way that jQuery can perform the search is by crawling the entire DOM looking for matches. Modern browsers that support the querySelectorAll() method will perform better in certain cases (Opera, especially, runs these searches much faster than any other browser) but, generally speaking, this type of selector is Slowey McSlowersons. $(":hidden"); Like attribute selectors, there is no native JavaScript method for this one to use. Pseudo-selectors can be painfully slow since the selector has to be run against every element in your search space. Again, modern browsers with querySelectorAll() will perform slightly better here, but try to avoid these if at all possible. If you must use one, try to limit the search space to a specific portion of the page: $("#list").find(":hidden"); But, hey, proof is in the performance testing, right? It just so happens that said proof is sitting right here. Be sure to notice the class selector numbers beside IE7 and 8 compared to other browsers and then wonder how the people on the IE team at Microsoft manage to sleep at night. Yikes. Chaining Almost all jQuery methods return a jQuery object. This means that when a method is run, its results are returned and you can continue executing more methods on them. Rather than writing out the same selector multiple times over, just making a selection once allows multiple actions to be run on it. Without chaining $("#object").addClass("active"); $("#object").css("color","#f0f"); $("#object").height(300); With chaining $("#object").addClass("active").css("color", "#f0f").height(300); This has the dual effect of making your code shorter and faster. Chained methods will be slightly faster than multiple methods made on a cached selector, and both ways will be much faster than multiple methods made on non-cached selectors. Wait… “cached selector”? What is this new devilry? Caching Another easy way to speed up your code that seems to be a mystery to developers is the idea of caching your selectors. Think of how many times you end up writing the same selector over and over again in any project. Every $(".element") selector has to search the entire DOM each time, regardless of whether or not that selector had been previously run. Running the selection once and then storing the results in a variable means that the DOM only has to be searched once. Once the results of a selector have been cached, you can do anything with them. First, run your search (here we’re selecting all of the <li> elements inside <ul id="blocks">): var blocks = $("#blocks").find("li"); Now, you can use the blocks variable wherever you want without having to search the DOM every time. $("#hideBlocks").click(function() { blocks.fadeOut(); }); $("#showBlocks").click(function() { blocks.fadeIn(); }); My advice? Any selector that gets run more than once should be cached. This jsperf test shows just how much faster a cached selector runs compared to a non-cached one (and even throws some chaining love in to boot). Event delegation Event listeners cost memory. In complex websites and apps it’s not uncommon to have a lot of event listeners floating around, and thankfully jQuery provides some really easy methods for handling event listeners efficiently through delegation. In a bit of an extreme example, imagine a situation where a 10×10 cell table needs to have an event listener on each cell; let’s say that clicking on a cell adds or removes a class that defines the cell’s background color. A typical way that this might be written (and something I’ve often seen during code reviews) is like so: $('table').find('td').click(function() { $(this).toggleClass('active'); }); jQuery 1.7 has provided us with a new event listener method, .on(). It acts as a utility that wraps all of jQuery’s previous event listeners into one convenient method, and the way you write it determines how it behaves. To rewrite the above .click() example using .on(), we’d simply do the following: $('table').find('td').on('click',function() { $(this).toggleClass('active'); }); Simple enough, right? Sure, but the problem here is that we’re still binding one hundred event listeners to our page, one to each individual table cell. A far better way to do things is to create one event listener on the table itself that listens for events inside it. Since the majority of events bubble up the DOM tree, we can bind a single event listener to one element (in this case, the <table>) and wait for events to bubble up from its children. The way to do this using the .on() method requires only one change from our code above: $('table').on('click','td',function() { $(this).toggleClass('active'); }); All we’ve done is moved the td selector to an argument inside the .on() method. Providing a selector to .on() switches it into delegation mode, and the event is only fired for descendants of the bound element (table) that match the selector (td). With that one simple change, we’ve gone from having to bind one hundred event listeners to just one. You might think that the browser having to do one hundred times less work would be a good thing and you’d be completely right. The difference between the two examples above is staggering. (Note that if your site is using a version of jQuery earlier than 1.7, you can accomplish the very same thing using the .delegate() method. The syntax of how you write the function differs slightly; if you’ve never used it before, it’s worth checking the API docs for that page to see how it works.) DOM manipulation jQuery makes it very easy to manipulate the DOM. It’s trivial to create new nodes, insert them, remove other ones, move things around, and so on. While the code to do this is simple to write, every time the DOM is manipulated, the browser has to repaint and reflow content which can be extremely costly. This is no more evident than in a long loop, whether it be a standard for() loop, while() loop, or jQuery $.each() loop. In this case, let’s say we’ve just received an array full of image URLs from a database or Ajax call or wherever, and we want to put all of those images in an unordered list. Commonly, you’ll see code like this to pull this off: var arr = [reallyLongArrayOfImageURLs]; $.each(arr, function(count, item) { var newImg = '<li><img src="'+item+'"></li>'; $('#imgList').append(newImg); }); There are a couple of problems with this. For one (which you should have already noticed if you’ve read the earlier part of this article), we’re making the $("#imgList") selection once for each iteration of our loop. The other problem here is that each time the loop iterates, it’s adding a new <li> to the DOM. Each of those insertions is going to be costly, and if our array is quite large then this could lead to a massive slowdown or even the dreaded ‘A script is causing this page to run slowly’ warning. var arr = [reallyLongArrayOfImageURLs], tmp = ''; $.each(arr, function(count, item) { tmp += '<li><img src="'+item+'"></li>'; }); $('#imgList').append(tmp); All we’ve done here is create a tmp variable that each <li> is added to as it’s created. Once our loop has finished iterating, that tmp variable will contain all of our list items in memory, and can be appended to our <ul> all in one go. Browsers work much faster when working with objects in memory rather than on screen, so this is a much faster, more CPU-cycle-friendly method of building a list. Wrapping up These are far from being the only ways to make your jQuery code run better, but they are among the simplest ones to implement. Though each individual change may only make a few milliseconds of difference, it doesn’t take long for those milliseconds to add up. Studies have shown that the human eye can discern delays of as few as 100ms, so simply making a few changes sprinkled throughout your code can very easily have a noticeable effect on how well your website or app performs. Do you have other jQuery optimization tips to share? Leave them in the comments and help make us all better. Now go forth and make awesome! 2011 Scott Kosman scottkosman 2011-12-13T00:00:00+00:00 https://24ways.org/2011/your-jquery-now-with-less-suck/ code
221 “Probably, Maybe, No”: The State of HTML5 Audio With the hype around HTML5 and CSS3 exceeding levels not seen since 2005’s Ajax era, it’s worth noting that the excitement comes with good reason: the two specifications render many years of feature hacks redundant by replacing them with native features. For fun, consider how many CSS2-based rounded corners hacks you’ve probably glossed over, looking for a magic solution. These days, with CSS3, the magic is border-radius (and perhaps some vendor prefixes) followed by a coffee break. CSS3’s border-radius, box-shadow, text-shadow and gradients, and HTML5’s <canvas>, <audio> and <video> are some of the most anticipated features we’ll see put to creative (ab)use as adoption of the ‘new shiny’ grows. Developers jumping on the cutting edge are using subsets of these features to little detriment, in most cases. The more popular CSS features are design flourishes that can degrade nicely, but the current audio and video implementations in particular suffer from a number of annoyances. The new shiny: how we got here Sound involves one of the five senses, a key part of daily life for most – and yet it has been strangely absent from HTML and much of the web by default. From a simplistic perspective, it seems odd that HTML did not include support for the full multimedia experience earlier, despite the CD-ROM-based craze of the early 1990s. In truth, standards like HTML can take much longer to bake, but eventually deliver the promise of a lowered barrier to entry, consistent implementations and shiny new features now possible ‘for free’ just about everywhere. <img> was introduced early and naturally to HTML, despite having some opponents at the time. Perhaps <audio> and <video> were avoided, given the added technical complexity of decoding various multi-frame formats, plus the hardware and bandwidth limitations of the era. Perhaps there were quarrels about choosing a standard format or – more simply – maybe these elements just weren’t considered to be applicable to the HTML-based web at the time. In any event, browser plugins from programs like RealPlayer and QuickTime eventually helped to fill the in-page audio/video gap, handling <object> and <embed> markup which pointed to .wav, .avi, .rm or .mov files. Suffice it to say, the experience was inconsistent at best and, on the standards side of the fence right now, so is HTML5 in terms of audio and video. : the theory As far as HTML goes, the code for <audio> is simple and logical. Just as with <img>, a src attribute specifies the file to load. Pretty straightforward – sounds easy, right? <audio src="mysong.ogg" controls> <!-- alternate content for unsupported case --> Download <a href="mysong.ogg">mysong.ogg</a>; </audio> Ah, if only it were that simple. The first problem is that the OGG audio format, while ‘free’, is not supported by some browsers. Conversely, nor is MP3, despite being a de facto standard used in all kinds of desktop software (and hardware). In fact, as of November 2010, no single audio format is commonly supported across all major HTML5-enabled browsers. What you end up writing, then, is something like this: <audio controls> <source src="mysong.mp3" /> <source src="mysong.ogg" /> <!-- alternate content for unsupported case, maybe Flash, etc. --> Download <a href="mysong.ogg">mysong.ogg</a> or <a href="mysong.mp3">mysong.mp3</a> </audio> Keep in mind, this is only a ‘first class’ experience for the HTML5 case; also, for non-supported browsers, you may want to look at another inline player (object/embed, or a JavaScript plus Flash API) to have inline audio. You can imagine the added code complexity in the case of supporting ‘first class’ experiences for older browsers, too. : the caveats With <img>, you typically don’t have to worry about format support – it just works – and that’s part of what makes a standard wonderful. JPEG, PNG, BMP, GIF, even TIFF images all render just fine if for no better reason, perhaps, than being implemented during the ‘wild west’ days of the web. The situation with <audio> today reflects a very different – read: business-aware – environment in 2010. (Further subtext: There’s a lot of [potential] money involved.) Regrettably, this is a collision of free and commercial interests, where the casualty is ultimately the user. Second up in the casualty list is you, the developer, who has to write additional code around this fragmented support. The HTML5 audio API as implemented in JavaScript has one of the most un-computer-like responses I’ve ever seen, and inspired the title of this post. Calling new Audio().canPlayType('audio/mp3'), which queries the system for format support according to a MIME type, is supposed to return one of “probably”, “maybe”, or “no”. Sometimes, you’ll just get a null or empty string, which is also fun. A “maybe” response does not guarantee that a format will be supported; sometimes audio/mp3 gives “maybe,” but then audio/mpeg; codecs="mp3" will give a more-solid “probably” response. This can vary by browser or platform, too, depending on native support – and finally, the user may also be able to install codecs, extending support to include other formats. (Are you excited yet?) Damn you, warring formats! New market and business opportunities go hand-in-hand with technology developments. What we have here is certainly not failure to communicate; rather, we have competing parties shouting loudly in public in attempts to influence mindshare towards a de facto standard for audio and video. Unfortunately, the current situation means that at least two formats are effectively required to serve the majority of users correctly. As it currently stands, we have the free and open source software camp of OGG Vorbis/WebM and its proponents (notably, Mozilla, Google and Opera in terms of browser makers), up against the non-free, proprietary and ‘closed’ camp of MP3 and MPEG4/HE-AAC/H.264 – which is where you’ll find commitments from Apple and Microsoft, among others. Apple is likely in with H.264 for the long haul, given its use of the format for its iTunes music store and video offerings. It is generally held that H.264 is a technically superior format in terms of file size versus quality, but it involves intellectual property and, in many use cases, requires licensing fees. To be fair, there is a business model with H.264 and much has been invested in its development, but this approach is not often the kind that wins over the web. On that front, OGG/WebM may eventually win for being a ‘free’ format that does not involve a licensing scheme. Closed software and tools ideologically clash with the open nature of the web, which exists largely thanks to free and open technology. Because of philosophical and business reasons, support for audio and video is fragmented across browsers adopting HTML5 features. It does not help that a large amount of audio and video currently exists in non-free MP3 and MPEG-4 formats. Adoption of <audio> and <video> may be slowed, since it is more complex than <img> and may feel ‘broken’ to developers when edge cases are encountered. Furthermore, the HTML5 spec does not mandate a single required format. The end result is that, as a developer, you must currently provide at least both MP3 and OGG, for example, to serve most existing HTML5-based user agents. Transitioning to There will be some growing pains as developers start to pick up the new HTML5 shiny, while balancing the needs of current and older agents that don’t support either <audio> or the preferred format you may choose (for example, MP3). In either event, Flash or other plugins can be used as done traditionally within HTML4 documents to embed and play the relevant audio. The SoundManager 2 page player demo in action. Ideally, HTML5 audio should be used whenever possible with Flash as the backup option. A few JavaScript/Flash-based audio player projects exist which balance the two; in attempting to tackle this problem, I develop and maintain SoundManager 2, a JavaScript sound API which transparently uses HTML5 Audio() and, if needed, Flash for playing audio files. The internals can get somewhat ugly, but the transition between HTML4 and HTML5 is going to be just that – and even with HTML5, you will need some form of format fall-back in addition to graceful degradation. It may be safest to fall back to MP3/MP4 formats for inline playback at this time, given wide support via Flash, some HTML5-based browsers and mobile devices. Considering the amount of MP3/MP4 media currently available, it is wiser to try these before falling through to a traditional file download process. Early findings Here is a brief list of behavioural notes, annoyances, bugs, quirks and general weirdness I have found while playing with HTML5-based audio at time of writing (November 2010): Apple iPad/iPhone (iOS 4, iPad 3.2+) Only one sound can be played at a time. If a second sound starts, the first is stopped. No auto-play allowed. Sounds follow the pop-up window security model and can only be started from within a user event handler such as onclick/touch, and so on. Otherwise, playback attempts silently fail. Once started, a sequence of sounds can be created or played via the ‘finish’ event of the previous sound (for example, advancing through a playlist without interaction after first track starts). iPad, iOS 3.2: Occasional ‘infinite loop’ bug seen where audio does not complete and stop at a sound’s logical end – instead, it plays again from the beginning. Might be specific to example file format (HE-AAC) encoded from iTunes. Apple Safari, OS X Snow Leopard 10.6.5 Critical bug: Safari 4 and 5 intermittently fail to load or play HTML5 audio on Snow Leopard due to bug(s) in QuickTime X and/or other underlying frameworks. Known Apple ‘radar’ bug: bugs.webkit.org #32159 (see also, test case.) Amusing side note: Safari on Windows is fine. Apple Safari, Windows Food for thought: if you download “Safari” alone on Windows, you will not get HTML5 audio/video support (tested in WinXP). You need to download “Safari + QuickTime” to get HTML5 audio/video support within Safari. (As far as I’m aware, Chrome, Firefox and Opera either include decoders or use system libraries accordingly. Presumably IE 9 will use OS-level APIs.) General Quirks Seeking and loading, ‘progress’ events, and calculating bytes loaded versus bytes total should not be expected to be linear, as users can arbitrarily seek within a sound. It appears that some support for HTTP ranges exists, which adds a bit of logic to UI code. Browsers seem to vary slightly in their current implementations of these features. The onload event of a sound may be of little relevance, if non-linear loading is involved (see above note re: seeking). Interestingly (perhaps I missed it), the current spec does not seem to specify a panning or left/right channel mix option. The preload attribute values may vary slightly between browsers at this time. Upcoming shiny: HTML5 Audio Data API With access to audio data, you can incorporate waveform and spectrum elements that make your designs react to music. The HTML5 audio spec does a good job covering the basics of playback, but did not initially get into manipulation or generation of audio on-the-fly, something Flash has had for a number of years now. What if JavaScript could create, monitor and change audio dynamically, like a sort of audio <canvas> element? With that kind of capability, many dynamic audio processing features become feasible and, when combined with other media, can make for some impressive demos. What started as a small idea among a small group of audio and programming enthusiasts grew to inspire a W3C audio incubator group, and continued to establish the Mozilla Audio Data API. Contributors wrote a patch for Firefox which was reviewed and revised, and is now slated to be in the public release of Firefox 4. Some background and demos are also detailed in an article from the BBC R&D blog. There are plenty of live demos to see, which give an impression of the new creative ideas this API enables. Many concepts are not new in themselves, but it is exciting to see this sort of thing happening within the native browser context. Mozilla is not alone in this effort; the WebKit folks are also working on a JavaScriptAudioNode interface, which implements similar audio buffering and sample elements. The future? It is my hope that we’ll see a common format emerge in terms of support across the major browsers for both audio and video; otherwise, support will continue to be fragmented and mildly frustrating to develop for, and that can impede growth of the feature. It’s a big call, but if <img> had lacked a common format back in the wild west era, I doubt the web would have grown to where it is today. Complaints and nitpicks aside, HTML5 brings excellent progress on the browser multimedia front, and the first signs of native support are a welcome improvement given all audio and video previously relied on plugins. There is good reason to be excited. While there is room for more, support could certainly be much worse – and as tends to happen with specifications, the implementations targeting them should improve over time. Note: Thanks to Nate Koechley, who suggested the Audio().canPlayType() response be part of the article title. 2010 Scott Schiller scottschiller 2010-12-08T00:00:00+00:00 https://24ways.org/2010/the-state-of-html5-audio/ code
Powered by Datasette · Query took 2.149ms