{"rowid": 264, "title": "Dynamic Social Sharing Images", "contents": "Way back when social media was new, you could be pretty sure that whatever you posted would be read by those who follow you. If you\u2019d written a blog post and you wanted to share it with those who follow you, you could post a link and your followers would see it in their streams. Oh heady days! \nWith so many social channels and a proliferation of content and promotions flying past in everyone\u2019s streams, it\u2019s no longer enough to share content on social media, you have to actively sell it if you want it to be seen. You really need to make the most of every opportunity to catch a reader\u2019s attention if you\u2019re trying to get as many eyes as possible on that sweet, sweet social content.\nOne of the best ways to grab attention with your posts or tweets is to include an image. There\u2019s heaps of research that says that having images in your posts helps them stand out to followers. Reports I found showed figures from anything from 35% to 150% improvement from just having image in a post. Unfortunately, the details were surrounded with gross words like engagement and visual marketing assets and so I had to close the page before I started to hate myself too much.\nSo without hard stats to quote, we\u2019ll call it a rule of thumb. The rule of thumb is that posts with images will grab more attention than those without, so it makes sense that when adding pages to a website, you should make sure that they have social media sharing images associated with them.\nAdding sharing images\nThe process for declaring an image to be used in places like Facebook and Twitter is very simple, and at this point is familiar to many of us. You add a meta tag to the head of the page to point to the location of the image to use. When a link to the page is added to a post, the social network will fetch the page, look for the meta tag and then use the image you specified.\n\nThere\u2019s a good post on this over at CSS-Tricks if you need to bone up on the details of this and other similar meta tags for social media sharing.\nThis is all fine and well for content that has a very obvious choice of image to go along with it, but what if you don\u2019t necessarily have an image? One approach is to use stock photography, but that\u2019s not going to be right for every situation.\nThis was something we faced with 24 ways in 2017. We wanted to add images to the tweets we post each day announcing a new article. Some articles have images, but not all, and there tended not to be any consistency in terms of imagery from one article to the next. We always have an author photograph, but those don\u2019t usually lend themselves directly to being the main \u2018hero\u2019 image for an article.\nPutting his thinking cap on, Paul came up with a design for an image that used the author photo along with a quote extracted from the article.\nOne of the hand-made sharing images from 2017\nEach day we would pick a quote from the article, and Paul would manually compose an image to be uploaded to the site. The results were great, but the whole process was a bit too labour intensive and relied on an individual (Paul) being available each day to do the work. I thought we could probably improve this.\nHatching a new plan\nOne initial idea I came up with was to script the image editor to dynamically build a new image by pulling content from our database. Sketch has plugins available to pull JSON content into a design, and our CMS can easily output JSON data, so that was one possibility.\nThe more I thought about this and how much I wish graphic design tools worked just a little bit more like CSS, the obvious solution hit me. We should just build it with CSS!\nIn fact, as the author name and image already exist in our CMS, and the visual styling is based on the design of the website, couldn\u2019t this just be another page on the site generated by the CMS?\nBreaking it down, I figured the steps needed would be something like:\n\nCreate the CSS to lay out a component that could be turned into an image\nAdd a new field to articles in the CMS to hold a handpicked quote\nBuild a new article template in the CMS to output the author name and quote dynamically for any article\n\u2026 um \u2026 screenshot?\n\nI thought I\u2019d get cracking and see if I could figure out the final steps later.\nBuilding the page\nThe first thing to tackle was the basic HTML and CSS to lay out the components for our image. That bit was really easy, as I just asked Paul to do it. Everyone should have a Paul.\nPaul\u2019s code uses a fixed dimension container in the HTML, set to 600 \u00d7 315px. This is to make it the correct aspect ratio for Facebook\u2019s recommended image size. It\u2019s useful to remember here that it doesn\u2019t need to be responsive or robust, as the page only needs to lay out correctly for a screenshot and a fixed size in a known browser.\nWith the markup and CSS in place, I turned this into a new template. Our CMS can easily display content through any number of templates, so I created a version of the article template that was totally stripped down. It only included the author details and the quote, along with Paul\u2019s markup.\nI also added the quote as a new field on the article in the CMS, so each \u2018image\u2019 could be quickly and easily customised in the editing process.\nI added a new field to the article template to capture the quote.\nWith very little effort, we quickly had a page to dynamically generate our \u2018image\u2019 right from the CMS. You can see any of them by adding /sharing onto the end of an article URL for any 2018 article.\nOur automatically generated layout direct from the CMS\nIt soon became clear that the elusive Step 4 was going to be the tricky part. I can create a small page on the site that looks like an image, but how should I go about turning it into one? An obvious route is to screenshot the page by hand, but that\u2019s going back to some of the manual steps I was trying to eliminate, and also opens up a possibility for errors to be made. But it did lead me to the thought\u2026 how could I automatically take a screenshot?\nEnter Puppeteer\nPuppeteer is a Node.js library that provides a nice API onto Headless Chrome. What is Headless Chrome, you ask? It\u2019s just a version of the Chrome browser than runs from the command line without ever drawing anything to a user interface window. It loads pages, renders CSS, runs JavaScript, pretty much every normal thing that Chrome on the desktop does, but without a clicky user interface.\nHeadless Chrome can be used for all sorts of things such as running automated tests on front-end code after making changes, or\u2026 get this\u2026 rendering pages that can be used for screenshots. The actual process of writing some code to control Chrome and to take the screenshot is where Puppeteer comes in. Puppeteer puts a friendly layer in front of big old scary Chrome to enable us to interact with it using simple JavaScript code running in Node.\nUsing Puppeteer, I can write a small script that will repeatably turn a URL into an image. So simple is it to do this, that\u2019s it\u2019s actually Puppeteer\u2019s \u2018hello world\u2019 example.\nFirst you install Puppeteer. It downloads a compatible headless browser (actually Chromium) as a dependancy, so you don\u2019t need to worry about installing that. At the command line:\nnpm i puppeteer\nThen save a new file as example.js with this code:\nconst puppeteer = require('puppeteer');\n\n(async () => {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto('https://example.com');\n await page.screenshot({path: 'example.png'});\n await browser.close();\n})();\nand then run it using Node:\nnode example.js\nThis will output an image file example.png to disk, which contains a screenshot of, in this case https://example.com. The logic of the code is reasonably easy to follow:\n\nLaunch a browser\nOpen up a new page\nGoto a URL\nTake a screenshot\nClose the browser\n\nThe async function and await keywords are a way to have the script pause and wait for normally asynchronous code to return before proceeding. That\u2019s useful with actions like loading a web page that might take some time to complete. They\u2019re used with Promises, and the effect is to make asynchronous code behave as if it\u2019s synchronous. You can read more about async and await at MDN if you\u2019re interested.\nThat\u2019s a good proof-of-concept using the basic Puppeteer example. I can take a screenshot of a URL! But what happens if I put the URL of my new special page in there?\nOur content is up in the corner of the image with lots of empty space.\nThat\u2019s not great. It\u2019s okay, but not great. It looks like that, by default, Puppeteer takes a screenshot with a resolution of 800 \u00d7 600, so we need to find out how to adjust that. Fortunately, the docs aren\u2019t the worst and I was able to find the page.setViewport() method pretty easily.\nconst puppeteer = require('puppeteer');\n\n(async () => {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto('https://24ways.org/2018/clip-paths-know-no-bounds/sharing');\n await page.setViewport({\n width: 600,\n height: 315\n });\n await page.screenshot({path: 'example.png'});\n await browser.close();\n})();\nThis worked! The screenshot is now 600 \u00d7 315 as expected. That\u2019s exactly what we asked for. Trouble is, that\u2019s a bit low res and it is nearly 2019 after all. While in those docs, I noticed the deviceScaleFactor option that can be passed to page.setViewport(). Setting that to 2 gives us an image of the same area of the screen, but with twice as many pixels.\n await page.setViewport({\n width: 600,\n height: 315,\n deviceScaleFactor: 2\n });\nPerfect! We now have a programmatic way of turning a URL into an image.\nImproving the script\nRather than having a script with a fixed URL in it that outputs an image called example.png, the next step is to make that a bit more dynamic. The aim here is to have a script that we can run with a URL as an argument and have it output an image for that one page. That way we can run it manually, or hook it into part of our site\u2019s build process to automate the generation of the image.\nOur goal is to call the script like this:\nnode shoot-sharing-image.js https://24ways.org/2018/clip-paths-know-no-bounds/\nAnd I want the image to come out with the name clip-paths-know-no-bounds.png. To do that, I need to have my script look for command arguments, and then to split the URL up to grab the slug from it.\n// Get the URL and the slug segment from it\nconst url = process.argv[2];\nconst segments = url.split('/');\n// Get the second-to-last segment (the slug)\nconst slug = segments[segments.length-2];\nWe can then use these variables later in the script, remembering to add sharing back onto the end of the URL to get our dedicated page.\n(async () => {\n const browser = await puppeteer.launch();\n const page = await browser.newPage();\n await page.goto(url + 'sharing');\n await page.setViewport({\n width: 600,\n height: 315,\n deviceScaleFactor: 2\n });\n await page.screenshot({path: slug + '.png'});\n await browser.close();\n})();\nOnce you\u2019re generating the image with Node, there\u2019s all sorts of things you can do with it. An obvious step is to move it to the correct location within your site or project.\nYou can also run optimisations on the file. I\u2019m using imagemin with pngquant to reduce the file size a little.\nconst imagemin = require('imagemin');\nconst imageminPngquant = require('imagemin-pngquant');\n\nawait imagemin([slug + '.png'], 'build', {\n plugins: [\n imageminPngquant({quality: '75-90'})\n ]\n});\n\nYou can see the completed example as a gist.\nIntegrating it with your CMS\nSo we now have a command we can run to take a URL and generate a custom image for that URL. It\u2019s in a format that can be called by any sort of build script, or triggered from a publishing hook in a CMS. Exactly how you do that is going to depend on the way your site is built and the technology stack you\u2019re using, but it\u2019s likely not too hard as long as you can run a command as part of the process.\nFor 24 ways this year, I\u2019ve been running the script by hand once each article is ready. My script adds the file to a git repo and pushes to a deployment remote that is configured to automatically deploy static assets to our server. Along with our theme of making incremental improvements, next year I\u2019ll look to automate this one step further.\nWe may also look at having a few slightly different layouts to choose from, so that each day isn\u2019t exactly the same as the last. Interestingly, we could even try some A/B tests to see if there\u2019s any particular format of image or type of quote that does a better job of grabbing attention. There are lots of possibilities!\n\nBy using a bit of ingenuity, some custom CMS templates, and the very useful Puppeteer project, we\u2019ve been able to reliably produce dynamic social media sharing images for all of our articles. In doing so, we reduced the dependancy on any individual for producing those images, and opened up a world of possibilities in how we use those images.\nI hope you\u2019ll give it a try!", "year": "2018", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2018-12-24T00:00:00+00:00", "url": "https://24ways.org/2018/dynamic-social-sharing-images/", "topic": "code"} {"rowid": 246, "title": "Designing Your Site Like It\u2019s 1998", "contents": "It\u2019s 20 years to the day since my wife and I started Stuff & Nonsense, our little studio and my outlet for creative ideas on the web. To celebrate this anniversary\u2014and my fourteenth contribution to 24 ways\u2014 I\u2019d like to explain how I would\u2019ve developed a design for Planes, Trains and Automobiles, one of my favourite Christmas films.\nMy design for Planes, Trains and Automobiles is fixed at 800px wide.\nDeveloping a framework\nI\u2019ll start by using frames to set up the framework for this new website. Frames are individual pages\u2014one for navigation, the other for my content\u2014pulled together to form a frameset. Space is limited on lower-resolution screens, so by using frames I can ensure my navigation always remains visible. I can include any number of frames inside a element.\nI add two rows to my ; the first is for my navigation and is 50px tall, the second is for my content and will resize to fill any available space. As I don\u2019t want frame borders or any space between my frames, I set frameborder and framespacing attributes to 0:\n\n[\u2026]\n\nNext I add the source of my two frame documents. I don\u2019t want people to be able to resize or scroll my navigation, so I add the noresize attribute to that frame:\n\n\n\n\nI do want links from my navigation to open in the content frame, so I give each a name so I can specify where I want links to open:\n\n\n\n\nThe framework for this website is simple as it contains only two horizontal rows. Should I need a more complex layout, I can nest as many framesets\u2014and as many individual documents\u2014as I need:\n\n \n \n \n \n \n\nLetterbox framesets were common way to deal with multiple screen sizes. In a letterbox, the central frameset had a fixed height and width, while the frames on the top, right, bottom, and left expanded to fill any remaining space.\nHandling older browsers\nSadly not every browser supports frames, so I should send a helpful message to people who use older browsers asking them to upgrade. Happily, I can do that using noframes content:\n\n<body>\n<p>This page uses frames, but your browser doesn\u2019t support them. \n Please upgrade your browser.</p>\n</body>\n\nForcing someone back into a frame\nSometimes, someone may follow a link to a page from a portal or search engine, or they might attempt to open it in a new window or tab. If that page properly belongs inside a , people could easily miss out on other parts of a design. This short script will prevent this happening and because it\u2019s vanilla Javascript, it doesn\u2019t require a library such as jQuery:\n\n\nLaying out my page\nBefore starting my layout, I add a few basic background and colour styles. I must include these attributes in every page on my website:\n\nI want absolute control over how people experience my design and don\u2019t want to allow it to stretch, so I first need a which limits the width of my layout to 800px. The align attribute will keep this
in the centre of someone\u2019s screen:\n
\n \n \n \n
[\u2026]
\nAlthough they were developed for displaying tabular information, the cells and rows which make up the element make it ideal for the precise implementation of a design. I need several tables\u2014often nested inside each other\u2014to implement my design. These include tables for a banner and three rows of content:\n
\n
[\u2026]
\n \n
\n
[\u2026]
\n \n \n [\u2026]
\n [\u2026]
\n\nThe width of the first table\u2014used for my banner\u2014is fixed to match the logo it contains. As I don\u2019t need borders, padding, or spacing between these cells, I use attributes to remove them:\n\n \n \n \n
\"Logo\"
\nThe next table\u2014which contains the largest image, introduction, and a call-to-action\u2014is one of the most complex parts of my design, so I need to ensure its layout is pixel perfect. To do that I add an extra row at the top of this table and fill each of its cells with tiny transparent images:\n\n \n \n\nThe height and width of these \u201cshims\u201d or \u201cspacers\u201d is only 1px but they will stretch to any size without increasing their weight on the page. This makes them perfect for performant website development.\nFor the hero of this design, I splice up the large image into three separate files and apply each slice as a background to the table cells. I also match the height of those cells to the background images:\n\n \u00a0\n [\u2026]\n\n\n\n \u00a0\n\nI use tables and spacer images throughout the rest of this design to lay out the various types of content with perfect precision. For example, to add a single-pixel border around my two columns of content, I first apply a blue background to an outer table along with 1px of cellspacing, then simply nest an inner table\u2014this time with a white background\u2014inside it:\n\n \n \n \n
\n \n[\u2026]\n
\n
\nAdding details\nTables are fabulous tools for laying out a page, but they\u2019re also useful for implementing details on those pages. I can use a table to add a gradient background, rounded corners, and a shadow to the button which forms my \u201cBuy the DVD\u201d call-to-action. First, I splice my button graphic into three slices; two fixed-width rounded ends, plus a narrow gradient which stretches and makes this button responsive. Then, I add those images as backgrounds and use spacers to perfectly size my button:\n\n \n \n\n \n\n \n \n
\n
\n Buy the DVD\n
\n
\nI use those same elements to add details to headlines and lists too. Adding a \u201cbullet\u201d to each item in a list needs only two additional table cells, a circular graphic, and a spacer:\n\n \n \n \n \n \n
\u00a0\u00a0Directed by John Hughes
\nImplementing a typographic hierarchy\nSo far I\u2019ve explained how to use frames, tables, and spacers to develop a layout for my content, but what about styling that content? I use elements to change the typeface from the browser\u2019s default to any font installed on someone\u2019s device:\nPlanes, Trains and Automobiles is a comedy film [\u2026]\nTo adjust the size of those fonts, I use the size attribute and a value between the smallest (1) and the largest (7) where 3 is the browser\u2019s default. I use a size of 4 for this headline and 2 for the text which follows:\nSteve Martin\n\nAn American actor, comedian, writer, producer, and musician.\nWhen I need to change the typeface, perhaps from a sans-serif like Arial to a serif like Times New Roman, I must change the value of the face attribute on every element on all pages on my website.\nNB: I use as many
elements as needed to create space between headlines and paragraphs.\nView the final result (and especially the source.)\nMy modern day design for Planes, Trains and Automobiles.\nI can imagine many people reading this and thinking \u201cThis is terrible advice because we don\u2019t develop websites like this in 2018.\u201d That\u2019s true.\nWe have the ability to embed any number of web fonts into our products and websites and have far more control over type features, leading, ligatures, and sizes:\nfont-variant-caps: titling-caps;\nfont-variant-ligatures: common-ligatures;\nfont-variant-numeric: oldstyle-nums;\nGrid has simplified the implementation of even the most complex compound grid down to just a few lines of CSS:\nbody {\n display: grid;\n grid-template-columns: 3fr 1fr 2fr 2fr 1fr 3fr;\n grid-template-rows: auto;\n grid-column-gap: 2vw;\n grid-row-gap: 1vh;\n}\nFlexbox has made it easy to develop flexible components such as navigation links:\nnav ul { display: flex; }\nnav li { flex: 1; }\nJust one line of CSS can create multiple columns of fluid type:\nmain { column-width: 12em; }\nCSS Shapes enable text to flow around irregular shapes including polygons:\n[src*=\"main-img\"] {\n float: left;\n shape-outside: polygon(\u2026);\n}\nToday, we wouldn\u2019t dream of using images and a table to add a gradient, rounded corners, and a shadow to a button or link, preferring instead:\n.btn {\n background: linear-gradient(#8B1212, #DD3A3C);\n border-radius: 1em;\n box-shadow: 0 2px 4px 0 rgba(0,0,0,0.50), inset 0 -1px 1px 0 rgba(0,0,0,0.50);\n}\nCSS Custom Properties, feature and media queries, filters, pseudo-elements, and SVG; the list of advances in HTML, CSS, and other technologies goes on. So does our understanding of how best to use them by separating content, structure, presentation, and behaviour. As 2018 draws to a close, we\u2019re certain we know how to design and develop products and websites better than we did at the end of 1998.\nStrange as it might seem looking back, in 1998 we were also certain our techniques and technologies were the best for the job. That\u2019s why it\u2019s dangerous to believe with absolute certainty that the frameworks and tools we increasingly rely on today\u2014tools like Bootstrap, Bower, and Brunch, Grunt, Gulp, Node, Require, React, and Sass\u2014will be any more relevant in the future than elements, frames, layout tables, and spacer images are today.\nI have no prediction for what the web will be like twenty years from now. However, I want to believe we\u2019ll build on what we\u2019ve learned during these past two decades about the importance of accessibility, flexibility, and usability, and that the mistakes we made while infatuated by technologies won\u2019t be repeated.\n\nHead over to my website if you\u2019d like to read about how I\u2019d implement my design for \u2018Planes, Trains and Automobiles\u2019 today.", "year": "2018", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2018-12-23T00:00:00+00:00", "url": "https://24ways.org/2018/designing-your-site-like-its-1998/", "topic": "code"} {"rowid": 248, "title": "How to Use Audio on the Web", "contents": "I know what you\u2019re thinking. I never never want to hear sound anywhere near a browser, ever ever, wow! \ud83d\ude49\nYou\u2019re having flashbacks, flashbacks to the days of yore, when we had a element and yup did everyone think that was the most rad thing since . I mean put those two together with a , only use CSS colour names, make sure your borders were all set to ridge and you\u2019ve got yourself the neatest website since 1998.\nThe sound played when the website loaded and you could play a MIDI file as well! Everyone could hear that wicked digital track you chose. Oh, surfing was gnarly back then.\nYes it is 2018, the end of in fact, soon to be 2019. We are certainly living in the future. Hoverboards self driving cars, holodecks VR headsets, rocket boots drone racing, sound on websites get real, Ruth.\nWe can\u2019t help but be jaded, even though the element is depreciated, and the autoplay policy appeared this year. Although still in it\u2019s infancy, the policy \u201ccontrols when video and audio is allowed to autoplay\u201d, which should reduce the somewhat obtrusive playing of sound when a website or app loads in the future.\nBut then of course comes the question, having lived in a muted present for so long, where and why would you use audio?\n\u2728 Showcase Time \u2728\nThere are some incredible uses of audio on websites today. This is my personal favourite futurelibrary.no, a site from Norway chronicling books that have been published from a forest of trees planted precisely for the books themselves. The sound effects are lovely, adding to the overall experience.\nfuturelibrary.no\nAnother site that executes this well is pottermore.com. The Hogwarts WebGL simulation uses both sound effects and ambient background music and gives a great experience. The button hovers are particularly good.\npottermore.com\nEighty-six and a half years is a beautiful narrative site, documenting the musings of an eighty-six and a half year old man. The background music playing on this site is not offensive, it adds to the experience.\nEighty-six and a half years\nSound can be powerful and in some cases useful. Last year I wrote about using them to help validate forms. Audiochart is a library which \u201callows the user to explore charts on web pages using sound and the keyboard\u201d. Ben Byford recorded voice descriptions of the pages on his website for playback should you need or want it. There is a whole area of accessibility to be explored here.\nThen there\u2019s education. Fancy beginning with some piano in the new year? flowkey.com is a website which allows you to play along and learn at the same time. Need to brush up on your music theory? lightnote.co takes you through lessons to do just that, all audio enhanced. Electronic music more your thing? Ableton has your back with learningmusic.ableton.com, a site which takes you through the process of composing electronic music. A website, all made possible through the powers with have with the Web Audio API today.\nlightnote.co\nlearningmusic.ableton.com\nConsiderations\nYes, tis the season, let\u2019s be more thoughtful about our audios. There are some user experience patterns to begin with. 86andahalfyears.com tells the user they are about to \u2018enter\u2019 the site and headphones are recommended. This is a good approach because it a) deals with the autoplay policy (audio needs to be instigated by a user gesture) and b) by stating headphones are recommended you are setting the users expectations, they will expect sound, and if in a public setting can enlist the use of a common electronic device to cause less embarrassment.\nEighty-six and a half years\nAllowing mute and/or volume control clearly within the user interface is a good idea. It won\u2019t draw the user out of the experience, it\u2019ll give more control to the user about what audio they want to hear (they may not want to turn down the volume of their entire device), and it\u2019s less thought to reach for a very visible volume than to fumble with device settings.\nIndicating that sound is playing is also something to consider. Browsers do this by adding icons to tabs, but this isn\u2019t always the first place to look for everyone.\nTo The Future\nSo let\u2019s go!\nWe see amazing demos built with Web Audio, and I\u2019m sure, like me, they make you think, oh wow I wish I could do that / had thought of that / knew the first thing about audio to begin to even conceive that.\nBut audio doesn\u2019t actually need to be all bells and whistles (hey, it\u2019s Christmas). Starting, stopping and adjusting simple panning and volume might be all you need to get started to introduce some good sound design in your web design.\nIsn\u2019t it great then that there\u2019s a tutorial just for that! Head on over to the MDN Web Audio API docs where the Using the Web Audio API article takes you through playing and pausing sounds, volume control and simple panning (moving the sound from left to right on stereo speakers).\nThis year I believe we have all experienced the web as a shopping mall more than ever. It\u2019s shining store fronts, flashing adverts, fast food, loud noises.\nLet\u2019s use 2019 to create more forests to explore, oceans to dive and mountains to climb.", "year": "2018", "author": "Ruth John", "author_slug": "ruthjohn", "published": "2018-12-22T00:00:00+00:00", "url": "https://24ways.org/2018/how-to-use-audio-on-the-web/", "topic": "design"} {"rowid": 241, "title": "Jank-Free Image Loads", "contents": "There are a few fundamental problems with embedding images in pages of hypertext; perhaps chief among them is this: text is very light and loads rather fast; images are much heavier and arrive much later. Consequently, millions (billions?) of times a day, a hapless Web surfer will start reading some text on a page, and then \u2014\nYour browser doesn\u2019t support HTML5 video. Here is\n a link to the video instead.\n\n\u2014 oops! \u2014 an image pops in above it, pushing said text down the page, and our poor reader loses their place.\nBy default, partially-loaded pages have the user experience of a slippery fish, or spilled jar of jumping beans. For the rest of this article, I shall call that jarring, no-good jumpiness by its name: jank. And I\u2019ll chart a path into a jank-free future \u2013 one in which it\u2019s easy and natural to author elements that load like this:\nYour browser doesn\u2019t support HTML5 video. Here is\n a link to the video instead.\n\nJank is a very old problem, and there is a very old solution to it: the width and height attributes on . The idea is: if we stick an image\u2019s dimensions right into the HTML, browsers can know those dimensions before the image loads, and reserve some space on the layout for it so that nothing gets bumped down the page when the image finally arrives.\n\nwidth\nSpecifies the intended width of the image in pixels. When given together with the height, this allows user agents to reserve screen space for the image before the image data has arrived over the network.\n\n\u2014The HTML 3.2 Specification, published on January 14 1997\nUnfortunately for us, when width and height were first spec\u2019d and implemented, layouts were largely fixed and images were usually only intended to render at their fixed, actual dimensions. When image sizing gets fluid, width and height get weird:\nSee the Pen fluid width + fixed height = distortion by Eric Portis (@eeeps) on CodePen.\n\nwidth and height are too rigid for the responsive world. What we need, and have needed for a very long time, is a way to specify fixed aspect ratios, to pair with our fluid widths.\nI have good news, bad news, and great news.\nThe good news is, there are ways to do this, now, that work in every browser. Responsible sites, and responsible developers, go through the effort to do them.\nThe bad news is that these techniques are all terrible, cumbersome hacks. They\u2019re difficult to remember, difficult to understand, and they can interact with other pieces of CSS in unexpected ways.\nSo, the great news: there are two on-the-horizon web platform features that are trying to make no-jank, fixed-aspect-ratio, fluid-width images a natural part of the web platform.\naspect-ratio in CSS\nThe first proposed feature? An aspect-ratio property in CSS!\nThis would allow us to write CSS like this:\nimg {\n width: 100%;\n}\n\n.thumb {\n aspect-ratio: 1/1;\n}\n\n.hero {\n aspect-ratio: 16/9;\n}\nThis\u2019ll work wonders when we need to set aspect ratios for whole classes of images, which are all sized to fit within pre-defined layout slots, like the .thumb and .hero images, above.\nAlas, the harder problem, in my experience, is not images with known-ahead-of-time aspect ratios. It\u2019s images \u2013 possibly user generated images \u2013 that can have any aspect ratio. The really tricky problem is unknown-when-you\u2019re-writing-your-CSS aspect ratios that can vary per-image. Using aspect-ratio to reserve space for images like this requires inline styles:\n\nAnd inline styles give me the heebie-jeebies! As a web developer of a certain age, I have a tiny man in a blue beanie permanently embedded deep within my hindbrain, who cries out in agony whenever I author a style=\"\" attribute. And you know what? The old man has a point! By sticking super-high-specificity inline styles in my content, I\u2019m cutting off my, (or anyone else\u2019s) ability to change those aspect ratios, for whatever reason, later.\nHow might we specify aspect ratios at a lower level? How might we give browsers information about an image\u2019s dimensions, without giving them explicit instructions about how to style it?\nI\u2019ll tell you: we could give browsers the intrinsic aspect ratio of the image in our HTML, rather than specifying an extrinsic aspect ratio!\nA brief note on intrinsic and extrinsic sizing\nWhat do I mean by \u201cintrinsic\u201d and \u201cextrinsic?\u201d\nThe intrinsic size of an image is, put simply, how big it\u2019d be if you plopped it onto a page and applied no CSS to it whatsoever. An 800\u00d7600 image has an intrinsic width of 800px.\nThe extrinsic size of an image, then, is how large it ends up after CSS has been applied. Stick a width: 300px rule on that same 800\u00d7600 image, and its intrinsic size (accessible via the Image.naturalWidth property, in JavaScript) doesn\u2019t change: its intrinsic size is still 800px. But this image now has an extrinsic size (accessible via Image.clientWidth) of 300px.\nIt surprised me to learn this year that height and width are interpreted as presentational hints and that they end up setting extrinsic dimensions (albeit ones that, unlike inline styles, have absolutely no specificity).\nCSS aspect-ratio lets us avoid setting extrinsic heights and widths \u2013 and instead lets us give images (or anything else) an extrinsic aspect ratio, so that as soon as we set one dimension (possibly to a fluid width, like 100%!), the other dimension is set automatically in relation to it.\nThe last tool I\u2019m going to talk about gets us out of the extrinsic sizing game all together \u2014 which, I think, is only appropriate for a feature that we\u2019re going to be using in HTML.\nintrinsicsize in HTML\nThe proposed intrinsicsize attribute will let you do this:\n\nThat tells the browser, \u201chey, this image.jpg that I\u2019m using here \u2013 I know you haven\u2019t loaded it yet but I\u2019m just going to let you know right away that it\u2019s going to have an intrinsic size of 800\u00d7600.\u201d This gives the browser enough information to reserve space on the layout for the image, and ensures that any and all extrinsic sizing instructions, specified in our CSS, will layer cleanly on top of this, the image\u2019s intrinsic size.\nYou may ask (I did!): wait, what if my references multiple resources, which all have different intrinsic sizes? Well, if you\u2019re using srcset, intrinsicsize is a bit of a misnomer \u2013 what the attribute will do then, is specify an intrinsic aspect ratio:\n\nIn the future (and behind the \u201cExperimental Web Platform Features\u201d flag right now, in Chrome 71+), asking this image for its .naturalWidth would not return 3 \u2013 it will return whatever 75vw is, given the current viewport width. And Image.naturalHeight will return that width, divided by the intrinsic aspect ratio: 3/2.\nCan\u2019t wait\nI seem to have gotten myself into the weeds a bit. Sizing on the web is complicated!\nDon\u2019t let all of these details bury the big takeaway here: sometime soon (\ud83e\udd1e 2019\u203d \ud83e\udd1e), we\u2019ll be able to toss our terrible aspect-ratio hacks into the dustbin of history, get in the habit of setting aspect-ratios in CSS and/or intrinsicsizes in HTML, and surf a less-frustrating, more-performant, less-janky web. I can\u2019t wait!", "year": "2018", "author": "Eric Portis", "author_slug": "ericportis", "published": "2018-12-21T00:00:00+00:00", "url": "https://24ways.org/2018/jank-free-image-loads/", "topic": "code"} {"rowid": 253, "title": "Clip Paths Know No Bounds", "contents": "CSS Shapes are getting a lot of attention as browser support has increased for properties like shape-outside and clip-path. There are a few ways that we can use CSS Shapes, in particular with the clip-path property, that are not necessarily evident at first glance.\nThe basics of a clip path\nBefore we dig into specific techniques to expand on clip paths, we should first take a look at a basic shape and clip-path. Clip paths can apply a CSS Shape such as a circle(), ellipse(), inset(), or the flexible polygon() to any element. Everywhere in the element that is not within the bounds of our shape will be visually removed.\nUsing the polygon shape function, for example, we can create triangles, stars, or other straight-edged shapes as on Bennett Feely\u2019s Clippy. While fixed units like pixels can be used when defining vertices/points (where the sides meet), percentages will give more flexibility to adapt to the element\u2019s dimensions.\nSee the Pen Clip Path Box by Dan Wilson (@danwilson) on CodePen.\n\nSo for an octagon, we can set eight x, y pairs of percentages to define those points. In this case we start 30% into the width of the box for the first x and at the top of the box for the y and go clockwise. The visible area becomes the interior of the shape made by connecting these points with straight lines.\nclip-path: polygon(\n 30% 0%,\n 70% 0%,\n 100% 30%,\n 100% 70%,\n 70% 100%,\n 30% 100%,\n 0% 70%,\n 0% 30%\n);\nA shape with less vertices than the eye can see\nIt\u2019s reasonable to look at the polygon() function and assume that we need to have one pair of x, y coordinates for every point in our shape. However, we gain some flexibility by thinking outside the box \u2014 or more specifically when we think outside the range of 0% - 100%.\nOur element\u2019s box model will be the ultimate boundary for a clip-path, but we can still define points that exist beyond that natural box for an element.\nSee the Pen CSS Shapes Know No Bounds by Dan Wilson (@danwilson) on CodePen.\n\nBy going beyond the 0% - 100% range we can turn a polygon with three points into a quadrilateral, a pentagon, or a hexagon. In this example the shapes used are all similar triangles defining three points, but due to exceeding the bounds for our element box we visually see one triangle and two pentagons.\nOur earlier octagon can similarly be made with only four points.\nSee the Pen Octagon with four points by Dan Wilson (@danwilson) on CodePen.\n\nMultiple shapes, one clip path\nWe can lean on this power of going beyond the bounds of our element to also create more than one visual shape with a single polygon().\nSee the Pen Multiple shapes from one clip-path by Dan Wilson (@danwilson) on CodePen.\n\nDepending on how we lay it out we can make each shape directly, but since we know we can move around in the space beyond the element\u2019s box, we can draw extra lines to help us get where we need to go next as needed.\nIt can also help us in slicing an element. Combined with CSS Variables, we can work with overlapping elements and clip each one into alternating strips. This example is two elements, each divided into a few rectangles.\nSee the Pen 24w: Sliced Icon by Dan Wilson (@danwilson) on CodePen.\n\nDifferent shapes with fill rules\nA polygon() is not just a collection of points. There is one more key piece to its puzzle according to the specification \u2014 the Fill Rule. The default value we have been using so far is nonzero, and the second option is evenodd. These two values help determine what is considered inside and outside the shape.\nSee the Pen A Star Multiways by Dan Wilson (@danwilson) on CodePen.\n\nAs lines intersect we can get into situations where pieces seemingly on the inside can be considered outside the shape boundary. When using the evenodd fill rule, we can determine if a given point is inside or outside the boundary by drawing a ray from the point in any direction. If the ray crosses an even number of the clip path\u2019s lines, the point is considered outside, and if it crosses an odd number the point is inside.\nOrder of operations\nIt is important to note that there are many CSS properties that affect the final composited appearance of an element via CSS Filters, Blend Modes, and more.\nThese compositing effects are applied in the order:\n\nCSS Filters (e.g. filter: blur(2px))\nClipping (e.g. what this article is about)\nMasking (Clipping\u2019s cousin)\nBlend Modes (e.g. mix-blend-mode: multiply)\nOpacity\n\nThis means if we want to have a star shape and blur it, the blur will happen before the clip. And since blurs are most noticeable around the edge of an element box, the effect might be completely lost since we have clipped away the element\u2019s box edges.\nSee the Pen Order of Filter + Clip by Dan Wilson (@danwilson) on CodePen.\n\nIf we want the edges of the star to be blurred, we do have the option to wrap our clipped element in a blurred parent element. The inner element will be rendered first (with its star clip) and then the parent will blur its contents normally.\nRevealing content with animation\nCSS Shapes can be transitioned and animated, allowing us to animate the visual area of our element without affecting the content within. For example, we can start with visually hidden content (fully clipped) and grow the clip path to reveal the content within. The important caveat for polygon() is that the number of points need to be the same for each keyframe, as well as the fill rule. Otherwise the browser will not have enough information to interpolate the intermediate values. \nSee the Pen Clip Path Shape Reveal by Dan Wilson (@danwilson) on CodePen.\n\nDon\u2019t keep CSS Shapes in a box\nClip paths give us some interesting new possibilities, especially when we think of them as more than just basic shapes. We may be heavily modifying the visual representation of our elements with clip-path, but the underlying content remains unchanged and accessible which makes this property fairly powerful.", "year": "2018", "author": "Dan Wilson", "author_slug": "danwilson", "published": "2018-12-20T00:00:00+00:00", "url": "https://24ways.org/2018/clip-paths-know-no-bounds/", "topic": "code"} {"rowid": 249, "title": "Fast Autocomplete Search for Your Website", "contents": "Every website deserves a great search engine - but building a search engine can be a lot of work, and hosting it can quickly get expensive.\nI\u2019m going to build a search engine for 24 ways that\u2019s fast enough to support autocomplete (a.k.a. typeahead) search queries and can be hosted for free. I\u2019ll be using wget, Python, SQLite, Jupyter, sqlite-utils and my open source Datasette tool to build the API backend, and a few dozen lines of modern vanilla JavaScript to build the interface.\n\nTry it out here, then read on to see how I built it.\nFirst step: crawling the data\nThe first step in building a search engine is to grab a copy of the data that you plan to make searchable.\nThere are plenty of potential ways to do this: you might be able to pull it directly from a database, or extract it using an API. If you don\u2019t have access to the raw data, you can imitate Google and write a crawler to extract the data that you need.\nI\u2019m going to do exactly that against 24 ways: I\u2019ll build a simple crawler using wget, a command-line tool that features a powerful \u201crecursive\u201d mode that\u2019s ideal for scraping websites.\nWe\u2019ll start at the https://24ways.org/archives/ page, which links to an archived index for every year that 24 ways has been running.\nThen we\u2019ll tell wget to recursively crawl the website, using the --recursive flag.\nWe don\u2019t want to fetch every single page on the site - we\u2019re only interested in the actual articles. Luckily, 24 ways has nicely designed URLs, so we can tell wget that we only care about pages that start with one of the years it has been running, using the -I argument like this: -I /2005,/2006,/2007,/2008,/2009,/2010,/2011,/2012,/2013,/2014,/2015,/2016,/2017\nWe want to be polite, so let\u2019s wait for 2 seconds between each request rather than hammering the site as fast as we can: --wait 2\nThe first time I ran this, I accidentally downloaded the comments pages as well. We don\u2019t want those, so let\u2019s exclude them from the crawl using -X \"/*/*/comments\".\nFinally, it\u2019s useful to be able to run the command multiple times without downloading pages that we have already fetched. We can use the --no-clobber option for this.\nTie all of those options together and we get this command:\nwget --recursive --wait 2 --no-clobber \n -I /2005,/2006,/2007,/2008,/2009,/2010,/2011,/2012,/2013,/2014,/2015,/2016,/2017 \n -X \"/*/*/comments\" \n https://24ways.org/archives/ \nIf you leave this running for a few minutes, you\u2019ll end up with a folder structure something like this:\n$ find 24ways.org\n24ways.org\n24ways.org/2013\n24ways.org/2013/why-bother-with-accessibility\n24ways.org/2013/why-bother-with-accessibility/index.html\n24ways.org/2013/levelling-up\n24ways.org/2013/levelling-up/index.html\n24ways.org/2013/project-hubs\n24ways.org/2013/project-hubs/index.html\n24ways.org/2013/credits-and-recognition\n24ways.org/2013/credits-and-recognition/index.html\n...\nAs a quick sanity check, let\u2019s count the number of HTML pages we have retrieved:\n$ find 24ways.org | grep index.html | wc -l\n328\nThere\u2019s one last step! We got everything up to 2017, but we need to fetch the articles for 2018 (so far) as well. They aren\u2019t linked in the /archives/ yet so we need to point our crawler at the site\u2019s front page instead:\nwget --recursive --wait 2 --no-clobber \n -I /2018 \n -X \"/*/*/comments\" \n https://24ways.org/\nThanks to --no-clobber, this is safe to run every day in December to pick up any new content.\nWe now have a folder on our computer containing an HTML file for every article that has ever been published on the site! Let\u2019s use them to build ourselves a search index.\nBuilding a search index using SQLite\nThere are many tools out there that can be used to build a search engine. You can use an open-source search server like Elasticsearch or Solr, a hosted option like Algolia or Amazon CloudSearch or you can tap into the built-in search features of relational databases like MySQL or PostgreSQL.\nI\u2019m going to use something that\u2019s less commonly used for web applications but makes for a powerful and extremely inexpensive alternative: SQLite.\nSQLite is the world\u2019s most widely deployed database, even though many people have never even heard of it. That\u2019s because it\u2019s designed to be used as an embedded database: it\u2019s commonly used by native mobile applications and even runs as part of the default set of apps on the Apple Watch!\nSQLite has one major limitation: unlike databases like MySQL and PostgreSQL, it isn\u2019t really designed to handle large numbers of concurrent writes. For this reason, most people avoid it for building web applications.\nThis doesn\u2019t matter nearly so much if you are building a search engine for infrequently updated content - say one for a site that only publishes new content on 24 days every year.\nIt turns out SQLite has very powerful full-text search functionality built into the core database - the FTS5 extension.\nI\u2019ve been doing a lot of work with SQLite recently, and as part of that, I\u2019ve been building a Python utility library to make building new SQLite databases as easy as possible, called sqlite-utils. It\u2019s designed to be used within a Jupyter notebook - an enormously productive way of interacting with Python code that\u2019s similar to the Observable notebooks Natalie described on 24 ways yesterday.\nIf you haven\u2019t used Jupyter before, here\u2019s the fastest way to get up and running with it - assuming you have Python 3 installed on your machine. We can use a Python virtual environment to ensure the software we are installing doesn\u2019t clash with any other installed packages:\n$ python3 -m venv ./jupyter-venv\n$ ./jupyter-venv/bin/pip install jupyter\n# ... lots of installer output\n# Now lets install some extra packages we will need later\n$ ./jupyter-venv/bin/pip install beautifulsoup4 sqlite-utils html5lib\n# And start the notebook web application\n$ ./jupyter-venv/bin/jupyter-notebook\n# This will open your browser to Jupyter at http://localhost:8888/\nYou should now be in the Jupyter web application. Click New -> Python 3 to start a new notebook.\nA neat thing about Jupyter notebooks is that if you publish them to GitHub (either in a regular repository or as a Gist), it will render them as HTML. This makes them a very powerful way to share annotated code. I\u2019ve published the notebook I used to build the search index on my GitHub account. \n\u200b\n\nHere\u2019s the Python code I used to scrape the relevant data from the downloaded HTML files. Check out the notebook for a line-by-line explanation of what\u2019s going on.\nfrom pathlib import Path\nfrom bs4 import BeautifulSoup as Soup\nbase = Path(\"/Users/simonw/Dropbox/Development/24ways-search\")\narticles = list(base.glob(\"*/*/*/*.html\"))\n# articles is now a list of paths that look like this:\n# PosixPath('...24ways-search/24ways.org/2013/why-bother-with-accessibility/index.html')\ndocs = []\nfor path in articles:\n year = str(path.relative_to(base)).split(\"/\")[1]\n url = 'https://' + str(path.relative_to(base).parent) + '/'\n soup = Soup(path.open().read(), \"html5lib\")\n author = soup.select_one(\".c-continue\")[\"title\"].split(\n \"More information about\"\n )[1].strip()\n author_slug = soup.select_one(\".c-continue\")[\"href\"].split(\n \"/authors/\"\n )[1].split(\"/\")[0]\n published = soup.select_one(\".c-meta time\")[\"datetime\"]\n contents = soup.select_one(\".e-content\").text.strip()\n title = soup.find(\"title\").text.split(\" \u25c6\")[0]\n try:\n topic = soup.select_one(\n '.c-meta a[href^=\"/topics/\"]'\n )[\"href\"].split(\"/topics/\")[1].split(\"/\")[0]\n except TypeError:\n topic = None\n docs.append({\n \"title\": title,\n \"contents\": contents,\n \"year\": year,\n \"author\": author,\n \"author_slug\": author_slug,\n \"published\": published,\n \"url\": url,\n \"topic\": topic,\n })\nAfter running this code, I have a list of Python dictionaries representing each of the documents that I want to add to the index. The list looks something like this:\n[\n {\n \"title\": \"Why Bother with Accessibility?\",\n \"contents\": \"Web accessibility (known in other fields as inclus...\",\n \"year\": \"2013\",\n \"author\": \"Laura Kalbag\",\n \"author_slug\": \"laurakalbag\",\n \"published\": \"2013-12-10T00:00:00+00:00\",\n \"url\": \"https://24ways.org/2013/why-bother-with-accessibility/\",\n \"topic\": \"design\"\n },\n {\n \"title\": \"Levelling Up\",\n \"contents\": \"Hello, 24 ways. Iu2019m Ashley and I sell property ins...\",\n \"year\": \"2013\",\n \"author\": \"Ashley Baxter\",\n \"author_slug\": \"ashleybaxter\",\n \"published\": \"2013-12-06T00:00:00+00:00\",\n \"url\": \"https://24ways.org/2013/levelling-up/\",\n \"topic\": \"business\"\n },\n ...\nMy sqlite-utils library has the ability to take a list of objects like this and automatically create a SQLite database table with the right schema to store the data. Here\u2019s how to do that using this list of dictionaries.\nimport sqlite_utils\ndb = sqlite_utils.Database(\"/tmp/24ways.db\")\ndb[\"articles\"].insert_all(docs)\nThat\u2019s all there is to it! The library will create a new database and add a table to it called articles with the necessary columns, then insert all of the documents into that table.\n(I put the database in /tmp/ for the moment - you can move it to a more sensible location later on.)\nYou can inspect the table using the sqlite3 command-line utility (which comes with OS X) like this:\n$ sqlite3 /tmp/24ways.db\nsqlite> .headers on\nsqlite> .mode column\nsqlite> select title, author, year from articles;\ntitle author year \n------------------------------ ------------ ----------\nWhy Bother with Accessibility? Laura Kalbag 2013 \nLevelling Up Ashley Baxte 2013 \nProject Hubs: A Home Base for Brad Frost 2013 \nCredits and Recognition Geri Coady 2013 \nManaging a Mind Christopher 2013 \nRun Ragged Mark Boulton 2013 \nGet Started With GitHub Pages Anna Debenha 2013 \nCoding Towards Accessibility Charlie Perr 2013 \n...\n\nThere\u2019s one last step to take in our notebook. We know we want to use SQLite\u2019s full-text search feature, and sqlite-utils has a simple convenience method for enabling it for a specified set of columns in a table. We want to be able to search by the title, author and contents fields, so we call the enable_fts() method like this:\ndb[\"articles\"].enable_fts([\"title\", \"author\", \"contents\"])\nIntroducing Datasette\nDatasette is the open-source tool I\u2019ve been building that makes it easy to both explore SQLite databases and publish them to the internet.\nWe\u2019ve been exploring our new SQLite database using the sqlite3 command-line tool. Wouldn\u2019t it be nice if we could use a more human-friendly interface for that?\nIf you don\u2019t want to install Datasette right now, you can visit https://search-24ways.herokuapp.com/ to try it out against the 24 ways search index data. I\u2019ll show you how to deploy Datasette to Heroku like this later in the article.\nIf you want to install Datasette locally, you can reuse the virtual environment we created to play with Jupyter:\n./jupyter-venv/bin/pip install datasette\nThis will install Datasette in the ./jupyter-venv/bin/ folder. You can also install it system-wide using regular pip install datasette.\nNow you can run Datasette against the 24ways.db file we created earlier like so:\n./jupyter-venv/bin/datasette /tmp/24ways.db\nThis will start a local webserver running. Visit http://localhost:8001/ to start interacting with the Datasette web application.\nIf you want to try out Datasette without creating your own 24ways.db file you can download the one I created directly from https://search-24ways.herokuapp.com/24ways-ae60295.db\nPublishing the database to the internet\nOne of the goals of the Datasette project is to make deploying data-backed APIs to the internet as easy as possible. Datasette has a built-in command for this, datasette publish. If you have an account with Heroku or Zeit Now, you can deploy a database to the internet with a single command. Here\u2019s how I deployed https://search-24ways.herokuapp.com/ (running on Heroku\u2019s free tier) using datasette publish:\n$ ./jupyter-venv/bin/datasette publish heroku /tmp/24ways.db --name search-24ways\n-----> Python app detected\n-----> Installing requirements with pip\n\n-----> Running post-compile hook\n-----> Discovering process types\n Procfile declares types -> web\n\n-----> Compressing...\n Done: 47.1M\n-----> Launching...\n Released v8\n https://search-24ways.herokuapp.com/ deployed to Heroku\nIf you try this out, you\u2019ll need to pick a different --name, since I\u2019ve already taken search-24ways.\nYou can run this command as many times as you like to deploy updated versions of the underlying database.\nSearching and faceting\nDatasette can detect tables with SQLite full-text search configured, and will add a search box directly to the page. Take a look at http://search-24ways.herokuapp.com/24ways-b607e21/articles to see this in action.\n\u200b\n\nSQLite search supports wildcards, so if you want autocomplete-style search where you don\u2019t need to enter full words to start getting results you can add a * to the end of your search term. Here\u2019s a search for access* which returns articles on accessibility:\nhttp://search-24ways.herokuapp.com/24ways-ae60295/articles?_search=acces%2A\nA neat feature of Datasette is the ability to calculate facets against your data. Here\u2019s a page showing search results for svg with facet counts calculated against both the year and the topic columns:\nhttp://search-24ways.herokuapp.com/24ways-ae60295/articles?_search=svg&_facet=year&_facet=topic\nEvery page visible via Datasette has a corresponding JSON API, which can be accessed using the JSON link on the page - or by adding a .json extension to the URL:\nhttp://search-24ways.herokuapp.com/24ways-ae60295/articles.json?_search=acces%2A\nBetter search using custom SQL\nThe search results we get back from ../articles?_search=svg are OK, but the order they are returned in is not ideal - they\u2019re actually being returned in the order they were inserted into the database! You can see why this is happening by clicking the View and edit SQL link on that search results page.\nThis exposes the underlying SQL query, which looks like this:\nselect rowid, * from articles where rowid in (\n select rowid from articles_fts where articles_fts match :search\n) order by rowid limit 101\nWe can do better than this by constructing a custom SQL query. Here\u2019s the query we will use instead:\nselect\n snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet,\n articles_fts.rank, articles.title, articles.url, articles.author, articles.year\nfrom articles\n join articles_fts on articles.rowid = articles_fts.rowid\nwhere articles_fts match :search || \"*\"\n order by rank limit 10;\nYou can try this query out directly - since Datasette opens the underling SQLite database in read-only mode and enforces a one second time limit on queries, it\u2019s safe to allow users to provide arbitrary SQL select queries for Datasette to execute.\nThere\u2019s a lot going on here! Let\u2019s break the SQL down line-by-line:\nselect\n snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet,\nWe\u2019re using snippet(), a built-in SQLite function, to generate a snippet highlighting the words that matched the query. We use two unique strings that I made up to mark the beginning and end of each match - you\u2019ll see why in the JavaScript later on.\n articles_fts.rank, articles.title, articles.url, articles.author, articles.year\nThese are the other fields we need back - most of them are from the articles table but we retrieve the rank (representing the strength of the search match) from the magical articles_fts table.\nfrom articles\n join articles_fts on articles.rowid = articles_fts.rowid\narticles is the table containing our data. articles_fts is a magic SQLite virtual table which implements full-text search - we need to join against it to be able to query it.\nwhere articles_fts match :search || \"*\"\n order by rank limit 10;\n:search || \"*\" takes the ?search= argument from the page querystring and adds a * to the end of it, giving us the wildcard search that we want for autocomplete. We then match that against the articles_fts table using the match operator. Finally, we order by rank so that the best matching results are returned at the top - and limit to the first 10 results.\nHow do we turn this into an API? As before, the secret is to add the .json extension. Datasette actually supports multiple shapes of JSON - we\u2019re going to use ?_shape=array to get back a plain array of objects:\nJSON API call to search for articles matching SVG\nThe HTML version of that page shows the time taken to execute the SQL in the footer. Hitting refresh a few times, I get response times between 2 and 5ms - easily fast enough to power a responsive autocomplete feature.\nA simple JavaScript autocomplete search interface\nI considered building this using React or Svelte or another of the myriad of JavaScript framework options available today, but then I remembered that vanilla JavaScript in 2018 is a very productive environment all on its own.\nWe need a few small utility functions: first, a classic debounce function adapted from this one by David Walsh:\nfunction debounce(func, wait, immediate) {\n let timeout;\n return function() {\n let context = this, args = arguments;\n let later = () => {\n timeout = null;\n if (!immediate) func.apply(context, args);\n };\n let callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) func.apply(context, args);\n };\n};\nWe\u2019ll use this to only send fetch() requests a maximum of once every 100ms while the user is typing.\nSince we\u2019re rendering data that might include HTML tags (24 ways is a site about web development after all), we need an HTML escaping function. I\u2019m amazed that browsers still don\u2019t bundle a default one of these:\nconst htmlEscape = (s) => s.replace(\n />/g, '>'\n).replace(\n /Autocomplete search\n
\n

\n
\n
\nAnd now the autocomplete implementation itself, as a glorious, messy stream-of-consciousness of JavaScript:\n// Embed the SQL query in a multi-line backtick string:\nconst sql = `select\n snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet,\n articles_fts.rank, articles.title, articles.url, articles.author, articles.year\nfrom articles\n join articles_fts on articles.rowid = articles_fts.rowid\nwhere articles_fts match :search || \"*\"\n order by rank limit 10`;\n\n// Grab a reference to the \nconst searchbox = document.getElementById(\"searchbox\");\n\n// Used to avoid race-conditions:\nlet requestInFlight = null;\n\nsearchbox.onkeyup = debounce(() => {\n const q = searchbox.value;\n // Construct the API URL, using encodeURIComponent() for the parameters\n const url = (\n \"https://search-24ways.herokuapp.com/24ways-866073b.json?sql=\" +\n encodeURIComponent(sql) +\n `&search=${encodeURIComponent(q)}&_shape=array`\n );\n // Unique object used just for race-condition comparison\n let currentRequest = {};\n requestInFlight = currentRequest;\n fetch(url).then(r => r.json()).then(d => {\n if (requestInFlight !== currentRequest) {\n // Avoid race conditions where a slow request returns\n // after a faster one.\n return;\n }\n let results = d.map(r => `\n
\n

${htmlEscape(r.title)}

\n

${htmlEscape(r.author)} - ${r.year}

\n

${highlight(r.snippet)}

\n
\n `).join(\"\");\n document.getElementById(\"results\").innerHTML = results;\n });\n}, 100); // debounce every 100ms\nThere\u2019s just one more utility function, used to help construct the HTML results:\nconst highlight = (s) => htmlEscape(s).replace(\n /b4de2a49c8/g, ''\n).replace(\n /8c94a2ed4b/g, ''\n);\nThis is what those unique strings passed to the snippet() function were for.\nAvoiding race conditions in autocomplete\nOne trick in this code that you may not have seen before is the way race-conditions are handled. Any time you build an autocomplete feature, you have to consider the following case:\n\nUser types acces\nBrowser sends request A - querying documents matching acces*\nUser continues to type accessibility\nBrowser sends request B - querying documents matching accessibility*\nRequest B returns. It was fast, because there are fewer documents matching the full term\nThe results interface updates with the documents from request B, matching accessibility*\nRequest A returns results (this was the slower of the two requests)\nThe results interface updates with the documents from request A - results matching access*\n\nThis is a terrible user experience: the user saw their desired results for a brief second, and then had them snatched away and replaced with those results from earlier on.\nThankfully there\u2019s an easy way to avoid this. I set up a variable in the outer scope called requestInFlight, initially set to null.\nAny time I start a new fetch() request, I create a new currentRequest = {} object and assign it to the outer requestInFlight as well.\nWhen the fetch() completes, I use requestInFlight !== currentRequest to sanity check that the currentRequest object is strictly identical to the one that was in flight. If a new request has been triggered since we started the current request we can detect that and avoid updating the results.\nIt\u2019s not a lot of code, really\nAnd that\u2019s the whole thing! The code is pretty ugly, but when the entire implementation clocks in at fewer than 70 lines of JavaScript, I honestly don\u2019t think it matters. You\u2019re welcome to refactor it as much you like.\nHow good is this search implementation? I\u2019ve been building search engines for a long time using a wide variety of technologies and I\u2019m happy to report that using SQLite in this way is genuinely a really solid option. It scales happily up to hundreds of MBs (or even GBs) of data, and the fact that it\u2019s based on SQL makes it easy and flexible to work with.\nA surprisingly large number of desktop and mobile applications you use every day implement their search feature on top of SQLite.\nMore importantly though, I hope that this demonstrates that using Datasette for an API means you can build relatively sophisticated API-backed applications with very little backend programming effort. If you\u2019re working with a small-to-medium amount of data that changes infrequently, you may not need a more expensive database. Datasette-powered applications easily fit within the free tier of both Heroku and Zeit Now.\nFor more of my writing on Datasette, check out the datasette tag on my blog. And if you do build something fun with it, please let me know on Twitter.", "year": "2018", "author": "Simon Willison", "author_slug": "simonwillison", "published": "2018-12-19T00:00:00+00:00", "url": "https://24ways.org/2018/fast-autocomplete-search-for-your-website/", "topic": "code"} {"rowid": 256, "title": "Develop Your Naturalist Superpowers with Observable Notebooks and iNaturalist", "contents": "We\u2019re going to level up your knowledge of what animals you might see in an area at a particular time of year - a skill every naturalist* strives for - using technology! Using iNaturalist and Observable Notebooks we\u2019re going to prototype seasonality graphs for particular species in an area, and automatically create a guide to what animals you might see in each month.\n*(a Naturalist is someone who likes learning about nature, not someone who\u2019s a fan of being naked, that\u2019s a \u2018Naturist\u2019\u2026 different thing!)\nLooking for critters in rocky intertidal habitats\nOne of my favourite things to do is going rockpooling, or as we call it over here in California, \u2018tidepooling\u2019. Amounting to the same thing, it\u2019s going to a beach that has rocks where the tide covers then uncovers little pools of water at different times of the day. All sorts of fun creatures and life can be found in this \u2018rocky intertidal habitat\u2019\nA particularly exciting creature that lives here is the Nudibranch, a type of super colourful \u2018sea slug\u2019. There are over 3000 species of Nudibranch worldwide. (The word \u201cnudibranch\u201d comes from the Latin nudus, naked, and the Greek \u03b2\u03c1\u03b1\u03bd\u03c7\u03b9\u03b1 / brankhia, gills.)\n\u200b\n\nThey are however quite tricky to find! Even though they are often brightly coloured and interestingly shaped, some of them are very small, and in our part of the world in the Bay Area in California their appearance in our rockpools is seasonal. We see them more often in Summer months, despite the not-as-low tides as in our Winter and Spring seasons.\nMy favourite place to go tidepooling here is Pillar Point in Half Moon bay (at other times of the year more famously known for the surf competition \u2018Mavericks\u2019). The rockpools there are rich in species diversity, of varied types and water-coverage habitat zones as well as being relatively accessible.\n\u200b\n\nI was rockpooling at Pillar Point recently with my parents and we talked to a lady who remarked that she hadn\u2019t seen any Nudibranchs on her visit this time. I realised that having an idea of what species to find where, and at what time of year is one of the many superpower goals of every budding Naturalist. \nUsing technology and the croudsourced species observations of the iNaturalist community we can shortcut our way to this superpower!\nFinding nearby animals with iNaturalist\nWe\u2019re going to be getting our information about what animals you can see in Pillar Point using iNaturalist. iNaturalist is a really fun platform that helps connect people to nature and report their findings of life in the outdoors. It is also a community of nature-loving people who help each other identify and confirm those observations. iNaturalist is a project run as a joint initiative by the California Academy of Sciences and the National Geographic Society.\nI\u2019ve been using iNaturalist for over two years to record and identify plants and animals that I\u2019ve found in the outdoors. I use their iPhone app to upload my pictures, which then uses machine learning algorithms to make an initial guess at what it is I\u2019ve seen. The community is really active, and I often find someone else has verified or updated my species guess pretty soon after posting. \nThis process is great because once an observation has been identified by at least two people it becomes \u2018verified\u2019 and is considered research grade. Research grade observations get exported and used by scientists, as well as being indexed by the Global Biodiversity Information Facility, GBIF.\n\u200b\n\niNaturalist has a great API and API explorer, which makes interacting and prototyping using iNaturalist data really fun. For example, if you go to the API explorer and expand the Observations : Search and fetch section and then the GET /observations API, you get a selection of input boxes that allow you to play with options that you can then pass to the API when you click the \u2018Try it out\u2019 button.\n\u200b\n\nYou\u2019ll then get a URL that looks a bit like\nhttps://api.inaturalist.org/v1/observations?captive=false &geo=true&verifiable=true&taxon_id=47113&lat=37.495461&lng=-122.499584 &radius=5&order=desc&order_by=created_at \nwhich you can call and interrrogate using a programming language of your choice.\nIf you would like to see an all-JavaScript application that uses the iNaturalist API, take a look at OwlsNearMe.com which Simon and I built one weekend earlier this year. It gets your location and shows you all iNaturalist observations of owls near you and lists which species you are likely to see (not adjusted for season).\nRapid development using Observable Notebooks\nWe\u2019re going to be using Observable Notebooks to prototype our examples, pulling data down from iNaturalist. I really like using visual notebooks like Observable, they are great for learning and building things quickly. You may be familiar with Jupyter notebooks for Python which is similar but takes a bit of setup to get going - I often use these for prototyping too. Observable is amazing for querying and visualising data with JavaScript and since it is a hosted product it doesn\u2019t require any setup at all.\nYou can follow along and play with this example on my Observable notebook. If you create an account there you can fork my notebook and create your own version of this example. \nEach \u2018notebook\u2019 consists of a page with a column of \u2018cells\u2019, similar to what you get in a spreadsheet. A cell can contain Markdown text or JavaScript code and the output of evaluating the cell appears above the code that generated it. There are lots of tutorials out there on Observable Notebooks, I like this code introduction one from Observable (and D3) creator Mike Bostock.\nDeveloping your Naturalist superpowers\nIf you have an idea of what plants and critters you might see in a place at the time you visit, you can hone in on what you want to study and train your Naturalist eye to better identify the life around you.\nFor our example, we care about wildlife we can see at Pillar Point, so we need a way of letting the iNaturalist API know which area we are interested in.\nWe could use a latitide, longitude and radius for this, but a rectangular bounding box is a better shape for the reef. We can use this tool to draw the area we want to search within: boundingbox.klokantech.com\n\u200b\n\nThe tool lets you export the bounding box in several forms using the dropdown at the bottom left under the map givese We are going to use the \u2018DublinCore\u2019 format as it\u2019s closest to the format needed by the iNaturalist API.\n westlimit=-122.50542; southlimit=37.492805; eastlimit=-122.492738; northlimit=37.499811\nA quick map primer:\nThe higher the latitude the more north it is\nThe lower the latitude the more south it is\nLatitude 0 = the equator\n\nThe higher the longitude the more east it is of Greenwich\nThe lower the longitude the more west it is of Greenwich\nLongitude 0 = Greenwich\nIn the iNaturalst API we want to use the parameters nelat, nelng, swlat, swlng to create a query that looks inside a bounding box of Pillar Point near Half Moon Bay in California:\nnelat = highest latitude = north limit = 37.499811\nnelng = highest longitude = east limit = -122.492738\nswlat = smallest latitude = south limit = 37.492805\nswlng = smallest longitude = west limit = 122.50542\nAs API parameters these look like this:\n?nelat=37.499811&nelng=-122.492738&swlat=37.492805&swlng=122.50542\nThese parameters in this format can be used for most of the iNaturalist API methods.\nNudibranch seasonality in Pillar Point\nWe can use the iNaturalist observation_histogram API to get a count of Nudibranch observations per week-of-year across all time and within our Pillar Point bounding box.\nIn addition to the geographic parameters that we just worked out, we are also sending the taxon_id of 47113, which is iNaturalists internal number associated with the Nudibranch taxon. By using this we can get all species which are under the parent \u2018Order Nudibranchia\u2019. \nAnother useful piece of naturalist knowledge is understanding the biological classification scheme of Taxanomic Rank - roughly, when a species has a Latin name of two words eg \u2018Glaucus Atlanticus\u2019 the first Latin word is the \u2018Genus\u2019 like a family name \u2018Glaucus\u2019, and the second word identifies that particular species, like a given name \u2018Atlanticus\u2019. \nThe two Latin words together indicate a specific species, the term we use colloquially to refer to a type of animal often differs wildly region to region, and sometimes the same common name in two countries can refer to two different species. The common names for the Glaucus Atlanticus (which incidentally is my favourite sea slug) include: sea swallow, blue angel, blue glaucus, blue dragon, blue sea slug and blue ocean slug! Because this gets super confusing, Scientists like using this Latin name format instead.\nThe following piece of code asks the iNaturalist Histogram API to return per-week counts for verified observations of Nudibranchs within our Pillar Point bounding box:\npillar_point_counts_per_week = fetch(\n \"https://api.inaturalist.org/v1/observations/histogram?taxon_id=47113&nelat=37.499811&nelng=-122.492738&swlat=37.492805&swlng=-122.50542&date_field=observed&interval=week_of_year&verifiable=true\"\n ).then(response => {\n return response.json();\n})\nOur next step is to take this data and draw a graph! We\u2019ll be using Vega-Lite for this, which is a fab JavaScript graphing libary that is also easy and fun to use with Observable Notebooks. \n(Here is a great tutorial on exploring data and drawing graphs with Observable and Vega-Lite)\nThe iNaturalist API returns data that looks like this:\n{\n \"total_results\": 53,\n \"page\": 1,\n \"per_page\": 53,\n \"results\": {\n \"week_of_year\": {\n \"1\": 136,\n \"2\": 20,\n \"3\": 150,\n \"4\": 65,\n \"5\": 186,\n \"6\": 74,\n \"7\": 47,\n \"8\": 87,\n \"9\": 64,\n \"10\": 56,\nBut for our Vega-Lite graph we need data that looks like this:\n[{\n \"week\": \"01\",\n \"value\": 136\n}, {\n \"week\": \"02\",\n \"value\": 20\n}, ...]\nWe can convert what we get back from the API to the second format using a loop that iterates over the object keys:\nobjects_to_plot = {\n let objects = [];\n Object.keys(pillar_point_counts_per_week.results.week_of_year).map(function(week_index) {\n objects.push({\n week: `Wk ${week_index.toString()}`,\n observations: pillar_point_counts_per_week.results.week_of_year[week_index]\n });\n })\n return objects;\n}\nWe can then plug this into Vega-Lite to draw us a graph:\nvegalite({\n data: {values: objects_to_plot},\n mark: \"bar\",\n encoding: {\n x: {field: \"week\", type: \"nominal\", sort: null},\n y: {field: \"observations\", type: \"quantitative\"}\n },\n width: width * 0.9\n})\n\nIt\u2019s worth noting that we have a lot of observations of Nudibranchs particularly at Pillar Point due in no small part to the intertidal monitoring research that Alison Young and Rebecca Johnson facilitate for the California Achademy of Sciences. \nSo, what if we want to look for the seasonality of observations of a particular species of adorable sea slug? We want our interface to have a select box with a list of all the species you might find at any time of year. We can do this using the species_counts API to create us an object with the iNaturalist species ID and common & Latin names.\npillar_point_nudibranches = {\n let api_results = await fetch(\n \"https://api.inaturalist.org/v1/observations/species_counts?taxon_id=47113&nelat=37.499811&nelng=-122.492738&swlat=37.492805&swlng=-122.50542&date_field=observed&verifiable=true\"\n ).then(r => r.json())\n\n let species_list = api_results.results.map(i => ({\n value: i.taxon.id,\n label: `${i.taxon.preferred_common_name} (${i.taxon.name})`\n }));\n\n return species_list\n}\nWe can create an interactive select box by importing code from Jeremy Ashkanas\u2019 Observable Notebook: add import {select} from \"@jashkenas/inputs\" to a cell anywhere in our notebook. Observable is magic: like a spreadsheet, the order of the cells doesn\u2019t matter - if one cell is referenced by any other cell then when that cell updates all the other cells refresh themselves. You can also import and reference one notebook from another!\nviewof select_species = select({\n title: \"Which Nudibranch do you want to see seasonality for?\",\n options: [{value: \"\", label: \"All the Nudibranchs!\"}, ...pillar_point_nudibranches],\n value: \"\"\n})\nThen we go back to our old favourite, the histogram API just like before, only this time we are calling it with the value created by our select box ${select_species} as taxon_id instead of the number 47113.\npillar_point_counts_per_month_per_species = fetch(\n `https://api.inaturalist.org/v1/observations/histogram?taxon_id=${select_species}&nelat=37.499811&nelng=-122.492738&swlat=37.492805&swlng=-122.50542&date_field=observed&interval=month_of_year&verifiable=true`\n).then(r => r.json())\nNow for the fun graph bit! As we did before, we re-format the result of the API into a format compatible with Vega-Lite:\nobjects_to_plot_species_month = {\n let objects = [];\n Object.keys(pillar_point_counts_per_month_per_species.results.month_of_year).map(function(month_index) {\n objects.push({\n month: (new Date(2018, (month_index - 1), 1)).toLocaleString(\"en\", {month: \"long\"}),\n observations: pillar_point_counts_per_month_per_species.results.month_of_year[month_index]\n });\n })\n return objects;\n}\n(Note that in the above code we are creating a date object with our specific month in, and using toLocalString() to get the longer English name for the month. Because the JavaScript Date object counts January as 0, we use month_index -1 to get the correct month)\nAnd we draw the graph as we did before, only now if you interact with the select box in Observable the graph will dynamically update!\nvegalite({\n data: {values: objects_to_plot_species_month},\n mark: \"bar\",\n encoding: {\n x: {field: \"month\", type: \"nominal\", sort:null},\n y: {field: \"observations\", type: \"quantitative\"}\n },\n width: width * 0.9\n})\nNow we can see when is the best time of year to plan to go tidepooling in Pillar Point if we want to find a specific species of Nudibranch.\n\u200b\n\nThis tool is great for planning when we to go rockpooling at Pillar Point, but what about if you are going this month and want to pre-train your eye with what to look for in order to impress your friends with your knowledge of Nudibranchs?\nWell\u2026 we can create ourselves a dynamic guide that you can with a list of the species, their photo, name and how many times they have been observed in that month of the year!\nOur select box this time looks as follows, simpler than before but assigning the month value to the variable selected_month.\nviewof selected_month = select({\n title: \"When do you want to see Nudibranchs?\",\n options: [\n { label: \"Whenever\", value: \"\" },\n { label: \"January\", value: \"1\" },\n { label: \"February\", value: \"2\" },\n { label: \"March\", value: \"3\" },\n { label: \"April\", value: \"4\" },\n { label: \"May\", value: \"5\" },\n { label: \"June\", value: \"6\" },\n { label: \"July\", value: \"7\" },\n { label: \"August\", value: \"8\" },\n { label: \"September\", value: \"9\" },\n { label: \"October\", value: \"10\" },\n { label: \"November\", value: \"11\" },\n { label: \"December\", value: \"12\" },\n ],\n value: \"\"\n })\nWe then can use the species_counts API to get all the relevant information about which species we can see in month=${selected_month}. We\u2019ll be able to reference this response object and its values later with the variable we just created, eg: all_species_data.results[0].taxon.name.\nall_species_data = fetch(\n `https://api.inaturalist.org/v1/observations/species_counts?taxon_id=47113&month=${selected_month}&nelat=37.499811&nelng=-122.492738&swlat=37.492805&swlng=-122.50542&verifiable=true`\n).then(r => r.json())\nYou can render HTML directly in a notebook cell using Observable\u2019s html tagged template literal:\n\n\n

If you go to Pillar Point ${\n {\"\": \"\",\n \"1\":\"in January\",\n \"2\":\"in Febrary\",\n \"3\":\"in March\",\n \"4\":\"in April\",\n \"5\":\"in May\",\n \"6\":\"in June\",\n \"7\":\"in July\",\n \"8\":\"in August\",\n \"9\":\"in September\",\n \"10\":\"in October\",\n \"11\":\"in November\",\n \"12\":\"in December\",\n }[selected_month]\n } you might see\u2026

\n\n
\n${all_species_data.results.map(s => `

${s.taxon.name}

\n

Seen ${s.count} times

\n
\n`)}\n
\nThese few lines of HTML are all you need to get this exciting dynamic guide to what Nudibranchs you will see in each month!\n\u200b\n\nPlay with it yourself in this Observable Notebook.\nConclusion\nI hope by playing with these examples you have an idea of how powerful it can be to prototype using Observable Notebooks and how you can use the incredible crowdsourced community data and APIs from iNaturalist to augment your naturalist skills and impress your friends with your new \u2018knowledge of nature\u2019 superpower.\nLastly I strongly encourage you to get outside on a low tide to explore your local rocky intertidal habitat, and all the amazing critters that live there.\nHere is a great introduction video to tidepooling / rockpooling, by Rebecca Johnson and Alison Young from the California Academy of Sciences.", "year": "2018", "author": "Natalie Downe", "author_slug": "nataliedowne", "published": "2018-12-18T00:00:00+00:00", "url": "https://24ways.org/2018/observable-notebooks-and-inaturalist/", "topic": "code"} {"rowid": 244, "title": "It\u2019s Beginning to Look a Lot Like XSSmas", "contents": "I dread the office Secret Santa. I have a knack for choosing well-meaning but inappropriate presents, like a bottle of port for a teetotaller, a cheese-tasting experience for a vegan, or heaven forbid, Spurs socks for an Arsenal supporter. Ok, the last one was intentional.\nIt\u2019s the same with gifting code. Once, I made a pattern library for A List Apart which I open sourced, and a few weeks later, a glaring security vulnerability was found in it. My gift was so generous that it enabled unrestricted access to any file on any public-facing server that hosted it.\nWith platforms like GitHub and npm, giving the gift of code is so easy it\u2019s practically a no-brainer. This giant, open source yankee swap helps us do our jobs without starting from scratch with every project. But like any gift-giving, it\u2019s also risky.\nVulnerabilities and Open Source\nOpen source code is not inherently more or less vulnerable than closed-source code. What makes it higher risk is that the same piece of code gets reused in lots of places, meaning a hacker can use the same exploit mechanism on the same vulnerable code in different apps.\nGraph showing the number of open source vulnerabilities published per year, from the State of Open Source Security 2017\nIn the first 24 ways article this year, Katie referenced a few different types of vulnerability:\n\nCross-site Request Forgery (also known as CSRF)\nSQL Injection\nCross-site Scripting (also known as XSS)\n\nThere are many more types of vulnerability, and those that live under the same category share similarities. \nFor example, my favourite \u2013 is it weird to have a favourite vulnerability? \u2013 is Cross Site Scripting (XSS), which allows for the injection of scripts into web pages. This is a really common vulnerability often unwittingly added by developers. OWASP (the Open Web Application Security Project) wrote a great article about how to prevent opening the door to XSS attacks \u2013 share it generously with your colleagues.\nMost vulnerabilities like this are not added intentionally \u2013 they\u2019re doors left ajar due to the way something has been scripted, like the over-generous code in my pattern library. \nOthers, though, are added intentionally. A few months ago, a hacker, disguised as a helpful elf, offered to take over the maintenance of a popular npm package that had been unmaintained for a couple of years. The owner had moved onto other projects, and was keen to see it continue to be maintained by someone else, so transferred ownership. Fast-forward 3 months, it was discovered that the individual had quietly added a malicious package to the codebase, and the obfuscated code in it had been unwittingly installed onto thousands of apps. The code added was designed to harvest Bitcoin if it was run alongside another application. It was only spotted due to a developer\u2019s curiosity.\nAnother tactic to get developers to unwittingly install malicious packages into their codebase is \u201ctyposquatting\u201d \u2013 back in August last year, npm reported that a user had been publishing packages with very similar names to popular packages (for example, crossenv instead of cross-env). \nThis is a big wakeup call for open source maintainers. Techniques like this are likely to be used more as the maintenance of open source libraries becomes an increasing burden to their owners. After all, starting a new project often has a greater reward than maintaining an existing one, but remember, an open source library is for life, not just for Christmas.\nSanta\u2019s on his sleigh\nIf you use open source libraries, chances are that these libraries also use open source libraries. Your app may only have a handful of dependencies, but tucked in the back of that sleigh may be a whole extra sack of dependencies known as deep dependencies (ones that you didn\u2019t directly install, but are dependencies of that dependency), and these can contain vulnerabilities too.\nLet\u2019s look at the npm package santa as an example. santa has 8 direct dependencies listed on npm. That seems pretty manageable. But that\u2019s just the tip of the iceberg \u2013 have a look at the full dependency tree which contains 109 dependencies \u2013 more dependencies than there are Christmas puns in this article. Only one of these direct dependencies has a vulnerability (at the time of writing), but there are actually 13 other known vulnerabilities in santa, which have been introduced through its deeper dependencies.\nFixing vulnerabilities \u2013 the ultimate christmas gift\nIf you\u2019re a maintainer of open source libraries, taking good care of them is the ultimate gift you can give. Keep your dependencies up to date, use a security tool to monitor and alert you when new vulnerabilities are found in your code, and fix or patch them promptly. This will help keep the whole open source ecosystem healthy.\nWhen you find out about a new vulnerability, you have some options:\nFix the vulnerability via an upgrade\nYou can often fix a vulnerability by upgrading the library to the latest version. Make sure you\u2019re using software that monitors your dependencies for new security issues and lets you know when a fix is ready, otherwise you may be unwittingly using a vulnerable version.\nPatch the vulnerable code\nSometimes, a fix for a vulnerable library isn\u2019t possible. This is often the case when a library is no longer being maintained, or the version of the library being used might be so out of date that upgrading it would cause a breaking change. Patches are bits of code that will fix that particular issue, but won\u2019t change anything else.\nSwitch to a different library\nIf the library you\u2019re using has no fix or patch, you may be better of switching it out for another one, particularly if it looks like it\u2019s being unmaintained.\nResponsibly disclosing vulnerabilities\nKnowing how to responsibly disclose vulnerabilities is something I\u2019m ashamed to admit that I didn\u2019t know about before I joined a security company. But it\u2019s so important! On discovering a new vulnerability, a developer has a few options: \n\nA malicious developer will exploit that vulnerability for their own gain. \nA reckless (or inexperienced) developer will disclose that vulnerability to the world without following a responsible disclosure process. This opens the door to an unethical developer exploiting the vulnerability. At Snyk, we monitor social media for mentions of newly found vulnerabilities so we can add them to our database and share fixes before they get exploited.\nAn ethical and aware developer will follow what\u2019s known as a \u201cresponsible disclosure process\u201d. They will contact the maintainer of the code privately, allowing reasonable time for them to release a fix for the issue and to give others who use that vulnerable code a chance to fix it too.\n\nIt\u2019s important to understand this process if you\u2019re a maintainer or contributor of code. It can be daunting when a report comes in, but understanding and following the right steps will help reduce the risk to the people who use that code.\nSo what does responsible disclosure look like? I\u2019ll take Node.js\u2019s security disclosure policy as an example. They ask that all security issues that are found in Node.js are reported there. (There\u2019s a separate process for bug found in third-party npm packages). Once you\u2019ve reported a vulnerability, they promise to acknowledge it within 24 hours, and to give a more detailed response within 48 hours. If they find that the issue is indeed a security bug, they\u2019ll give you regular updates about the progress they\u2019re making towards fixing it. As part of this, they\u2019ll figure out which versions are affected, and prepare fixes for them. They\u2019ll assign the vulnerability a CVE (Common Vulnerabilities and Exposures) ID and decide on an embargo date for public disclosure. On the date of the embargo, they announce the vulnerability in their Node.js security mailing list and deploy fixes to nodejs.org.\nTim Kadlec published an in-depth article about responsible disclosures if you\u2019re interested in knowing more. It has some interesting horror stories of what happened when the disclosure process was not followed.\nEncourage responsible disclosure\nAdd a SECURITY.md file to your project so someone who wants to message you about a vulnerability can do so without having to hunt around for contact details. Last year, Snyk published a State of Open Source Security report that found 79.5% of maintainers do not have a public disclosure policy. Those that did were considerably more likely to get notified privately about a vulnerability \u2013 73% of maintainers who had one had been notified, vs 21% of maintainers who hadn\u2019t published one one.\nStats from the State of Open Source Security 2017\nBug bounties\nSome companies run bug bounties to encourage the responsible disclosure of vulnerabilities. By offering a reward for finding and safely disclosing a vulnerability, it also reduces the enticement of exploiting a vulnerability over reporting it and getting a quick cash reward. Hackerone is a community of ethical hackers who pentest apps that have signed up for the scheme and get paid when they find a new vulnerability. Wordpress is one such participant, and you can see the long list of vulnerabilities that have been disclosed as part of that program.\nIf you don\u2019t have such a bounty, be prepared to get the odd vulnerability extortion email. Scott Helme, who founded securityheaders.com and report-uri.com, wrote a post about some of the requests he gets for a report about a critical vulnerability in exchange for money. \n\nOn one hand, I want to be as responsible as possible and if my users are at risk then I need to know and patch this issue to protect them. On the other hand this is such irresponsible and unethical behaviour that interacting with this person seems out of the question.\n\nA gift worth giving\nIt\u2019s time to brush the dust off those old gifts that we shared and forgot about. Practice good hygiene and run them through your favourite security tool \u2013 I\u2019m just a little biased towards Snyk, but as Katie mentioned, there\u2019s also npm audit if you use Node.js, and most source code managers like GitHub and GitLab have basic vulnerability alert capabilities.\nStats from the State of Open Source Security 2017\nMost importantly, patch or upgrade away those vulnerabilities away, and if you want to share that Christmas spirit, open fixes for your favourite open source projects, too.", "year": "2018", "author": "Anna Debenham", "author_slug": "annadebenham", "published": "2018-12-17T00:00:00+00:00", "url": "https://24ways.org/2018/its-beginning-to-look-a-lot-like-xssmas/", "topic": "code"} {"rowid": 251, "title": "The System, the Search, and the Food Bank", "contents": "Imagine a warehouse, half the length of a football field, with a looped conveyer belt down the center. \nOn the belt are plastic bins filled with assortments of shelf-stable food\u2014one 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 \u201cBottled Water\u201d or \u201cCereal\u201d or \u201cCandy.\u201d \nSuch 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.\nI could scarcely believe my good fortune of assignments. You want me to sort things? Into categories? For several hours? And you say there\u2019s an element of time pressure? Listen, is there some sort of permanent position I could be conscripted into.\nLook, I can\u2019t quite explain it: I just know that I love sorting, organizing, and classifying things\u2014groceries 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?\nThe opportunity to create meaning from nothing is at the core of my excitement, which is why I\u2019ve tried to build a career out of organizing digital content, and why I brought a frankly frightening level of enthusiasm to the food bank. \u201cI can\u2019t believe they\u2019re letting me do this,\u201d 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.\nThe 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\u2019s not just a nice-to-have that we spent our morning separating cookies from carrots\u2014it\u2019s a crucial step in the process. Organization makes the difference between chaos and sense, between randomness and usefulness, whether we\u2019re talking about donated groceries or\u2014there it is\u2014web content.\nThis 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.) \nIs X a Y? was the question at the heart of our food sorting\u2014but it\u2019s also at the heart of any information-seeking behavior. When we are organizing, or looking for, any kind of information, we are asking ourselves:\n\nWhat is the criteria that defines Y?\nDoes X meet that criteria?\n\nWe don\u2019t usually articulate it so concretely because it\u2019s 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\u2019t require much thought to place them in the Canned Soup box. Boxed broth, on the other hand, wasn\u2019t allowed, causing a small cognitive hiccup\u2014this X is NOT a Y\u2014that sometimes meant having to re-sort our boxes.\nOn the web, we\u2019re interested\u2014I would hope\u2014in 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\u2014Is 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?\nWe have a responsibility, therefore, to make information easy for our users to find, understand, and act on. This means\u2014well, this means a lot of things, and I\u2019ve got limited space here, so let\u2019s focus on these three lessons from the food bank:\n\n\nUse plain, familiar language. This advice seems to be given constantly, but that\u2019s because it\u2019s solid and it\u2019s 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\u2019s not that different from sites that use industry jargon, company lingo, acronyms (oh, yes, I\u2019ve seen it), or other internally focused language when trying to provide wayfinding for users. Choose words that your audience knows\u2014not only will they be more likely to spot what they\u2019re looking for on your site or app, but you\u2019ll turn up more often in search results.\n\n\nCreate consistency in all things. Missteps in consistency look like my earlier chicken broth example\u2014changing 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\u2014these 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.\n\nMake 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.\n\nThis 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\u2019t know every category label around the conveyer belt, nor what criteria each category warranted. \nThe system wasn\u2019t 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\u2019d ask staff members. We\u2019d ask more seasoned volunteers. We\u2019d ask each other. We\u2019d make guesses, and guess wrongly, and mess up the boxes, and correct our mistakes, and learn.\nThe 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.\nThe 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\u2014or, worse, misinform or hurt them. \nThis is why we must make choices that prioritize transparency, consistency, and familiarity. Our users want to know if X is a Y\u2014well-sorted content can give them the answer.", "year": "2018", "author": "Lisa Maria Martin", "author_slug": "lisamariamartin", "published": "2018-12-16T00:00:00+00:00", "url": "https://24ways.org/2018/the-system-the-search-and-the-food-bank/", "topic": "content"} {"rowid": 259, "title": "Designing Your Future", "contents": "I\u2019ve had the pleasure of working for a variety of clients \u2013 both large and small \u2013 over the last 25 years. In addition to my work as a design consultant, I\u2019ve worked as an educator, leading the Interaction Design team at Belfast School of Art, for the last 15 years.\nIn July, 2018 \u2013 frustrated with formal education, not least the ever-present hand of \u2018austerity\u2019 that has ravaged universities in the UK for almost a decade \u2013 I formally reduced my teaching commitment, moving from a full-time role to a half-time role.\nMaking the move from a (healthy!) monthly salary towards a position as a freelance consultant is not without its challenges: one month your salary\u2019s arriving in your bank account (and promptly disappearing to pay all of your bills); the next month, that salary\u2019s been drastically reduced. That can be a shock to the system.\nIn this article, I\u2019ll explore the challenges encountered when taking a life-changing leap of faith. To help you confront \u2018the fear\u2019 \u2013 the nervousness, the sleepless nights and the ever-present worry about paying the bills \u2013 I\u2019ll provide a set of tools that will enable you to take a leap of faith and pursue what deep down drives you.\nIn short: I\u2019ll bare my soul and share everything I\u2019m currently working on to \u2013 once and for all \u2013 make a final bid for freedom.\nThis isn\u2019t easy. I\u2019m sharing my innermost hopes and aspirations, and I might open myself up to ridicule, but I believe that by doing so, I might help others, by providing them with tools to help them make their own leap of faith.\nThe power of visualisation\nAs designers we have skills that we use day in, day out to imagine future possibilities, which we then give form. In our day-to-day work, we use those abilities to design products and services, but I also believe we can use those skills to design something every bit as important: ourselves.\nIn this article I\u2019ll explore three tools that you can use to design your future:\n\nProduct DNA\nArtefacts From the Future\nTomorrow Clients\n\nEach of these tools is designed to help you visualise your future. By giving that future form, and providing a concrete goal to aim for, you put the pieces in place to make that future a reality.\nBrian Eno \u2013 the noted musician, producer and thinker \u2013 states, \u201cHumans are capable of a unique trick: creating realities by first imagining them, by experiencing them in their minds.\u201d Eno helpfully provides a powerful example:\n\nWhen Martin Luther King said, \u201cI have a dream,\u201d he was inviting others to dream that dream with him. Once a dream becomes shared in that way, current reality gets measured against it and then modified towards it.\nThe dream becomes an invisible force which pulls us forward. By this process it starts to come true. The act of imagining something makes it real.\n\nWhen you imagine your future \u2013 designing an alternate, imagined reality in your mind \u2013 you begin the process of making that future real.\nProduct DNA\nThe first tool, which I use regularly \u2013 for myself and for client work \u2013 is a tool called Product DNA. The intention of this tool is to identify beacons from which you can learn, helping you to visualise your future.\nWe all have heroes \u2013 individuals or organisations \u2013 that we look up to. Ask yourself, \u201cWho are your heroes?\u201d If you had to pick three, who would they be and what could you learn from them? (You probably have more than three, but distilling down to three is an exercise in itself.)\nEarlier this year, when I was putting the pieces in place for a change in career direction, I started with my heroes. I chose three individuals that inspired me:\n\nAlan Moore: the author of \u2018Do Design: Why Beauty is Key to Everything\u2019;\nMark Shayler: the founder of Ape, a strategic consultancy; and\nSeth Godin: a writer and educator I\u2019ve admired and followed for many years.\n\nLooking at each of these individuals, I \u2018borrowed\u2019 a little DNA from each of them. That DNA helped me to paint a picture of the kind of work I wanted to do and the direction I wanted to travel.\n\nMoore\u2019s book - \u2018Do Design\u2019 \u2013 had a powerful influence on me, but the primary inspiration I drew from him was the sense of gravitas he conveyed in his work. Moore\u2019s mission is an important one and he conveys that with an appropriate weight of expression.\nShayler\u2019s work appealed to me for its focus on equipping big businesses with a startup mindset. As he puts it: \u201cI believe that you can do the things that you do better.\u201d That sense \u2013 of helping others to be their best selves \u2013 appealed to me.\nFinally, the words Godin uses to describe himself \u2013 \u201cAn Author, Entrepreneur and Most of All, a Teacher\u201d \u2013 resonated with me. The way he positions himself, as, \u201cmost of all, a teacher,\u201d gave me the belief I needed that I could work as an educator, but beyond the ivory tower of academia.\nI\u2019ve been exploring each of these individuals in depth, learning from them and applying what I learn to my practice. They don\u2019t all know it, but they are all \u2018mentors from afar\u2019.\nIn a moment of serendipity \u2013 and largely, I believe, because I\u2019d used this tool to explore his work \u2013 I was recently invited by Alan Moore to help him develop a leadership programme built around his book.\nThe key lesson here is that not only has this exercise helped me to design my future and give it tangible form, it\u2019s also led to a fantastic opportunity to work with Alan Moore, a thinker who I respect greatly.\nArtefacts From the Future\nThe second tool, which I also use regularly, is a tool called \u2018Artefacts From the Future\u2019. These artefacts \u2013 especially when designed as \u2018finished\u2019 pieces \u2013 are useful for creating provocations to help you see the future more clearly.\n\u2018Artefacts From the Future\u2019 can take many forms: they might be imagined magazine articles, news items, or other manifestations of success. By imagining these end points and giving them form, you clarify your goals, establishing something concrete to aim for.\nEarlier this year I revisited this tool to create a provocation for myself. I\u2019d just finished Alla Kholmatova\u2019s excellent book on \u2018Design Systems\u2019, which I would recommend highly. The book wasn\u2019t just filled with valuable insights, it was also beautifully designed.\nOnce I\u2019d finished reading Kholmatova\u2019s book, I started thinking: \u201cPerhaps it\u2019s time for me to write a new book?\u201d Using the magic of \u2018Inspect Element\u2019, I created a fictitious page for a new book I wanted to write: \u2018Designing Delightful Experiences\u2019.\nI wrote a description for the book, considering how I\u2019d pitch it.\n\nThis imagined page was just what I needed to paint a picture in my mind of a possible new book. I contacted the team at Smashing Magazine and pitched the idea to them. I\u2019m happy to say that I\u2019m now working on that book, which is due to be published in 2019.\nWithout this fictional promotional page from the future, the book would have remained as an idea \u2013 loosely defined \u2013 rolling around my mind. By spending some time, turning that idea into something \u2018real\u2019, I had everything I needed to tell the story of the book, sharing it with the publishing team at Smashing Magazine.\nOf course, they could have politely informed me that they weren\u2019t interested, but I\u2019d have lost nothing \u2013 truly \u2013 in the process.\nAs designers, creating these imaginary \u2018Artefacts From the Future\u2019 is firmly within our grasp. All we need to do is let go a little and allow our imaginations to wander.\nIn my experience, working with clients and \u2013 to a lesser extent, students \u2013 it\u2019s the \u2018letting go\u2019 part that\u2019s the hard part. It can be difficult to let down your guard and share a weighty goal, but I\u2019d encourage you to do so. At the end of the day, you have nothing to lose.\nThe key lesson here is that your \u2018Artefacts From the Future\u2019 will focus your mind. They\u2019ll transform your unformed ideas into \u2018tangible evidence\u2019 of future possibilities, which you can use as discussion points and provocations, helping you to shape your future reality.\nTomorrow Clients\nThe third tool, which I developed more recently, is a tool called \u2018Tomorrow Clients\u2019. This tool is designed to help you identify a list of clients that you aspire to work with.\nThe goal is to pinpoint who you would like to work with \u2013 in an ideal world \u2013 and define how you\u2019d position yourself to win them over. Again, this involves \u2018letting go\u2019 and allowing your mind to imagine the possibilities, asking, \u201cWhat if\u2026?\u201d\nBefore I embarked upon the design of my new website, I put together a \u2018soul searching\u2019 document that acted as a focal point for my thinking. I contacted a number of designers for a second opinion to see if my thinking was sound.\nOne of my graduates \u2013 Chris Armstrong, the founder of Niice \u2013 replied with the following: \u201cMight it be useful to consider five to ten companies you\u2019d love to work for, and consider how you\u2019d pitch yourself to them?\u201d\nThis was just the provocation I needed. To add a little focus, I reduced the list to three, asking: \u201cWho would my top three clients be?\u201d\n\nBy distilling the list down I focused on who I\u2019d like to work for and how I\u2019d position myself to entice them to work with me. My list included: IDEO, Adobe and IBM. All are companies I admire and I believed each would be interesting to work for.\nThis exercise might \u2013 on the surface \u2013 appear a little like indulging in fantasy, but I believe it helps you to clarify exactly what it is you are good at and, just as importantly, put that in to words.\nFor each company, I wrote a short pitch outlining why I admired them and what I thought I could add to their already existing skillset.\nFocusing first on Adobe, I suggested establishing an emphasis on educational resources, designed to help those using Adobe\u2019s creative tools to get the most out of them.\nA few weeks ago, I signed a contract with the team working on Adobe XD to create a series of \u2018capsule courses\u2019, focused on UX design. The first of these courses \u2013 exploring UI design \u2013 will be out in 2019.\nI believe that Armstrong\u2019s provocation \u2013 asking me to shift my focus from clients I have worked for in the past to clients I aspire to work for in the future \u2013 made all the difference.\nThe key lesson here is that this exercise encouraged me to raise the bar and look to the future, not the past. In short, it enabled me to proactively design my future.\nIn closing\u2026\nI hope these three tools will prove a welcome addition to your toolset. I use them when working with clients, I also use them when working with myself.\nI passionately believe that you can design your future. I also firmly believe that you\u2019re more likely to make that future a reality if you put some thought into defining what it looks like.\nAs I say to my students and the clients I work with: It\u2019s not enough to want to be a success, the word \u2018success\u2019 is too vague to be a destination. A far better approach is to define exactly what success looks like.\nThe secret is to visualise your future in as much detail as possible. With that future vision in hand as a map, you give yourself something tangible to translate into a reality.", "year": "2018", "author": "Christopher Murphy", "author_slug": "christophermurphy", "published": "2018-12-15T00:00:00+00:00", "url": "https://24ways.org/2018/designing-your-future/", "topic": "process"} {"rowid": 243, "title": "Researching a Property in the CSS Specifications", "contents": "I frequently joke that I\u2019m \u201creading the specs so you don\u2019t have to\u201d, as I unpack some detail of a CSS spec in a post on my blog, some documentation for MDN, or an article on Smashing Magazine. However waiting for someone like me to write an article about something is a pretty slow way to get the information you need. Sometimes people like me get things wrong, or specifications change after we write a tutorial. \nWhat if you could just look it up yourself? That\u2019s what you get when you learn to read the CSS specifications, and in this article my aim is to give you the basic details you need to grab quick information about any CSS property detailed in the CSS specs.\nWhere are the CSS Specifications?\nThe easiest way to see all of the CSS specs is to take a look at the Current Work page in the CSS section of the W3C Website. Here you can see all of the specifications listed, the level they are at and their status. There is also a link to the specification from this page. I explained CSS Levels in my article Why there is no CSS 4.\nWho are the specifications for?\nCSS specifications are for everyone who uses CSS. You might be a browser engineer - referred to as an implementor - needing to know how to implement a feature, or a web developer - referred to as an author - wanting to know how to use the feature. The fact that both parties are looking at the same document hopefully means that what the browser displays is what the web developer expected.\nWhich version of a spec should I look at?\nThere are a couple of places you might want to look. Each published spec will have the latest published version, which will have TR in the URL and can be accessed without a date (which is always the newest version) or at a date, which will be the date of that publication. If I\u2019m referring to a particular Working Draft in an article I\u2019ll typically link to the dated version. That way if the information changes it is possible for someone to see where I got the information from at the time of writing.\nIf you want the very latest additions and changes to the spec, then the Editor\u2019s Draft is the place to look. This is the version of the spec that the editors are committing changes to. If I make a change to the Multicol spec and push it to GitHub, within a few minutes that will be live in the Editor\u2019s Draft. So it is possible there are errors, bits of text that we are still working out and so on. The Editor\u2019s Draft however is definitely the place to look if you are wanting to raise an issue on a spec, as it may be that the issue you are about to raise is already fixed.\nIf you are especially keen on seeing updates to specifications keep an eye on https://drafts.csswg.org/ as this is a list of drafts, along with the date they were last updated.\nHow to approach a spec\nThe first thing to understand is that most CSS Specifications start with the most straightforward information, and get progressively further into the weeds. For an author the initial examples and explanations are likely to be of interest, and then the property definitions and examples. Therefore, if you are looking at a vast spec, know that you probably won\u2019t need to read all the way to the bottom, or read every section in detail.\nThe second thing that is useful to know about modern CSS specifications is how modularized they are. It really never is a case of finding everything you need in a single document. If we tried to do that, there would be a lot of repetition and likely inconsistency between specs. There are some key specifications that many other specifications draw on, such as:\n\nValues and Units\nIntrinsic and Extrinsic Sizing\nBox Alignment\n\nWhen something is defined in another specification the spec you are reading will link to it, so it is worth opening that other spec in a new tab in order that you can refer back to it as you explore.\nResearching your property\nAs an example we will take a look at the property grid-auto-rows, this property defines row tracks in the implicit grid when using CSS Grid Layout. The first thing you will need to do is find out which specification defines this property.\nYou might already know which spec the property is part of, and therefore you could go directly to the spec and search using your browser or look in the navigation for the spec to find it. Alternatively, you could take a look at the CSS Property Index, which is an automatically generated list of CSS Properties.\nClicking on a property will take you to the TR version of the spec, the latest published draft, and the definition of that property in it. This definition begins with a panel detailing the syntax of this property. For grid-auto-rows, you can see that it is listed along with grid-auto-columns as these two properties are essentially identical. They take the same values and work in the same way, one for rows and the other for columns.\nValue\nFor value we can see that the property accepts a value . The next thing to do is to find out what that actually means, clicking will take you to where it is defined in the Grid spec.\nThe value is defined as accepting various values:\n\n\nminmax( , )\nfit-content( \n\nWe need to head down the rabbit hole to find out what each of these mean. From here we essentially go down line by line until we have unpacked the value of track-size.\n is defined just below as:\n\n\n\nmin-content\nmax-content\nauto\n\nSo these are all things that would be valid to use as a value for grid-auto-rows.\nThe first value of is something you will see in many specifications as a value. It means that you can use a length unit - for example px or em - or a percentage. Some properties only accept a in which case you know that you cannot use a percentage as the value. This means that you could have grid-auto-rows with any of the following values.\ngrid-auto-rows: 100px;\ngrid-auto-rows: 1em;\ngrid-auto-rows: 30%;\nWhen using percentages, it is important to know what it is a percentage of. As a percentage has to resolve from something. There is text in the spec which explains how column and row percentages work.\n\n\u201c values are relative to the inline size of the grid container in column grid tracks, and the block size of the grid container in row grid tracks.\u201d\n\nThis means that in a horizontal writing mode such as when using English, a percentage when used as a track-size in grid-auto-columns would be a percentage of the width of the grid, and a percentage in grid-auto-rows a percentage of the height of the grid.\nThe second value of is also defined here, as \u201cA non-negative dimension with the unit fr specifying the track\u2019s flex factor.\u201d This is the fr unit, and the spec links to a fuller definition of fr as this unit is only used in Grid Layout so it is therefore defined in the grid spec. We now know that a valid value would be:\ngrid-auto-rows: 1fr;\nThere is some useful information about the fr unit in this part of the spec. It is noted that the fr unit has an automatic minimum. This means that 1fr is really minmax(auto, 1fr). This is why having a number of tracks all at 1fr does not mean that all are equal sized, as a larger item in any of the tracks would have a large auto size and therefore would be larger after spare space had been distributed.\nWe then have min-content and max-content. These keywords can be used for track sizing and the specification defines what they mean in the context of sizing a track, representing the min and max-sizing contributions of the grid tracks. You will see that there are various terms linked in the definition, so if you do not know what these mean you can follow them to find out.\nFor example the spec links max-content contribution to the CSS Intrinsic and Extrinsic Sizing specification. This is one of those specs which is drawn on by many other specifications. If we follow that link we can read the definition there and follow further links to understand what each term means. The more that you read specifications the more these terms will become familiar to you. Just like learning a foreign language, at first you feel like you have to look up every little thing. After a while you remember the vocabulary.\nWe can now add min-content and max-content to our available values.\ngrid-auto-rows: min-content;\ngrid-auto-rows: max-content;\nThe final item in our list is auto. If you are familiar with using Grid Layout, then you are probably aware that an auto sized track for will grow to fit the content used. There is an interesting note here in the spec detailing that auto sized rows will stretch to fill the grid container if there is extra space and align-content or justify-content have a value of stretch. As stretch is the default value, that means these tracks stretch by default. Tracks using other types of length will not behave like this.\ngrid-auto-rows: auto;\nSo, this was the list for , the next possible value is minmax( , ). So this is telling us that we can use minmax() as a value, the final (max) value will be and we have already unpacked all of the allowable values there. The first value (min) is detailed as an . If we look at the values for this, we discover that they are the same as , minus the value:\n\n\nmin-content\nmax-content\nauto\n\nWe already know what all of these do, so we can add possible minmax() values to our list of values for .\ngrid-auto-rows: minmax(100px, 200px);\ngrid-auto-rows: minmax(20%, 1fr);\ngrid-auto-rows: minmax(1em, auto);\ngrid-auto-rows: minmax(min-content, max-content);\nFinally we can use fit-content( . We can see that fit-content takes a value of which we already know to be either a length unit, or a percentage. The spec details how fit-content is worked out, and it essentially allows a track which acts as if you had used the max-content keyword, however the track stops growing when it hits the length passed to it.\ngrid-auto-rows: fit-content(200px);\ngrid-auto-rows: fit-content(20%);\nThose are all of our possible values, and to round things off, check again at the initial value, you can see it has a little + sign next to it, click that and you will be taken to the CSS Values and Units module to find that, \u201cA plus (+) indicates that the preceding type, word, or group occurs one or more times.\u201d This means that we can pass a single track size to grid-auto-rows or multiple track sizes as a space separated list. Below the box is an explanation of what happens if you pass in more than one track size:\n\n\u201cIf multiple track sizes are given, the pattern is repeated as necessary to find the size of the implicit tracks. The first implicit grid track after the explicit grid receives the first specified size, and so on forwards; and the last implicit grid track before the explicit grid receives the last specified size, and so on backwards.\u201d\n\nTherefore with the following CSS, if five implicit rows were needed they would be as follows:\n\n100px\n1fr\nauto\n100px\n1fr\n\n.grid {\n display: grid;\n grid-auto-rows: 100px 1fr auto;\n}\nInitial\nWe can now move to the next line in the box, and you\u2019ll be glad to know that it isn\u2019t going to require as much unpacking! This simply defines the initial value for grid-auto-rows. If you do not specify anything, created rows will be auto sized. All CSS properties have an initial value that they will use if they are invoked as part of the usage of the specification they are in, but you do not set a value for them. In the case of grid-auto-rows it is used whenever rows are created in the implicit grid, so it needs to have a value to be used even if you do not set one.\nApplies to\nThis line tells us what this property is used for. Some properties are used in multiple places. For example if you look at the definition for justify-content in the Box Alignment specification you can see it is used in multicol containers, flex containers, and grid containers. In our case the property only applies for grid containers.\nInherited\nThis tells us if the property can be inherited from a parent element if it is not set. In the case of grid-auto-rows it is not inherited. A property such as color is inherited, so you do not need to set it on each element.\nPercentages\nAre percentages allowed for this property, and if so how are they calculated. In this case we are referred to the definition for grid-template-columns and grid-template-rows where we discover that the percentage is from the corresponding dimension of the content area.\nMedia\nThis defines the media group that the property belongs to. In this case visual.\nComputed Value\nThis details how the value is resolved. The grid-auto-rows property again refers to track sizing as defined for grid-template-columns and grid-template-rows, which tells us the computed value is as specified with lengths made absolute.\nCanonical Order\nIf you have a property\u2013generally a shorthand property\u2013which takes multiple values in a set order, then those values need to be serialized in the order detailed in the grammar for that property. In general you don\u2019t need to worry about this value in the table.\nAnimation Type\nThis details whether the property can be animated, and if so what type of animation. This is useful if you are trying to animate something and not getting the result that you expect. Note that just because something is listed in the spec as animatable does not mean that browsers will have implemented animation for that property yet!\nThat\u2019s (mostly) it!\nSometimes the property will have additional examples - there is one underneath the table for grid-auto-rows. These are worth looking at as they will highlight usage of the property that the spec editor has felt could use an example. There may also be some additional text explaining anythign specific to this property.\nIn selecting grid-auto-rows I chose a fairly complex property in terms of the work we needed to do to unpack the value. Many properties are far simpler than this. However ultimately, even when you come across a complex value, it really is just a case of stepping through the definitions until you come to the bottom of the rabbit hole.\nBeing able to work out what is valid for each property is incredibly useful. It means you don\u2019t waste time trying to use a value that doesn\u2019t work for that property. You also may find that there are values you weren\u2019t aware of, that solve problems for you.\nFurther reading\nSpecifications are not designed to be user manuals, and while they often contain examples, these are pretty terse as they need to be clear to demonstrate their particular point. The manual for the Web Platform is MDN Web Docs. Pairing reading a specification with the examples and information on an MDN property page such as the one for grid-auto-rows is a really great way to ensure that you have all the information and practical usage examples you might need.\nYou may also find useful:\n\nValue Definition Syntax on MDN.\nThe MDN Glossary defines many common terms.\nUnderstanding the CSS Property Value Syntax goes into more detail in terms of reading the syntax.\nHow to read W3C Specs - from 2001 but still relevant.\n\nI hope this article has gone some way to demystify CSS specifications for you. Even if the specifications are not your preferred first stop to learn about new CSS, being able to go directly to the source and avoid having your understanding filtered by someone else, can be very useful indeed.", "year": "2018", "author": "Rachel Andrew", "author_slug": "rachelandrew", "published": "2018-12-14T00:00:00+00:00", "url": "https://24ways.org/2018/researching-a-property-in-the-css-specifications/", "topic": "code"} {"rowid": 255, "title": "Inclusive Considerations When Restyling Form Controls", "contents": "I would like to begin by saying 2018 was the year that we, as developers, visual designers, browser implementers, and inclusive design and experience specialists rallied together and achieved a long-sought goal: We now have the ability to fully style form controls, across all modern browsers, while retaining their ease of declaration, native functionality and accessibility.\nI would like to begin by saying all these things. However, they\u2019re not true. I think we spent the year debating about what file extension CSS should be written in, or something. Or was that last year? Maybe I\u2019m thinking of next year.\nReturning to reality, styling form controls is more tricky and time consuming these days rather than flat out \u201chard\u201d. In fact, depending on the length of the styling-leash a particular browser provides, there are controls you can style quite a bit. As for browsers with shorter leashes, there are other options to force their controls closer to the visual design you\u2019re tasked to match.\nHowever, when striving for custom styled controls, one must be careful not to forget about the inherent functionality and accessibility that many provide. People expect and deserve the products and services they use and pay for to work for them. If these services are visually pleasing, but only function for those who fit the handful of personas they\u2019ve been designed for, then we\u2019ve potentially deprived many people the experiences they deserve.\nQuick level setting\nGetting down to brass tacks, when creating custom styled form controls that should retain their expected semantics and functionality, we have to consider the following:\n\nMany form elements can be styled directly through standard and browser specific selectors, as well as through some clever styling of markup patterns. We should leverage these native options before reinventing any wheels.\nIt is important to preserve the underlying semantics of interactive controls. We must not unintentionally exclude people who use assistive technologies (ATs) that rely on these semantics. \nMake sure you test what you create. There is a lot of underlying complexity to form controls which may not be immediately apparent if they\u2019re judged solely by their visual presentation in a single browser, or with limited AT testing.\n\nVisually resetting and restyling form controls\nOver the course of 2018, I worked on a project where I tested and reported on the accessibility impact of styling various form controls. In conducting my research, I reviewed many of the form controls available in HTML, testing to see how malleable they were to direct styling from standardized CSS selectors. \nAs I expected, controls such as the various text fields could be restyled rather easily. However, other controls like radio buttons and checkboxes, or sub-elements of special text fields like date, search, and number spinners were resistant to standard-based styling. These particular controls and their sub-elements required specific pseudo-elements to reset and allow for restyling of some of their default presentation.\nSee the Pen form control styling comparisons by Scott (@scottohara) on CodePen.\nhttps://codepen.io/scottohara/pen/gZOrZm/\nOver the years, the ability to directly style form controls has been something many people have clamored for. However, one should realize the benefits of being able to restyle some of these controls may involve more effort than originally anticipated. \nIf you want to restyle a control from the ground up, then you must also recreate any :active, :focus, and :hover states for the control\u2014all those things that were previously taken care of by browsers. Not only that, but anything you restyle should also work with Windows High Contrast mode, styling for dark mode, and other OS-level settings that browser respect without you even realizing. \n\n You ever try playing with the accessibility settings of your display on macOS, or similar Windows setting?\n \nIt is also worth mentioning that any browser prefixed pseudo-elements are not standardized CSS selectors. As MDN mentions at the top of their pages documenting these pseudo-elements:\n\nNon-standard\nThis feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.\n\nWhile this may be a deterrent for some, it\u2019s my opinion the risks are often only skin-deep. By which I mean if a non-standard selector does change, the control may look a bit quirky, but likely won\u2019t cease to function. A bug report which requires a CSS selector change can be an easy JIRA ticket to close, after all.\nCan\u2019t make it? Fake it.\nInternet Explorer 11 (IE11) is still neck-and-neck with other browsers in vying for the number 2 spot in desktop browser share. Due to IE not recognizing vendor-prefixed appearance properties, some essential controls like checkboxes won\u2019t render as intended. \nAdditionally, some controls like select boxes, file uploads, and sub-elements of date fields (calendar popups) cannot be modified by just relying on styling their HTML selectors alone. This means that unless your company designs and develops with a progressive enhancement, or graceful degradation mindset, you\u2019ll need to take a different approach in styling.\nGetting clever with markup and CSS\nThe following CodePen demonstrates how we can create a custom checkbox markup pattern. By mindfully utilizing CSS sibling selectors and positioning of the native control, we can create custom visual styling while also retaining the functionality and accessibility expectations of a native checkbox.\nSee the Pen Accessible Styled Native Checkbox by Scott (@scottohara) on CodePen.\nhttps://codepen.io/scottohara/pen/RqEayN/\nCustomizing checkboxes by visually hiding the input and styling well-placed markup with sibling selectors may seem old hat to some. However, many variations of these patterns do not take into account how their method of visually hiding the checkboxes can create discovery issues for certain screen reader navigation methods. For instance, if someone is using a mobile device and exploring by touch, how will they be able to drag their finger over an input that has been reduced to a single pixel, or positioned off screen?\nAs we move away from the simplicity of declaring a single HTML element and using clever CSS and markup patterns to create restyled form controls, we increase the need for additional testing to ensure no expected behaviors are lost. In other words, what should work in theory may not work in practice when you introduce the various different ways people may engage with a form control. It\u2019s worth remembering: what might be typical interactions for ourselves may be problematic if not impossible for others.\nLimitations to cleverness\nCreative coding will allow us to apply more consistent custom styles to some of the more problematic form controls. There will be a varied amount of custom markup, CSS, and sometimes JavaScript that will be needed to preserve the control\u2019s inherent usability and accessibility for each control we take this approach to.\nHowever, this method of restyling still doesn\u2019t solve for the lack of feature parity across different browsers. Nor is it a means to account for controls which don\u2019t have a native HTML element equivalent, such as a switch or multi-thumb range slider? Maybe there\u2019s a control that calls for a visual design or proposed user experience that would require too much fighting with a native control\u2019s behavior to be worth the level of effort to implement. Here\u2019s where we need to take another approach.\nUsing ARIA when appropriate\nSometimes we have no other option than to roll up our sleeves and start building custom form controls from scratch. Fair warning though: just because we\u2019re not leveraging a native HTML control as our foundation, it doesn\u2019t mean we have carte blanche to throw semantics out the window. Enter Accessible Rich Internet Applications (ARIA).\nARIA is a set of attributes that can modify existing elements, or extend HTML to include roles, properties and states that aren\u2019t native to the language. While divs and spans have no meaningful semantic information for us to leverage, with help from the ARIA specification and ARIA Authoring Practices we can incorporate these elements to help create the UI that we need while still following the first rule of Using ARIA:\n\nIf you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.\n\nBy using these documents as guidelines, and testing our custom controls with people of various abilities, we can do our best to make sure a custom control performs as expected for as many people as possible.\nExceptions to the rule\nOne example of a control that allows for an exception to the first rule of Using ARIA would be a switch control.\nSwitches and checkboxes are similar components, in that they have both on/checked and off/unchecked states. However, checkboxes are often expected within the context of forms, or used to filter search queries on e-commerce sites. Switches are typically used to instantly enable or deactivate a particular setting at a component or app-based level, as this is their behavior in the native mobile apps in which they were popularized.\nWhile a switch control could be created by visually restyling a checkbox, this does not automatically mean that the underlying semantics and functionality will match the visual representation of the control. For example, the following CodePen restyles checkboxes to look like a switch control, but the semantics of the checkboxes remain which communicate a different way of interacting with the control than what you might expect from a native switch control.\nSee the Pen Switch Boxes - custom styled checkboxes posing as switches by Scott (@scottohara) on CodePen.\nhttps://codepen.io/scottohara/pen/XyvoeE/\nBy adding a role=\"switch\" to these checkboxes, we can repurpose the inherent checked/unchecked states of the native control, it\u2019s inherent ability to be focused by Tab key, and Space key to toggle state.\nBut while this is a valid approach to take in building a switch, how does this actually match up to reality?\nDoes it pass the test(s)?\nWhether deconstructing form controls to fully restyle them, or leveraging them and other HTML elements as a base to expand on, or create, a non-native form control, building it is just the start. We must test that what we\u2019ve restyled or rebuilt works the way people expect it to, if not better.\nWhat we must do here is run a gamut of comparative tests to document the functionality and usability of native form controls. For example:\n\n\nIs the control implemented in all supported browsers?\nIf not: where are the gaps? Will it be necessary to implement a custom solution for the situations that degrade to a standard text field? \nIf so: is each browser\u2019s implementation a good user experience? Is there room for improvement that can be tested against the native baseline? \n\n\nTest with multiple input devices.\nWhere the control is implemented, what is the quality of the user experience when using different input devices, such as mouse, touchscreen, keyboard, speech recognition or switch device, to name a few. \nYou\u2019ll find some HTML5 controls (like date pickers and number spinners) have additional UI elements that may not be announced to AT, or even allow keyboard accessibility. Often these controls can be adjusted by other means, such as text entry, or using arrow keys to increase or decrease values. If restyling or recreating a custom version of a control like these, it may make sense to maintain these native experiences as well.\n\n\nHow well does the control take to custom styles?\nIf a control can be styled enough to not need to be rebuilt from scratch, that\u2019s great! But make sure that there are no adverse affects on the accessibility of it. For instance, range sliders can be restyled and maintain their functionality and accessibility. However, elements like progress bars can be negatively affected by direct styling. \nAlways test with different browser and AT pairings to ensure nothing is lost when controls are restyled. \n\n\nDo specifications match reality?\nIf recreating controls to get around native limitations, such as the inability to style the options of a select element, or requiring a Switch control which is not native to HTML, do your solutions match user expectations? \nFor instance, selects have unique picker interfaces on touch devices. And switches have varied levels of support for different browser and screen reader pairings. Test with real people, and check your analytics. If these experiences don\u2019t match people\u2019s expectations, then maybe another solution is in order? \n\n\nWrapping up\nWhile styling form controls is definitely easier than it\u2019s ever been, that doesn\u2019t mean that it\u2019s at all simple, nor will it likely ever be. The level of difficulty you\u2019re going to face is going to depend entirely on what it is you\u2019re hoping to style, add-on to, or recreate. And even if you build your custom control exactly to specification, you\u2019ll still be reliant on browsers and assistive technologies being able to fully understand the component they\u2019ve been presented.\nForms and their controls are an incredibly important part of what we need the Internet for. Paying bills, scheduling appointments, ordering groceries, renewing your license or even ordering gifts for the holidays. These are all important tasks that people should be able to complete with as little effort as possible. Especially since for some, completing these tasks online might be their only option.\n2018 didn\u2019t end up being the year we got full customization of form controls sorted out. But that\u2019s OK. If we can continue to mindfully work with what we have, and instead challenge ourselves to follow inclusive design principles, well thought out Form Design Patterns, and solve problems with an accessibility first approach, we may come to realize that we can get along just fine without fully branded drop downs. \nAnd hey. There\u2019s always next year, right?", "year": "2018", "author": "Scott O'Hara", "author_slug": "scottohara", "published": "2018-12-13T00:00:00+00:00", "url": "https://24ways.org/2018/inclusive-considerations-when-restyling-form-controls/", "topic": "code"} {"rowid": 257, "title": "The (Switch)-Case for State Machines in User Interfaces", "contents": "You\u2019re tasked with creating a login form. Email, password, submit button, done.\n\u201cThis will be easy,\u201d you think to yourself.\nLogin form by Selecto\nYou\u2019ve made similar forms many times in the past; it\u2019s essentially muscle memory at this point. You\u2019re working closely with a designer, who gives you a beautiful, detailed mockup of a login form. Sure, you\u2019ll have to translate the pixels to meaningful, responsive CSS values, but that\u2019s the least of your problems.\nAs you\u2019re writing up the HTML structure and CSS layout and styles for this form, you realize that you don\u2019t know what the successful \u201clogged in\u201d page looks like. You remind the designer, who readily gives it to you. But then you start thinking more and more about how the login form is supposed to work.\n\nWhat if login fails? Where do those errors show up?\nShould we show errors differently if the user forgot to enter their email, or password, or both?\nOr should the submit button be disabled?\nShould we validate the email field?\nWhen should we show validation errors \u2013 as they\u2019re typing their email, or when they move to the password field, or when they click submit? (Note: many, many login forms are guilty of this.)\nWhen should the errors disappear?\nWhat do we show during the login process? Some loading spinner?\nWhat if loading takes too long, or a server error occurs?\n\nMany more questions come up, and you (and your designer) are understandably frustrated. The lack of upfront specification opens the door to scope creep, which readily finds itself at home in all the unexplored edge cases.\nModeling Behavior\nDescribing all the possible user flows and business logic of an application can become tricky. Ironically, user stories might not tell the whole story \u2013 they often leave out potential edge-cases or small yet important bits of information.\nHowever, one important (and very old) mathematical model of computation can be used for describing the behavior and all possible states of a user interface: the finite state machine.\nThe general idea, as it applies to user interfaces, is that all of our applications can be described (at some level of abstraction) as being in one, and only one, of a finite number of states at any given time. For example, we can describe our login form above in these states:\n\nstart - not submitted yet\nloading - submitted and logging in\nsuccess - successfully logged in\nerror - login failed\n\nAdditionally, we can describe an application as accepting a finite number of events \u2013 that is, all the possible events that can be \u201csent\u201d to the application, either from the user or some other external entity:\n\nSUBMIT - pressing the submit button\nRESOLVE - the server responds, indicating that login is successful\nREJECT - the server responds, indicating that login failed\n\nThen, we can combine these states and events to describe the transitions between them. That is, when the application is in one state, an an event occurs, we can specify what the next state should be:\n\nFrom the start state, when the SUBMIT event occurs, the app should be in the loading state.\nFrom the loading state, when the RESOLVE event occurs, login succeeded and the app should be in the success state.\nIf login fails from the loading state (i.e., when the REJECT event occurs), the app should be in the error state.\nFrom the error state, the user should be able to retry login: when the SUBMIT event occurs here, the app should go to the loading state.\nOtherwise, if any other event occurs, don\u2019t do anything and stay in the same state.\n\nThat\u2019s a pretty thorough description, similar to a user story! It\u2019s also a bit more symbolic than a user story (e.g., \u201cwhen the SUBMIT event occurs\u201d instead of \u201cwhen the user presses the submit button\u201d), and that\u2019s for a reason. By representing states, events, and transitions symbolically, we can visualize what this state machine looks like:\n\nEvery state is represented by a box, and every event is connected to a transition arrow that connects two states. This makes it intuitive to follow the flow and understand what the next state should be given the current state and an event.\nFrom Visuals to Code\nDrawing a state machine doesn\u2019t require any special software; in fact, using paper and pencil (in case anything changes!) does the job quite nicely. However, one common problem is handoff: it doesn\u2019t matter how detailed a user story or how well-designed a visualization is, it eventually has to be coded in order for it to become part of a real application.\nWith the state machine model described above, the same visual description can be mapped directly to code. Traditionally, and as the title suggests, this is done using switch/case statements:\nfunction loginMachine(state, event) {\n switch (state) {\n case 'start':\n if (event === 'SUBMIT') {\n return 'loading';\n }\n break;\n case 'loading':\n if (event === 'RESOLVE') {\n return 'success';\n } else if (event === 'REJECT') {\n return 'error';\n }\n break;\n case 'success':\n // Accept no further events\n break;\n case 'error':\n if (event === 'SUBMIT') {\n return 'loading';\n }\n break;\n default:\n // This should never occur\n return undefined;\n }\n}\n\nconsole.log(loginMachine('start', 'SUBMIT'));\n// => 'loading'\nThis is fine (I suppose) but personally, I find it much easier to use objects:\nconst loginMachine = {\n initial: \"start\",\n states: {\n start: {\n on: { SUBMIT: 'loading' }\n },\n loading: {\n on: {\n REJECT: 'error',\n RESOLVE: 'success'\n }\n },\n error: {\n on: {\n SUBMIT: 'loading'\n }\n },\n success: {}\n }\n};\n\nfunction transition(state, event) {\n return machine\n .states[state] // Look up the state\n .on[event] // Look up the next state based on the event\n || state; // If not found, return the current state\n}\n\nconsole.log(transition('start', 'SUBMIT'));\nAs you might have noticed, the loginMachine is a plain JS object, and can be written in JSON. This is important because it allows the machine to be visualized by a 3rd-party tool, as demonstrated here:\n\nA Common Language Between Designers and Developers\nAlthough finite state machines are a fundamental part of computer science, they have an amazing potential to bridge the application specification gap between designers and developers, as well as project managers, stakeholders, and more. By designing a state machine visually and with code, designers and developers alike can:\n\nidentify all possible states, and potentially missing states\ndescribe exactly what should happen when an event occurs on a given state, and prevent that event from having unintended side-effects in other states (ever click a submit button more than once?)\neliminate impossible states and identify states that are \u201cunreachable\u201d (have no entry transition) or \u201csunken\u201d (have no exit transition)\nadd features with full confidence of knowing what other states it might affect\nsimplify redundant states or complex user flows\ncreate test paths for almost every possible user flow, and easily identify edge cases\ncollaborate better by understanding the entire application model equally.\n\nNot a New Idea\nI\u2019m not the first to suggest that state machines can help bridge the gap between design and development.\n\nVince MingPu Shao wrote an article about designing UI states and communicating with developers effectively with finite state machines\nUser flow diagrams, which visually describe the paths that a user can take through an app to achieve certain goals, are essentially state machines. Numerous tools, from Sketch plugins to standalone apps, exist for creating them.\nIn 1999, Ian Horrocks wrote a book titled \u201cConstructing the User Interface with Statecharts\u201d, which takes state machines to the next level and describes the inherent difficulties (and solutions) with creating complex UIs. The ideas in the book are still relevant today.\nMore than a decade earlier, David Harel published \u201cStatecharts: A Visual Formalism for Complex Systems\u201d, in which the statechart - an extended hierarchical state machine model - is born.\n\nState machines and statecharts have been used for complex systems and user interfaces, both physical and digital, for decades, and are especially prevalent in other industries, such as game development and embedded electronic systems. Even NASA uses statecharts for the Curiosity Rover and more, citing many benefits:\n\nVisualized modeling\nPrecise diagrams\nAutomatic code generation\nComprehensive test coverage\nAccommodation of late-breaking requirements changes\n\nMoving Forward\nIt\u2019s time that we improve how we communicate between designers and developers, much less improve the way we develop UIs to deliver the best, bug-free, optimal user experience. There is so much more to state machines and statecharts than just being a different way of designing and coding. For more resources:\n\nThe World of Statecharts is a comprehensive guide by Erik Mogensen in using statecharts in your applications\nThe Statechart Community on Spectrum is always full of interesting ideas and questions related to state machines, statecharts, and software modeling\nI gave a talk at React Rally over a year ago about how state machines (finite automata) can improve the way we develop applications. The latest one is from Reactive Conf, where I demonstrate how statecharts can be used to automatically generate test cases.\nI have also been working on XState, which is a library for \u201cstate machines and statecharts for the modern web\u201d. You can create and visualize statecharts in JavaScript, and use them in any framework (and soon enough, multiple different languages).\n\nI\u2019m excited about the future of developing web and mobile applications with statecharts, especially with regard to faster design/development cycles, auto-generated testing, better error prevention, comprehensive analytics, and even the use of model-based reinforcement learning and artificial intelligence to greatly improve the user experience.", "year": "2018", "author": "David Khourshid", "author_slug": "davidkhourshid", "published": "2018-12-12T00:00:00+00:00", "url": "https://24ways.org/2018/state-machines-in-user-interfaces/", "topic": "code"} {"rowid": 252, "title": "Turn Jekyll up to Eleventy", "contents": "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 \u2014 and more secure \u2014 option. \nThe JAMstack (JavaScript, reusable APIs, and prebuilt Markup) is a popular marketing term for this way of building websites, but in some ways it\u2019s 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.\nBy combining three approachable languages \u2014 Markdown for content, YAML for data and Liquid for templating \u2014 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\u2019s 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 \u201cthis, but in Node\u201d. Thankfully, one of Santa\u2019s elves (Zach Leatherman) granted my Atwoodian wish and placed such a static site generator under my tree.\nIntroducing Eleventy\nEleventy is a more flexible alternative Jekyll. Besides being written in Node, it\u2019s 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).\nAs 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\u2019ve discovered, there are a few gotchas. If you\u2019ve been considering making the switch, here are a few tips and tricks to help you on your way1.\nNote: Throughout this article, I\u2019ll be converting Matt Cone\u2019s 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:\ngit clone https://github.com/mattcone/markdown-guide.git\ncd markdown-guide\nBefore you start\nIf you\u2019ve used tools like Grunt, Gulp or Webpack, you\u2019ll be familiar with Node.js but, if you\u2019ve been exclusively using Jekyll to compile your assets as well as generate your HTML, now\u2019s the time to install Node.js and set up your project to work with its package manager, NPM:\n\nInstall Node.js:\n\nMac: If you haven\u2019t already, I recommend installing Homebrew, a package manager for the Mac. Then in the Terminal type brew install node.\nWindows: Download the Windows installer from the Node.js website and follow the instructions.\n\nInitiate 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\u2019s Gemfile, this file contains a list of your project\u2019s third-party dependencies.\n\nIf you\u2019re 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\u2019t be version controlled. Eleventy will also honour the contents of this file, meaning anything you want Git to ignore, Eleventy will ignore too.\nInstalling Eleventy\nWith Node.js installed and your project setup to work with NPM, we can now install Eleventy as a dependency:\nnpm install --save-dev @11ty/eleventy\nIf you open package.json you should see the following:\n\u2026\n\"devDependencies\": {\n \"@11ty/eleventy\": \"^0.6.0\"\n}\n\u2026\nWe can now run Eleventy from the command line using NPM\u2019s npx command. For example, to covert the README.md file to HTML, we can run the following:\nnpx eleventy --input=README.md --formats=md\nThis 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.\nConfiguration\nWhereas 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\u2019ll see later on.\nWe\u2019ll start by creating our configuration file (.eleventy.js), copying the relevant settings in _config.yml over to their equivalent options:\nmodule.exports = function(eleventyConfig) {\n return {\n dir: {\n input: \"./\", // Equivalent to Jekyll's source property\n output: \"./_site\" // Equivalent to Jekyll's destination property\n }\n };\n};\nA few other things to bear in mind:\n\n\nWhereas 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).\n\nBy default, Eleventy uses markdown-it to parse Markdown. If your content uses advanced syntax features (such as abbreviations, definition lists and footnotes), you\u2019ll need to pass Eleventy an instance of this (or another) Markdown library configured with the relevant options and plugins.\n\nLayouts\nOne area Eleventy currently lacks flexibility is the location of layouts, which must reside within the _includes directory (see this issue on GitHub).\nWanting to keep our layouts together, we\u2019ll 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\u2019s config:\nmodule.exports = function(eleventyConfig) {\n // Aliases are in relation to the _includes folder\n eleventyConfig.addLayoutAlias('about', 'layouts/about.html');\n eleventyConfig.addLayoutAlias('book', 'layouts/book.html');\n eleventyConfig.addLayoutAlias('default', 'layouts/default.html');\n\n return {\n dir: {\n input: \"./\",\n output: \"./_site\"\n }\n };\n}\nDetermining which template language to use\nEleventy will transform Markdown (.md) files using Liquid by default, but we\u2019ll 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.\nVariables\nOn 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.\nSite variables\nAlongside build settings, Jekyll let\u2019s 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:\ntitle: \"Markdown Guide\"\nurl: https://www.markdownguide.org\nbaseurl: \"\"\nrepo: http://github.com/mattcone/markdown-guide\ncomments: false\nauthor:\n name: \"Matt Cone\"\nog_locale: \"en_US\"\nEleventy\u2019s 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.\n{\n \"title\": \"Markdown Guide\",\n \"url\": \"https://www.markdownguide.org\",\n \"baseurl\": \"\",\n \"repo\": \"http://github.com/mattcone/markdown-guide\",\n \"comments\": false,\n \"author\": {\n \"name\": \"Matt Cone\"\n },\n \"og_locale\": \"en_US\"\n}\nPage variables\nThe 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:\n\n\n\nJekyll\nEleventy\n\n\n\n\npage.url\npage.url\n\n\npage.date\npage.date\n\n\npage.path\npage.inputPath\n\n\npage.id\npage.outputPath\n\n\npage.name\npage.fileSlug\n\n\npage.content\ncontent\n\n\npage.title\ntitle\n\n\npage.foobar\nfoobar\n\n\n\nWhen iterating through pages, frontmatter values are available via the data object while content is available via templateContent:\n\n\n\nJekyll\nEleventy\n\n\n\n\nitem.url\nitem.url\n\n\nitem.date\nitem.date\n\n\nitem.path\nitem.inputPath\n\n\nitem.name\nitem.fileSlug\n\n\nitem.id\nitem.outputPath\n\n\nitem.content\nitem.templateContent\n\n\nitem.title\nitem.data.title\n\n\nitem.foobar\nitem.data.foobar\n\n\n\nIdeally 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.\nPagination variables\nWhereas Jekyll\u2019s 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:\n\n\n\nJekyll\nEleventy\n\n\n\n\npaginator.page\npagination.pageNumber\n\n\npaginator.per_page\npagination.size\n\n\npaginator.posts\npagination.items\n\n\npaginator.previous_page_path\npagination.previousPageHref\n\n\npaginator.next_page_path\npagination.nextPageHref\n\n\n\nFilters\nAlthough Jekyll uses Liquid, it provides a set of filters that are not part of the core Liquid library. There are quite a few \u2014 more than can be covered by this article \u2014 but you can replicate them by using Eleventy\u2019s addFilter configuration option. Let\u2019s convert two used by our Markdown Guide: jsonify and where.\nThe 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:\n// {{ variable | jsonify }}\neleventyConfig.addFilter('jsonify', function (variable) {\n return JSON.stringify(variable);\n});\nJekyll\u2019s 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:\n{{ site.members | where: \"graduation_year\",\"2014\" }}\nTo 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:\n// {{ array | where: key,value }}\neleventyConfig.addFilter('where', function (array, key, value) {\n return array.filter(item => {\n const keys = key.split('.');\n const reducedKey = keys.reduce((object, key) => {\n return object[key];\n }, item);\n\n return (reducedKey === value ? item : false);\n });\n});\nThere\u2019s quite a bit going on within this filter, but I\u2019ll try to explain. Essentially we\u2019re 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\u2019s removed. Phew!\nIncludes\nAs with filters, Jekyll provides a set of tags that aren\u2019t 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\u2019re not passing variables to your includes, everything should work without modification. Otherwise, note that whereas with Jekyll you would do this:\n\n{% include include.html value=\"key\" %}\n\n\n{{ include.value }}\nin Eleventy, you would do this:\n\n{% include \"include.html\", value: \"key\" %}\n\n\n{{ value }}\nA downside of Shopify\u2019s 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.\nTweaking Liquid\nYou 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\u2019s dynamicPartials option to false. Additionally, Eleventy doesn\u2019t support the include_relative tag, meaning you can\u2019t include files relative to the current document. However, LiquidJS does let us define multiple paths to look for included files via its root option. \nThankfully, Eleventy allows us to pass options to LiquidJS:\neleventyConfig.setLiquidOptions({\n dynamicPartials: false,\n root: [\n '_includes',\n '.'\n ]\n});\nCollections\nJekyll\u2019s 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.\nCollections in Jekyll\nIn 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:\ncollections:\n - basic-syntax\n - extended-syntax\nThese correspond to the folders _basic-syntax and _extended-syntax whose content we can iterate over like so:\n{% for syntax in site.extended-syntax %}\n {{ syntax.title }}\n{% endfor %}\nCollections in Eleventy\nThere are two ways you can set up collections in 11ty. The first, and most straightforward, is to use the tag property in content files:\n---\ntitle: Strikethrough\nsyntax-id: strikethrough\nsyntax-summary: \"~~The world is flat.~~\"\ntag: extended-syntax\n---\nWe can then iterate over tagged content like this:\n{% for syntax in collections.extended-syntax %}\n {{ syntax.data.title }}\n{% endfor %}\nEleventy 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):\neleventyConfig.addCollection('basic-syntax', collection => {\n return collection.getFilteredByGlob('_basic-syntax/*.md');\n});\n\neleventyConfig.addCollection('extended-syntax', collection => {\n return collection.getFilteredByGlob('_extended-syntax/*.md');\n});\nWe can extend this further. For example, say we wanted to sort a collection by the display_order property in our document\u2019s frontmatter. We could take the results of collection.getFilteredByGlob and then use JavaScript\u2019s sort method to sort the result:\neleventyConfig.addCollection('example', collection => {\n return collection.getFilteredByGlob('_examples/*.md').sort((a, b) => {\n return a.data.display_order - b.data.display_order;\n });\n});\nHopefully, this gives you just a hint of what\u2019s possible using this approach.\nUsing directory data to manage defaults\nBy 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:\n---\ntitle: Lists\nsyntax-id: lists\napi: \"no\"\npermalink: /basic-syntax/lists.html\n---\nAgain, 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.\nFor 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:\n{\n \"layout\": \"syntax\",\n \"tag\": \"basic-syntax\",\n \"permalink\": \"basic-syntax/{{ title | slug }}.html\"\n}\nHowever, Markdown Guide doesn\u2019t publish syntax examples at individual permanent URLs, it merely uses content files to store data. So let\u2019s change things around a little. No longer tied to Jekyll\u2019s rules about where collection folders should be saved and how they should be labelled, we\u2019ll move them into a folder called _content:\nmarkdown-guide\n\u2514\u2500\u2500 _content\n \u251c\u2500\u2500 basic-syntax\n \u251c\u2500\u2500 extended-syntax\n \u251c\u2500\u2500 getting-started\n \u2514\u2500\u2500 _content.json\nWe 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:\n{\n \"permalink\": false\n}\nStatic files\nEleventy only transforms files whose template language it\u2019s familiar with. But often we may have static assets that don\u2019t 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:\nmodule.exports = function(eleventyConfig) {\n \u2026\n\n // Copy the `assets` directory to the compiled site folder\n eleventyConfig.addPassthroughCopy('assets');\n\n return {\n dir: {\n input: \"./\",\n output: \"./_site\"\n },\n passthroughFileCopy: true\n };\n}\nFinal considerations\nAssets\nUnlike Jekyll, Eleventy provides no support for asset compilation or bundling scripts \u2014 we have plenty of choices in that department already. If you\u2019ve 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.\nPublishing to GitHub Pages\nOne of the benefits of Jekyll is its deep integration with GitHub Pages. To publish an Eleventy generated site \u2014 or any site not built with Jekyll \u2014 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\u2019s 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!\n\nGoing one louder\nIf you\u2019ve 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. \nWhile it\u2019s fun to try new software and emerging technologies, doing so can require a lot of work and compromise. For all of Eleventy\u2019s appeal, it\u2019s 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.\nI 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\u2019s perfectly fine! \nBut these go to 11.\n\n\n\n\nInformation provided is correct as of Eleventy v0.6.0 and Jekyll v3.8.5\u00a0\u21a9", "year": "2018", "author": "Paul Lloyd", "author_slug": "paulrobertlloyd", "published": "2018-12-11T00:00:00+00:00", "url": "https://24ways.org/2018/turn-jekyll-up-to-eleventy/", "topic": "content"} {"rowid": 250, "title": "Build up Your Leadership Toolbox", "contents": "Leadership. It can mean different things to different people and vary widely between companies. Leadership is more than just a job title. You won\u2019t wake up one day and magically be imbued with all you need to do a good job at leading. If we don\u2019t have a shared understanding of what a Good Leader looks like, how can we work on ourselves towards becoming one? How do you know if you even could be a leader? Can you be a leader without the title?\nWhat even is it?\nI got very frustrated way back in my days as a senior developer when I was given \u201cadvice\u201d about my leadership style; at the time I didn\u2019t have the words to describe the styles and ways in which I was leading to be able to push back. I heard these phrases a lot:\n\nyou need to step up\nyou need to take charge\nyou need to grab the bull by its horns\nyou need to have thicker skin\nyou need to just be more confident in your leading\nyou need to just make it happen\n\nI appreciate some people\u2019s intent was to help me, but honestly it did my head in. WAT?! What did any of this even mean. How exactly do you \u201cstep up\u201d and how are you evaluating what step I\u2019m on? I am confident, what does being even more confident help achieve with leading? Does that not lead you down the path of becoming an arrogant door knob? >___<\nWhile there is no One True Way to Lead, there is an overwhelming pattern of people in positions of leadership within tech industry being held by men. It felt a lot like what people were fundamentally telling me to do was to be more like an extroverted man. I was being asked to demonstrate more masculine associated qualities (#notallmen). I\u2019ll leave the gendered nature of leadership qualities as an exercise in googling for the reader.\nI\u2019ve never had a good manager and at the time had no one else to ask for help, so I turned to my trusted best friends. Books.\nI <3 books\nI refused to buy into that style of leadership as being the only accepted way to be. There had to be room for different kinds of people to be leaders and have different leadership styles.\nThere are three books that changed me forever in how I approach and think about leadership.\n\nPrimal leadership, by Daniel Goleman, Richard Boyatzis and Annie McKee\nQuiet, by Susan Cain\nDaring Greatly - How the Courage to be Vulnerable transforms the way we live, love, parent and Lead, by Bren\u00e9 Brown\n\nI recommend you read them. Ignore the slightly cheesy titles and trust me, just read them.\nPrimal leadership helped to give me the vocabulary and understanding I needed about the different styles of leadership there are, how and when to apply them.\nQuiet really helped me realise how much I was being undervalued and misunderstood in an extroverted world. If I\u2019d had managers or support from someone who valued introverts\u2019 strengths, things would\u2019ve been very different. I would\u2019ve had someone telling others to step down and shut up for a change rather than pushing on me to step up and talk louder over everyone else. It\u2019s OK to be different and needing different things like time to recharge or time to think before speaking. It also improved my ability to work alongside my more extroverted colleagues by giving me an understanding of their world so I could communicate my needs in a language they would get.\nBren\u00e9 Brown\u2019s book I am forever in debt to. Her work gave me the courage to stand up and be my own kind of leader. Even when no-one around me looked or sounded like me, I found my own voice.\nIt takes great courage to be vulnerable and open about what you can and can\u2019t do. Open about your mistakes. Vocalise what you don\u2019t know and asking for help. In some lights, these are seen as weaknesses and many have tried to use them against me, to pull me down and exclude me for talking about them. Dear reader, it did not work, they failed. The truth is, they are my greatest strengths. The privileges I have, I use for good as best and often as I can.\nJust like gender, leadership is not binary\nIf you google for what a leader is, you\u2019ll get many different answers. I personally think Bren\u00e9\u2019s version is the best as it is one that can apply to a wider range of people, irrespective of job title or function.\n\nI define a leader as anyone who takes responsibility for finding potential in people and processes, and who has the courage to develop that potential.\nBren\u00e9 Brown\n\nBeing a leader isn\u2019t about being the loudest in a room, having veto power, talking over people or ignoring everyone else\u2019s ideas. It\u2019s not about \u201ctelling people what to do\u201d. It\u2019s not about an elevated status that you\u2019re better than others. Nor is it about creating a hand wavey far away vision and forgetting to help support people in how to get there.\nBeing a Good Leader is about having a toolbox of leadership styles and skills to choose from depending on the situation. Knowing how and when to apply them is part of the challenge and difficulty in becoming good at it. It is something you will have to continuously work on, forever. There is no Done.\nLeaders are Made, they are not Born.\nBe flexible in your leadership style\n\nTypically, the best, most effective leaders act according to one or more of six distinct approaches to leadership and skillfully switch between the various styles depending on the situation.\n\nFrom the book, Primal Leadership, it gives a summary of 6 leadership styles which are:\n\nVisionary\nCoaching\nAffiliative\nDemocratic\nPacesetting\nCommanding\n\nVisionary, moves people toward a shared dream or future. When change requires a new vision or a clear direction is needed, using a visionary style of leadership helps communicate that picture. By learning how to effectively communicate a story you can help people to move in that direction and give them clarity on why they\u2019re doing what they\u2019re doing.\nCoaching, is about connecting what a person wants and helping to align that with organisation\u2019s goals. It\u2019s a balance of helping someone improve their performance to fulfil their role and their potential beyond.\nAffiliative, creates harmony by connecting people to each other and requires effective communication to aid facilitation of those connections. This style can be very impactful in healing rifts in a team or to help strengthen connections within and across teams. During stressful times having a positive and supportive connection to those around us really helps see us through those times.\nDemocratic, values people\u2019s input and gets commitment through participation. Taking this approach can help build buy-in or consensus and is a great way to get valuable input from people. The tricky part about this style, I find, is that when I gather and listen to everyone\u2019s input, that doesn\u2019t mean the end result is that I have to please everyone.\nThe next two, sadly, are the ones wielded far too often and have the greatest negative impact. It\u2019s where the \u201ctelling people what to do\u201d comes from. When used sparingly and in the right situations, they can be a force for good. However, they must not be your default style.\nPacesetting, when used well, it is about meeting challenging and exciting goals. When you need to get high-quality results from a motivated and well performing team, this can be great to help achieve real focus and drive. Sadly it is so overused and poorly executed it becomes the \u201cjust make it happen\u201d and driver of unrealistic workload which contributes to burnout.\nCommanding, when used appropriately soothes fears by giving clear direction in an emergency or crisis. When shit is on fire, you want to know that your leadership ability can help kick-start a turnaround and bring clarity. Then switch to another style. This approach is also required when dealing with problematic employees or unacceptable behaviour.\nCommanding style seems to be what a lot of people think being a leader is, taking control and commanding a situation. It should be used sparingly and only when absolutely necessary.\nBe responsible for the power you wield\nIf reading through those you find yourself feeling a bit guilty that maybe you overuse some of the styles, or overwhelmed that you haven\u2019t got all of these down and ready to use in your toolbox\u2026\nTake a breath. Take responsibility. Take action.\nNo one is perfect, and it\u2019s OK. You can start right now working on those. You can have a conversation with your team and try being open about how you\u2019re going to try some different styles. You can be vulnerable and own up to mistakes you might\u2019ve made followed with an apology. You can order those books and read them. Those books will give you more examples on those leadership styles and help you to find your own voice.\nThe impact you can have on the lives of those around you when you\u2019re a leader, is huge. You can help be that positive impact, help discover and develop potential in someone.\n\nTime spent understanding people is never wasted.\nCate Huston.\n\nI believe in you. <3 Mazz.", "year": "2018", "author": "Mazz Mosley", "author_slug": "mazzmosley", "published": "2018-12-10T00:00:00+00:00", "url": "https://24ways.org/2018/build-up-your-leadership-toolbox/", "topic": "business"} {"rowid": 261, "title": "Surviving\u2014and Thriving\u2014as a Remote Worker", "contents": "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\u2019s an entire world of talent out there?\nI\u2019ve been working remotely, full-time, for five and a half years. I\u2019ve reached the point where I can\u2019t 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\u2019ve grown attached to my current level of freedom and flexibility.\nHowever, it took me a lot of trial and error to reach success as a remote worker \u2014 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\u2019t for everyone, but most people, with enough effort, can make it work \u2014 or even thrive. Here\u2019s what I\u2019ve learned in over five years of working remotely.\nExperiment with your environment\nAs 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 \u2014 whether that\u2019s a dedicated office, a corner of your bedroom, or your kitchen table. (Ideally, not your couch\u2026 but I\u2019ve 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\u2019t completely destroy your eyesight.\nWorking remotely doesn\u2019t always mean working from home. If you don\u2019t 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\u2019t 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\u2019re 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.\nCo-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\u2019re 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.) \nJust be polite \u2014 make sure your headphones don\u2019t leak, and don\u2019t work from a library if you have a day full of calls.\nRemember, too, that you don\u2019t have to stay in the same spot all day. It\u2019s 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\u2019t force yourself to sit at your desk for eight hours if that doesn\u2019t work for you.\nSet boundaries\nIf you\u2019re a workaholic, working remotely can be a challenge. It\u2019s incredibly easy to just\u2026 work. All the time. My work computer is almost always with me. If I remember at 11pm that I wanted to do something, there\u2019s 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\u2019s time to figure this out, eh?\nLearning how to set boundaries is one of the most important lessons I\u2019ve learned working remotely. (And honestly, it\u2019s something I still struggle with). \nFor 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\u2019s noon, I\u2019m 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.\nI 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.\nI 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\u2019t get sucked into work before I\u2019m even dressed. I\u2019ve gotten pretty good at forbidding myself from working until I\u2019m ready, but building any new habit requires intentionality. \nSomething 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\u2019t 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\u2019ve heard other coworkers have figured out ways to work through these technical issues, so I\u2019m hoping to give it another try soon.\nYou might noticed that a lot of these ideas are just hacks for making myself not work outside of my designated work times. It\u2019s true! If you\u2019re a more disciplined person, you might not need any of these coping mechanisms. If you\u2019re struggling, finding ways to subvert your own bad habits can be the difference between thriving or burning out.\nCreate intentional transition time\nI know it\u2019s a stereotype that people who work from home stay in their pajamas all day, but\u2026 sometimes, it\u2019s very easy to do. I\u2019ve found that in order to reach peak focus, I need to create intentional transition time. \nThe 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\u2019s 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. \nI\u2019ve found it helpful to take similar steps at the end of my day. If I\u2019ve 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. \nThis is another reason working from outside your home is advantageous. Commutes, even if it\u2019s 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 \u2014 not next to your computer. \nEmbrace async\nIf you\u2019re used to working in an office, you\u2019ve probably gotten pretty used to being able to pop over to a colleague\u2019s desk if you need to ask a question. They\u2019re pretty much forced to engage with you at that point. When you\u2019re 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\u2019s in Australia and it\u2019s 3am there right now. \nFor many remote workers, that\u2019s part of the package. When you\u2019re 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.\nAsynchronous communication is great. Not everyone can be present for every meeting or office conversation \u2014 and the same goes for working remotely. However, when you\u2019re 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 (\u201cp2s\u201d) 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 \u2014 \u201cp2 or it didn\u2019t happen.\u201d\nWorking remotely has made me a better communicator largely because I\u2019ve gotten into the habit of making written updates. I\u2019ve 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!\n(That said, if you\u2019re 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.)\nSeek out social opportunities\nEven introverts can feel lonely or isolated. When you work remotely, there isn\u2019t a built-in community you\u2019re surrounded by every day. You have to intentionally seek out social opportunities that an office would normally provide.\nI 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.)\nEvery now and then, I\u2019ll 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.\nIf 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. \nIf you don\u2019t 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\u2019ve 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\u2019t fall back on your work to provide community, you need to build your own.\n\nThese are tips that I\u2019ve found help me, but not everyone works the same way. Remember that it\u2019s okay to experiment \u2014 just because you\u2019ve worked one way, doesn\u2019t mean that\u2019s 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!\nHope to see you all online soon \ud83d\ude4c", "year": "2018", "author": "Mel Choyce", "author_slug": "melchoyce", "published": "2018-12-09T00:00:00+00:00", "url": "https://24ways.org/2018/thriving-as-a-remote-worker/", "topic": "process"} {"rowid": 254, "title": "What I Learned in Six Years at GDS", "contents": "When I joined the Government Digital Service in April 2012, GOV.UK was just going into public beta. GDS was a completely new organisation, part of the Cabinet Office, with a mission to stop wasting government money on over-complicated and underperforming big IT projects and instead deliver simple, useful services for the public.\nLots of people who were experts in their fields were drawn in by this inspiring mission, and I learned loads from working with some true leaders. Here are three of the main things I learned.\n1. What is the user need?\n\u2028The main discipline I learned from my time at GDS was to always ask \u2018what is the user need?\u2019 It\u2019s very easy to build something that seems like a good idea, but until you\u2019ve identified what problem you are solving for the user, you can\u2019t be sure that you are building something that is going to help solve an actual problem.\nA really good example of this is GOV.UK Notify. This service was originally conceived of as a status tracker; a \u201cwhere\u2019s my stuff\u201d for government services. For example, if you apply for a passport online, it can take up to six weeks to arrive. After a few weeks, you might feel anxious and phone the Home Office to ask what\u2019s happening. The idea of the status tracker was to allow you to get this information online, saving your time and saving government money on call centres.\nThe project started, as all GDS projects do, with a discovery. The main purpose of a discovery is to identify the users\u2019 needs. At the end of this discovery, the team realised that a status tracker wasn\u2019t the way to address the problem. As they wrote in this blog post: \n\nStatus tracking tools are often just \u2018channel shift\u2019 for anxiety. They solve the symptom and not the problem. They do make it more convenient for people to reduce their anxiety, but they still require them to get anxious enough to request an update in the first place.\n\nWhat would actually address the user need would be to give you the information before you get anxious about where your passport is. For example, when your application is received, email you to let you know when to expect it, and perhaps text you at various points in the process to let you know how it\u2019s going. So instead of a status tracker, the team built GOV.UK Notify, to make it easy for government services to incorporate text, email and even letter notifications into their processes.\nMaking sure you know your user\nAt GDS user needs were taken very seriously. We had a user research lab on site and everyone was required to spend two hours observing user research every six weeks. Ideally you\u2019d observe users working with things you\u2019d built, but even if they weren\u2019t, it was an incredibly valuable experience, and something you should seek out if you are able to.\nEven if we think we understand our users very well, it is very enlightening to see how users actually use your stuff. Partly because in technology we tend to be power users and the average user doesn\u2019t use technology the same way we do. But even if you are building things for other developers, someone who is unfamiliar with it will interact with it in a way that may be very different to what you have envisaged.\nUser needs is not just about building things\nAsking the question \u201cwhat is the user need?\u201d really helps focus on why you are doing what you are doing. It keeps things on track, and helps the team think about what the actual desired end goal is (and should be). \nThinking about user needs has helped me with lots of things, not just building services. For example, you are raising a pull request. What\u2019s the user need? The reviewer needs to be able to easily understand what the change you are proposing is, why you are proposing that change and any areas you need particular help on with the review. \nOr you are writing an email to a colleague. What\u2019s the user need? What are you hoping the reader will learn, understand or do as a result of your email?\n2. Make things open: it makes things better\nThe second important thing I learned at GDS was \u2018make things open: it makes things better\u2019. This works on many levels: being open about your strategy, blogging about what you are doing and what you\u2019ve learned (including mistakes), and \u2013 the part that I got most involved in \u2013 coding in the open.\nTalking about your work helps clarify it\nOne thing we did really well at GDS was blogging \u2013 a lot \u2013 about what we were working on. Blogging about what you are working on is is really valuable for the writer because it forces you to think logically about what you are doing in order to tell a good story. If you are blogging about upcoming work, it makes you think clearly about why you\u2019re doing it; and it also means that people can comment on the blog post. Often people had really useful suggestions or clarifying questions.\nIt\u2019s also really valuable to blog about what you\u2019ve learned, especially if you\u2019ve made a mistake. It makes sure you\u2019ve learned the lesson and helps others avoid making the same mistakes. As well as blogging about lessons learned, GOV.UK also publishes incident reports when there is an outage or service degradation. Being open about things like this really engenders an atmosphere of trust and safe learning; which helps make things better.\nCoding in the open has a lot of benefits\nIn my last year at GDS I was the Open Source Lead, and one of the things I focused on was the requirement that all new government source code should be open. From the start, GDS coded in the open (the GitHub organisation still has the non-intuitive name alphagov, because it was created by the team doing the original Alpha of GOV.UK, before GDS was even formed).\nWhen I first joined GDS I was a little nervous about the fact that anyone could see my code. I worried about people seeing my mistakes, or receiving critical code reviews. (Setting people\u2019s mind at rest about these things is why it\u2019s crucial to have good standards around communication and positive behaviour - even a critical code review should be considerately given). \nBut I quickly realised there were huge advantages to coding in the open. In the same way as blogging your decisions makes you think carefully about whether they are good ones and what evidence you have, the fact that anyone in the world could see your code (even if, in practice, they probably won\u2019t be looking) makes everyone raise their game slightly. The very fact that you know it\u2019s open, makes you make it a bit better.\nIt helps with lots of other things as well, for example it makes it easier to collaborate with people and share your work. And now that I\u2019ve left GDS, it\u2019s so useful to be able to look back at code I worked on to remember how things worked.\nShare what you learn\nIt\u2019s sometimes hard to know where to start with being open about things, but it gets easier and becomes more natural as you practice. It helps you clarify your thoughts and follow through on what you\u2019ve decided to do. Working at GDS when this was a very important principle really helped me learn how to do this well.\n3. Do the hard work to make it simple (tech edition)\n\u2018Start with user needs\u2019 and \u2018Make things open: it makes things better\u2019 are two of the excellent government design principles. They are all good, but the third thing that I want to talk about is number 4: \u2018Do the hard work to make it simple\u2019, and specifically, how this manifests itself in the way we build technology.\nAt GDS, we worked very hard to do the hard work to make the code, systems and technology we built simple for those who came after us. For example, writing good commit messages is taken very seriously. There is commit message guidance, and it was not unusual for a pull request review to ask for a commit message to be rewritten to make a commit message clearer.\nWe worked very hard on making pull requests good, keeping the reviewer in mind and making it clear to the user how best to review it.\nReviewing others\u2019 pull requests is the highest priority so that no-one is blocked, and teams have screens showing the status of open pull requests (using fourth wall) and we even had a \u2018pull request seal\u2019, a bot that publishes pull requests to Slack and gets angry if they are uncommented on for more than two days.\nMaking it easier for developers to support the site\nAnother example of doing the hard work to make it simple was the opsmanual. I spent two years on the web operations team on GOV.UK, and one of the things I loved about that team was the huge efforts everyone went to to be open and inclusive to developers.\nThe team had some people who were really expert in web ops, but they were all incredibly helpful when bringing me on board as a developer with no previous experience of web ops, and also patiently explaining things whenever other devs in similar positions came with questions. \nThe main artefact of this was the opsmanual, which contained write-ups of how to do lots of things. One of the best things was that every alert that might lead to someone being woken up in the middle of the night had a link to documentation on the opsmanual which detailed what the alert meant and some suggested actions that could be taken to address it.\nThis was important because most of the devs on GOV.UK were on the on-call rota, so if they were woken at 3am by an alert they\u2019d never seen before, the opsmanual information might give them everything they needed to solve it, without the years of web ops training and the deep familiarity with the GOV.UK infrastructure that came with working on it every day.\nDevelopers are users too\nDoing the hard work to make it simple means that users can do what they need to do, and this applies even when the users are your developer peers. At GDS I really learned how to focus on simplicity for the user, and how much better this makes things work.\nThese three principles help us make great things\nI learned so much more in my six years at GDS. For example, the civil service has a very fair way of interviewing. I learned about the importance of good comms, working late, responsibly and the value of content design.\nAnd the real heart of what I learned, the guiding principles that help us deliver great products, is encapsulated by the three things I\u2019ve talked about here: think about the user need, make things open, and do the hard work to make it simple.", "year": "2018", "author": "Anna Shipman", "author_slug": "annashipman", "published": "2018-12-08T00:00:00+00:00", "url": "https://24ways.org/2018/what-i-learned-in-six-years-at-gds/", "topic": "business"} {"rowid": 247, "title": "Managing Flow and Rhythm with CSS Custom Properties", "contents": "An important part of designing user interfaces is creating consistent vertical rhythm between elements. Creating consistent, predictable space doesn\u2019t just make your web pages and views look better, but it can also improve the scan-ability. \nBrowsers ship with default CSS and these styles often create consistent rhythm for flow elements out of the box. The problem is though that we often reset these styles with a reset. Elements such as
and
also have no default margin or padding associated with them. \nI\u2019ve tried all sorts of weird and wonderful techniques to find a balance between using inherited CSS while also levelling the playing field for component driven front-ends with very little success. This experimentation is how I landed on the flow utility, though and I\u2019m going to show you how it works. Let\u2019s dive in!\nThe Flow utility\nWith the ever-growing number of folks working with component libraries and design systems, we could benefit from a utility that creates space for us, only when it\u2019s appropriate to do so. The problem with my previous attempts at fixing this is that the spacing values were very rigid. \nThat\u2019s fine for 90% of contexts, but sometimes, it\u2019s handy to be able to tweak the values based on the exact context of your component. This is where CSS Custom Properties come in handy.\nThe code\n.flow {\n --flow-space: 1em;\n} \n\n.flow > * + * { \n margin-top: var(--flow-space);\n}\nWhat this code does is enable you to add a class of flow to an element which will then add margin-top to sibling elements within that element. We use the lobotomised owl selector to select these siblings. This approach enables an almost anonymous and automatic system which is ideal for component library based front-ends where components probably don\u2019t have any idea what surrounds them. \nThe other important part of this utility is the usage of the --flow-space custom property. We define it in the .flow component and each element within it will be spaced by --flow-space, by default. The beauty about setting this as a custom property is that custom properties also participate in the cascade, so we can utilise specificity to change it if we need it. Pretty cool, right? Let\u2019s look at some examples.\nA basic example\nSee the Pen CSS Flow Utility: Basic implementation by Andy Bell (@hankchizljaw) on CodePen.\nhttps://codepen.io/hankchizljaw/pen/LXqerj\nWhat we\u2019ve got in this example is some basic HTML content that has a class of flow on the parent article element. Because there\u2019s a very heavy-handed reset added as a dependency, all of the content would have been squished together without the flow utility. \nBecause our --flow-space custom property is set to 1em, the space between elements is 1X the font size of the element in question. This means that a

in this context has a calculated margin-top value of 28.8px, because it has an assigned font size of 1.8rem. If we were to globally change the --flow-space value to 1.1em for example, we\u2019d affect everything because margin values would be calculated as 1.1X the font size. \nThis example looks great because using font size as the basis of rhythm works really well. What if we wanted to to tweak certain elements within this article, though? \nSee the Pen CSS Flow Utility: Tweaked Basic implementation by Andy Bell (@hankchizljaw) on CodePen.\nhttps://codepen.io/hankchizljaw/pen/qQgxaY\nI like lots of whitespace with my article layouts, so the 1em space isn\u2019t going to cut it for all elements. I like to provide plenty of space between headed sections, so I increase the --flow-space in these instances:\nh2 {\n --flow-space: 3rem;\n}\nNotice also how I also switch over to using rem units? I want to make sure that these overrides are always based on the root font size. This is a personal preference of mine and you can use whatever units you want. Just be aware that it\u2019s better for accessibility to use flexible units like em, rem and %, so that a user\u2019s font size preferences are honoured. \nA more advanced example\nAlthough the flow utility is super useful for a plethora of contexts, it really shines when working with a few unrelated components. Instead of having to write specific layout CSS just for your particular context, you can use flow and --flow-space to create predictable and contextual space.\nSee the Pen CSS Flow Utility: Unrelated components by Andy Bell (@hankchizljaw) on CodePen.\nhttps://codepen.io/hankchizljaw/pen/ZmPGyL\nIn this example, we\u2019ve got ourselves a little prototype layout that features a media element, followed by a grid of features. By using flow, it was really quick and easy to generate space between those two main elements. It was also easy to create space within the components. For example, I added it to the .media__content element, so that the article\u2019s content would space itself:\n
\n ...\n
\nSomething to remember though: the custom properties cascade in the same way that other CSS values do, so you\u2019ve got to keep that in mind. We\u2019ve got a great example of that in this example where because we\u2019ve got the flow utility on our .features component, which has a --flow-space override: the child elements of .features will inherit that value, so we\u2019ve had to set another value on the .features__list element.\n\u201cBut what about old browsers?\u201d, I hear you cry\nWe\u2019re using CSS Custom Properties that at the time of writing, have about 88% support. One thing we can do to remedy the other 12% of browsers is to set a default, traditional margin-top value of 1em, so it calculates itself based on the element\u2019s font-size:\n.flow {\n --flow-space: 1em;\n}\n\n.flow > * + * { \n margin-top: 1em;\n margin-top: var(--flow-space);\n}\nThanks to the cascading and declarative nature of CSS, we can set that default margin-top value and then immediately set it to use the custom property instead. Browsers that understand Custom Properties will automatically apply them\u2014those that don\u2019t will ignore them. Yay for the cascade and progressive enhancement! \nWrapping up\nThis tiny little utility can bring great power for when you want to consistently space elements, vertically. It also\u2014thanks to the power of the modern web\u2014allows us to create contextual overrides without creating modifier classes or shame CSS. \nIf you\u2019ve got other methods of doing this sort of work, please let me know on Twitter. I\u2019d love to see what you\u2019re working on!", "year": "2018", "author": "Andy Bell", "author_slug": "andybell", "published": "2018-12-07T00:00:00+00:00", "url": "https://24ways.org/2018/managing-flow-and-rhythm-with-css-custom-properties/", "topic": "code"} {"rowid": 262, "title": "Be the Villain", "contents": "Inclusive Design is the practice of making products and services accessible to, and usable by as many people as reasonably possible without the need for specialized accommodations. The practice was popularized by author and User Experience Design Director Kat Holmes. If getting you to discover her work is the only thing this article succeeds in doing then I\u2019ll consider it a success.\nAs a framework for creating resilient solutions to problems, Inclusive Design is incredible. However, the aimless idealistic aspirations many of its newer practitioners default to can oftentimes run into trouble. Without outlining concrete, actionable outcomes that are then vetted by the people you intend to serve, there is the potential to do more harm than good. \nWhen designing, you take a user flow and make sure it can\u2019t be broken. Ensuring that if something is removed, it can be restored. Or that something editable can also be updated at a later date\u2014you know, that kind of thing. What we want to do is avoid surprises. Much like a water slide with a section of pipe missing, a broken flow forcibly ejects a user, to great surprise and frustration. Interactions within a user flow also have to be small enough to be self-contained, so as to avoid creating a none pizza with left beef scenario.\nLately, I\u2019ve been thinking about how to expand on this practice. Watertight user flows make for a great immediate experience, but it\u2019s all too easy to miss the forest for the trees when you\u2019re a product designer focused on cranking out features. \nWhat I\u2019m concerned about is while to trying to envision how a user flow could be broken, you also think about how it could be subverted. In addition to preventing the removal of a section of water slide, you also keep someone from mugging the user when they shoot out the end.\nIf you pay attention, you\u2019ll start to notice this subversion with increasing frequency:\n\nDomestic abusers using internet-controlled devices to spy on and control their partner.\nZealots tanking a business\u2019 rating on Google because its owners spoke out against unchecked gun violence.\nForcing people to choose between TV or stalking because the messaging center portion of a cable provider\u2019s entertainment package lacks muting or blocking features.\nWhite supremacists tricking celebrities into endorsing anti-Semitic conspiracy theories.\nFacebook repeatedly allowing housing, credit, and employment advertisers to discriminate against users by their race, ability, and religion.\nWhite supremacists also using a video game chat service as a recruiting tool.\nThe unchecked harassment of minors on Instagram.\nSwatting.\n\nIf I were to guess why we haven\u2019t heard more about this problem, I\u2019d say that optimistically, people have settled out of court. Pessimistically, it\u2019s most likely because we ignore, dismiss, downplay, and suppress those who try to bring it to our attention. \nSubverted design isn\u2019t the practice of employing Dark Patterns to achieve your business goals. If you are not familiar with the term, Dark Patterns are the use of cheap user interface tricks and psychological manipulation to get users to act against their own best interests. User Experience consultant Chris Nodder wrote Evil By Design, a fantastic book that unpacks how to detect and think about them, if you\u2019re interested in this kind of thing\nSubverted design also isn\u2019t beholden design, or simple lack of attention. This phenomenon isn\u2019t even necessarily premeditated. I think it arises from na\u00efve (or willfully ignorant) design decisions being executed at a historically unprecedented pace and scale. These decisions are then preyed on by the shrewd and opportunistic, used to control and inflict harm on the undeserving. Have system, will game.\nThis is worth discussing. As the field of design continues to industrialize empathy, it also continues to ignore the very established practice of threat modeling. Most times, framing user experience in terms of how to best funnel people into a service comes with an implicit agreement that the larger system that necessitates the service is worth supporting. \nTo achieve success in the eyes of their superiors, designers may turn to emotional empathy exercises. By projecting themselves into the perceived surface-level experiences of others, they play-act at understanding how to nudge their targeted demographics into a conversion funnel. This roleplaying exercise has the effect of scoping concerns to the immediate, while simultaneously reinforcing the idea of engagement at all cost within the identified demographic.\nThe thing is, pure engagement leaves the door wide open for bad actors. Even within the scope of a limited population, the assumption that everyone entering into the funnel is acting with good intentions is a poor one. Security researchers, network administrators, and other professionals who practice threat modeling understand that the opposite is true. By preventing everyone save for well-intentioned users from operating a system within the parameters you set for them, you intentionally limit the scope of abuse that can be enacted.\nDon\u2019t get me wrong: being able to escort as many users as you can to the happy path is a foundational skill. But we should also be having uncomfortable conversations about why something unthinkable may in fact not be. \nThey\u2019re not going to be fun conversations. It\u2019s not going to be easy convincing others that these aren\u2019t paranoid delusions best tucked out of sight in the darkest, dustiest corner of the backlog. Realistically, talking about it may even harm your career.\nBut consider the alternative. The controlled environment of the hypothetical allows us to explore these issues without propagating harm. Better to be viewed as the office\u2019s resident villain than to have to live with something like this:\n\nIf the past few years have taught us anything, it\u2019s that the choices we make\u2014or avoid making\u2014have consequences. Design has been doing a lot of growing up as of late, including waking up to the idea that technology isn\u2019t neutral. \nYou\u2019re going to have to start thinking the way a monster does\u2014if you can imagine it, chances are someone else can as well. To get into this kind of mindset, inverting the Inclusive Design Principles is a good place to start:\n\nProviding a comparable experience becomes forcing a single path.\nConsidering situation becomes ignoring circumstance.\nBeing consistent becomes acting capriciously.\nGiving control becomes removing autonomy. \nOffering choice becomes limiting options. \nPrioritizing content becomes obfuscating purpose.\nAdding value becomes filling with gibberish. \n\nCombined, these inverted principles start to paint a picture of something we\u2019re all familiar with: a half-baked, unscrupulous service that will jump at the chance to take advantage of you. This environment is also a perfect breeding ground for spawning bad actors.\nThese kinds of services limit you in the ways you can interact with them. They kick you out or lock you in if you don\u2019t meet their unnamed criteria. They force you to parse layout, prices, and policies that change without notification or justification. Their controls operate in ways that are unexpected and may shift throughout the experience. Their terms are dictated to you, gaslighting you to extract profit. Heaps of jargon and flashy, unnecessary features are showered on you to distract from larger structural and conceptual flaws.\nSo, how else can we go about preventing subverted design? Marli Mesibov, Content Strategist and Managing Editor of UX Booth, wrote a brilliant article about how to use Dark Patterns for good\u2014perhaps the most important takeaway being admitting you have a problem in the first place. \nAnother exercise is asking the question, \u201cWhat is the evil version of this feature?\u201d Ask it during the ideation phase. Ask it as part of acceptance criteria. Heck, ask it over lunch. I honestly don\u2019t care when, so long as the question is actually raised. \nIn keeping with the spirit of this article, we can also expand on this line of thinking. Author, scientist, feminist, and pacifist Ursula Franklin urges us to ask, \u201cWhose benefits? Whose risks?\u201d instead of \u201cWhat benefits? What risks?\u201d in her talk, When the Seven Deadly Sins Became the Seven Cardinal Virtues. Inspired by the talk, Ethan Marcotte discusses how this relates to the web platform in his powerful post, Seven into seven.\nFew things in this world are intrinsically altruistic or good\u2014it\u2019s just the nature of the beast. However, that doesn\u2019t mean we have to stand idly by when harm is created. If we can add terms like \u201canti-pattern\u201d to our professional vocabulary, we can certainly also incorporate phrases like \u201cabuser flow.\u201d \nDesign finally got a seat at the table. We should use this newfound privilege wisely. Listen to women. Listen to minorities, listen to immigrants, the unhoused, the less economically advantaged, and the less technologically-literate. Listen to the underrepresented and the underprivileged.\nSubverted design is a huge problem, likely one that will never completely go away. However, the more of us who put the hard work into being the villain, the more we can lessen the scope of its impact.", "year": "2018", "author": "Eric Bailey", "author_slug": "ericbailey", "published": "2018-12-06T00:00:00+00:00", "url": "https://24ways.org/2018/be-the-villain/", "topic": "ux"} {"rowid": 242, "title": "Creating My First Chrome Extension", "contents": "Writing a Chrome Extension isn\u2019t as scary at it seems!\nNot too long ago, I used a Chrome extension called 20 Cubed. I\u2019m far-sighted, and being a software engineer makes it difficult to maintain distance vision. So I used 20 Cubed to remind myself to look away from my screen and rest my eyes. I loved its simple interface and design. I loved it so much, I often forgot to turn it off in the middle of presentations, where it would take over my entire screen. Oops.\nUnfortunately, the developer stopped updating the extension and removed it from Chrome\u2019s extension library. I was so sad. None of the other eye rest extensions out there matched my design aesthetic, so I decided to create my own! Want to do the same?\nFortunately, Google has some respectable documentation on how to create an extension. And remember, Chrome extensions are just HTML, CSS, and JavaScript. You can add libraries and frameworks, or you can just code the \u201cold-fashioned\u201d way. Sky\u2019s the limit!\nSetup\nBut first, some things you\u2019ll need to know about before getting started:\n\nCallbacks\nTimeouts\nChrome Dev Tools\n\nDeveloping with Chrome extension methods requires a lot of callbacks. If you\u2019ve never experienced the joy of callback hell, creating a Chrome extension will introduce you to this concept. However, things can get confusing pretty quickly. I\u2019d highly recommend brushing up on that subject before getting started.\nHyperbole and a Half\nTimeouts and Intervals are another thing you might want to brush up on. While creating this extension, I didn\u2019t consider the fact that I\u2019d be juggling three timers. And I probably would\u2019ve saved time organizing those and reading up on the Chrome extension Alarms documentation beforehand. But more on that in a bit.\nOn the note of organization, abstraction is important! You might have any combination of the following:\n\nThe Chrome extension options page\nThe popup from the Chrome Menu\nThe windows or tabs you create\nThe background scripts\n\nAnd that can get unwieldy. You might also edit the existing tabs or windows in the browser, which you\u2019ll probably want as a separate script too. Note that this tutorial only covers creating your own customized window rather than editing existing windows or tabs.\nAlright, now that you know all that up front, let\u2019s get going!\nDocumentation\nTL;DR READ THE DOCS.\nA few things to get started:\n\nRead Google\u2019s primer on browser extensions\nHave a look at their Getting started tutorial\nCheck out their overview on Chrome Extensions\n\nThis overview discusses the Chrome extension files, architecture, APIs, and communication between pages. Funnily enough, I only discovered the Overview page after creating my extension.\nThe manifest.json file gives the browser information about the extension, including general information, where to find your extension files and icons, and API permissions required. Here\u2019s what my manifest.json looked like, for example:\nhttps://github.com/jennz0r/eye-rest/blob/master/manifest.json\nBecause I\u2019m a visual learner, I found the images that describe the extension\u2019s architecture most helpful.\n\nTo clarify this diagram, the background.js file is the extension\u2019s event handler. It\u2019s constantly listening for browser events, which you\u2019ll feed to it using the Chrome Extension API. Google says that an effective background script is only loaded when it is needed and unloaded when it goes idle.\nThe Popup is the little window that appears when you click on an extension\u2019s icon in the Chrome Menu. It consists of markup and scripts, and you can tell the browser where to find it in the manifest.json under page_action: { \"default_popup\": FILE_NAME_HERE }.\nThe Options page is exactly as it says. This displays customizable options only visible to the user when they either right-click on the Chrome menu and choose \u201cOptions\u201d under an extension. This also consists of markup and scripts, and you can tell the browser where to find it in the manifest.json under options_page: FILE_NAME_HERE.\nContent scripts are any scripts that will interact with any web windows or tabs that the user has open. These scripts will also interact with any tabs or windows opened by your extension.\nDebugging\nA quick note: don\u2019t forget the debugging tutorial!\nJust like any other Chrome window, every piece of an extension has an inspector and dev tools. If (read: when) you run into errors (as I did), you\u2019re likely to have several inspector windows open \u2013 one for the background script, one for the popup, one for the options, and one for the window or tab the extension is interacting with.\nFor example, I kept seeing the error \u201cThis request exceeds the MAX_WRITE_OPERATIONS_PER_HOUR quota.\u201d Well, it turns out there are limitations on how often you can sync stored information.\nAnother error I kept seeing was \u201cAlarm delay is less than minimum of 1 minutes. In released .crx, alarm \u201cALARM_NAME_HERE\u201d will fire in approximately 1 minutes\u201d. Well, it turns out there are minimum interval times for alarms.\nChrome Extension creation definitely benefits from debugging skills. Especially with callbacks and listeners, good old fashioned console.log can really help!\nMe adding a ton of `console.log`s while trying to debug my alarms.\nEye Rest Functionality\nOk, so what is the extension I created? Again, it\u2019s a way to rest your eyes every twenty minutes for twenty seconds. So, the basic functionality should look like the following:\n\nIf the extension is running AND\nIf the user has not clicked Pause in the Popup HTML AND\nIf the counter in the Popup HTML is down to 00:00 THEN\n\nOpen a new window with Timer HTML AND\nStart a 20 sec countdown in Timer HTML AND\nReset the Popup HTML counter to 20:00\n\nIf the Timer HTML is down to 0 sec THEN\n\nClose that window. Rinse. Repeat.\n\n\nSounds simple enough, but wow, these timers became convoluted! Of all the Chrome extensions I decided to create, I decided to make one that\u2019s heavily dependent on time, intervals, and having those in sync with each other. In other words, I made this unnecessarily complicated and didn\u2019t realize until I started coding.\nFor visual reference of my confusion, check out the GitHub repository for Eye Rest. (And yes, it\u2019s a pun.)\nAPI\nNow let\u2019s discuss the APIs that I used to build this extension.\nAlarms\nWhat even are alarms? I didn\u2019t know either.\nAlarms are basically Chrome\u2019s setTimeout and setInterval. They exist because, as Google says\u2026\n\nDOM-based timers, such as window.setTimeout() or window.setInterval(), are not honored in non-persistent background scripts if they trigger when the event page is dormant.\n\nFor more information, check out this background migration doc.\nOne interesting note about alarms in Chrome extensions is that they are persistent. Garbage collection with Chrome extension alarms seems unreliable at best. I didn\u2019t have much luck using the clearAll method to remove alarms I created on previous extension loads or installs. A workaround (read: hack) is to specify a unique alarm name every time your extension is loaded and clearing any other alarms without that unique name.\nBackground Scripts\nFor Eye Rest, I have two background scripts. One is my actual initializer and event listener, and the other is a helpers file.\nI wanted to share a couple of functions between my Background and Popup scripts. Specifically, the clearAndCreateAlarm function. I wanted my background script to clear any existing alarms, create a new alarm, and add remaining time until the next alarm to local storage immediately upon extension load. To make the function available to the Background script, I added helpers.js as the first item under background > scripts in my manifest.json.\nI also wanted my Popup script to do the same things when the user has unpaused the extension\u2019s functionality. To make the function available to the Popup script, I just include the helpers script in the Popup HTML file.\nOther APIs\nWindows\nI use the Windows API to create the Timer window when the time of my alarm is up. The window creation is initiated by my Background script.\nOne day, while coding late into the evening, I found it very confusing that the window.create method included url as an option. I assumed it was meant to be an external web address. A friend pondered that there must be an option to specify the window\u2019s HTML. Until then, it hadn\u2019t dawned on me that the url could be relative. Duh. I was tired!\nI pass the timer.html as the url option, as well as type, size, position, and other visual options.\nStorage\nMaybe you want to pass information back and forth between the Background script and your Popup script? You can do that using Chrome or local storage. One benefit of using local storage over Chrome\u2019s storage is avoiding quotas and write operation maximums.\nI wanted to pass the time at which the latest alarm was set, the time to the next alarm, and whether or not the timer is paused between the Background and Popup scripts. Because the countdown should change every second, it\u2019s quite complicated and requires lots of writes. That\u2019s why I went with the user\u2019s local storage. You can see me getting and setting those variables in my Background, Helper, and Popup scripts. Just search for date, nextAlarmTime, and isPaused.\nDeclarative Content\nThe Declarative Content API allows you to show your extension\u2019s page action based on several type of matches, without needing to take a host permission or inject a content script. So you\u2019ll need this to get your extension to work in the browser!\nYou can see me set this in my Background script. Because I want my extension\u2019s popup to appear on every page one is browsing, I leave the page matchers empty.\nThere are many more APIs for Chrome apps and extensions, so make sure to surf around and see what features are available!\nThe Extension\nHere\u2019s what my original Popup looked like before I added styles.\nAnd here\u2019s what it looks like with new styles. I guess I\u2019m going for a Nickelodeon feel.\nAnd here\u2019s the Timer window and Popup together! \nPublishing\nPublishing is a cinch. You just zip up your files, create a new or use an existing Google Developer account, upload the files, add some details, and pay a one time $5 fee. That\u2019s all! Then your extension will be available on the Chrome extension store! Neato :D\nMy extension is now available for you to install.\nConclusion\nI thought creating a time based Chrome Extension would be quick and easy. I was wrong. It was more complicated than I thought! But it\u2019s definitely achievable with some time, persistence, and good ole Google searches.\nEventually, I\u2019d like to add more interactive elements to Eye Rest. For example, hitting the YouTube API to grab a silly or cute video as a reward for looking away during the 20 sec countdown and not closing the timer window. This harkens back to one of my first web projects, Toothtimer, from 2012. Or maybe a way to change the background colors of the Timer and Popup!\nEither way, with Eye Rest\u2019s framework built out, I\u2019m feeling fearless about future feature adds! Building this Chrome extension took some broken nails, achy shoulders, and tired eyes, but now Eye Rest can tell me to give my eyes a break every 20 minutes.", "year": "2018", "author": "Jennifer Wong", "author_slug": "jenniferwong", "published": "2018-12-05T00:00:00+00:00", "url": "https://24ways.org/2018/my-first-chrome-extension/", "topic": "code"} {"rowid": 258, "title": "Mistletoe Offline", "contents": "It\u2019s that time of year, when we gather together as families to celebrate the life of the greatest person in history. This man walked the Earth long before us, but he left behind words of wisdom. Those words can guide us every single day, but they are at the forefront of our minds during this special season.\nI am, of course, talking about Murphy, and the golden rule he gave unto us:\n\nAnything that can go wrong will go wrong.\n\nSo true! I mean, that\u2019s why we make sure we\u2019ve got nice 404 pages. It\u2019s not that we want people to ever get served a File Not Found message, but we acknowledge that, despite our best efforts, it\u2019s bound to happen sometime. Murphy\u2019s Law, innit?\nBut there are some Murphyesque situations where even your lovingly crafted 404 page won\u2019t help. What if your web server is down? What if someone is trying to reach your site but they lose their internet connection? These are all things than can\u2014and will\u2014go wrong.\nI guess there\u2019s nothing we can do about those particular situations, right?\nWrong!\nA service worker is a Murphy-battling technology that you can inject into a visitor\u2019s device from your website. Once it\u2019s installed, it can intercept any requests made to your domain. If anything goes wrong with a request\u2014as is inevitable\u2014you can provide instructions for the browser. That\u2019s your opportunity to turn those server outage frowns upside down. Take those network connection lemons and make network connection lemonade.\nIf you\u2019ve got a custom 404 page, why not make a custom offline page too?\nGet your server in order\nStep one is to make \u2026actually, wait. There\u2019s a step before that. Step zero. Get your site running on HTTPS, if it isn\u2019t already. You won\u2019t be able to use a service worker unless everything\u2019s being served over HTTPS, which makes sense when you consider the awesome power that a service worker wields.\nIf you\u2019re developing locally, service workers will work fine for localhost, even without HTTPS. But for a live site, HTTPS is a must.\nMake an offline page\nAlright, assuming your site is being served over HTTPS, then step one is to create an offline page. Make it as serious or as quirky as is appropriate for your particular brand. If the website is for a restaurant, maybe you could put the telephone number and address of the restaurant on the custom offline page (unsolicited advice: you could also put this on the home page, you know). Here\u2019s an example of the custom offline page for this year\u2019s Ampersand conference.\nWhen you\u2019re done, publish the offline page at suitably imaginative URL, like, say /offline.html.\nPre-cache your offline page\nNow create a JavaScript file called serviceworker.js. This is the script that the browser will look to when certain events are triggered. The first event to handle is what to do when the service worker is installed on the user\u2019s device. When that happens, an event called install is fired. You can listen out for this event using addEventListener:\naddEventListener('install', installEvent => {\n// put your instructions here.\n}); // end addEventListener\nIn this case, you want to make sure that your lovingly crafted custom offline page is put into a nice safe cache. You can use the Cache API to do this. You get to create as many caches as you like, and you can call them whatever you want. Here, I\u2019m going to call the cache Johnny just so I can refer to it as JohnnyCache in the code:\naddEventListener('install', installEvent => {\n installEvent.waitUntil(\n caches.open('Johnny')\n .then( JohnnyCache => {\n JohnnyCache.addAll([\n '/offline.html'\n ]); // end addAll\n }) // end open.then\n ); // end waitUntil\n}); // end addEventListener\nI\u2019m betting that your lovely offline page is linking to a CSS file, maybe an image or two, and perhaps some JavaScript. You can cache all of those at this point:\naddEventListener('install', installEvent => {\n installEvent.waitUntil(\n caches.open('Johnny')\n .then( JohnnyCache => {\n JohnnyCache.addAll([\n '/offline.html',\n '/path/to/stylesheet.css',\n '/path/to/javascript.js',\n '/path/to/image.jpg'\n ]); // end addAll\n }) // end open.then\n ); // end waitUntil\n}); // end addEventListener\nMake sure that the URLs are correct. If just one of the URLs in the list fails to resolve, none of the items in the list will be cached.\nIntercept requests\nThe next event you want to listen for is the fetch event. This is probably the most powerful\u2014and, let\u2019s be honest, the creepiest\u2014feature of a service worker. Once it has been installed, the service worker lurks on the user\u2019s device, waiting for any requests made to your site. Every time the user requests a web page from your site, a fetch event will fire. Every time that page requests a style sheet or an image, a fetch event will fire. You can provide instructions for what should happen each time:\naddEventListener('fetch', fetchEvent => {\n// What happens next is up to you!\n}); // end addEventListener\nLet\u2019s write a fairly conservative script with the following logic:\n\nWhenever a file is requested,\nFirst, try to fetch it from the network,\nBut if that doesn\u2019t work, try to find it in the cache,\nBut if that doesn\u2019t work, and it\u2019s a request for a web page, show the custom offline page instead.\n\nHere\u2019s how that translates into JavaScript:\n// Whenever a file is requested\naddEventListener('fetch', fetchEvent => {\n const request = fetchEvent.request;\n fetchEvent.respondWith(\n // First, try to fetch it from the network\n fetch(request)\n .then( responseFromFetch => {\n return responseFromFetch;\n }) // end fetch.then\n // But if that doesn't work\n .catch( fetchError => {\n // try to find it in the cache\n caches.match(request)\n .then( responseFromCache => {\n if (responseFromCache) {\n return responseFromCache;\n // But if that doesn't work\n } else {\n // and it's a request for a web page\n if (request.headers.get('Accept').includes('text/html')) {\n // show the custom offline page instead\n return caches.match('/offline.html');\n } // end if\n } // end if/else\n }) // end match.then\n }) // end fetch.catch\n ); // end respondWith\n}); // end addEventListener\nI am fully aware that I may have done some owl-drawing there. If you need a more detailed breakdown of what\u2019s happening at each point in the code, I\u2019ve written a whole book for you. It\u2019s the perfect present for Murphymas.\nHook up your service worker script\nYou can publish your service worker script at /serviceworker.js but you still need to tell the browser where to look for it. You can do that using JavaScript. Put this in an existing JavaScript file that you\u2019re calling in to every page on your site, or add this in a script element at the end of every page\u2019s HTML:\nif (navigator.serviceWorker) {\n navigator.serviceWorker.register('/serviceworker.js');\n}\nThat tells the browser to start installing the service worker, but not without first checking that the browser understands what a service worker is. When it comes to JavaScript, feature detection is your friend.\nYou might already have some JavaScript files in a folder like /assets/js/ and you might be tempted to put your service worker script in there too. Don\u2019t do that. If you do, the service worker will only be able to handle requests made to for files within /assets/js/. By putting the service worker script in the root directory, you\u2019re making sure that every request can be intercepted.\nGo further!\nNicely done! You\u2019ve made sure that if\u2014no, when\u2014a visitor can\u2019t reach your website, they\u2019ll get your hand-tailored offline page. You have temporarily defeated the forces of chaos! You have briefly fought the tide of entropy! You have made a small but ultimately futile gesture against the inevitable heat-death of the universe!\nThis is just the beginning. You can do more with service workers.\nWhat if, every time you fetched a page from the network, you stored a copy of that page in a cache? Then if that person tries to reach that page later, but they\u2019re offline, you could show them the cached version.\nOr, what if instead of reaching out the network first, you checked to see if a file is in the cache first? You could serve up that cached version\u2014which would be blazingly fast\u2014and still fetch a fresh version from the network in the background to pop in the cache for next time. That might be a good strategy for images.\nSo many options! The hard part isn\u2019t writing the code, it\u2019s figuring out the steps you want to take. Once you\u2019ve got those steps written out, then it\u2019s a matter of translating them into JavaScript.\nInevitably there will be some obstacles along the way\u2014usually it\u2019s a misplaced curly brace or a missing parenthesis. Don\u2019t be too hard on yourself if your code doesn\u2019t work at first. That\u2019s just Murphy\u2019s Law in action.", "year": "2018", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2018-12-04T00:00:00+00:00", "url": "https://24ways.org/2018/mistletoe-offline/", "topic": "code"} {"rowid": 245, "title": "Web Content Accessibility Guidelines 2.1\u2014for People Who Haven\u2019t Read the Update", "contents": "Happy United Nations International Day of Persons with Disabilities 2018! The United Nations chose \u201cEmpowering persons with disabilities and ensuring inclusiveness and equality\u201d as this year\u2019s theme. We\u2019ve seen great examples of that in 2018; for example, Paul Robert Lloyd has detailed how he improved the accessibility of this very website. \nOn 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, \u201cCaptions (Live)\u201d of the Web Content Accessibility Guidelines (figure 1) \u2026and British Vogue Contributing Editor Sin\u00e9ad 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, \u201cSign Language (Prerecorded)\u201d of the Web Content Accessibility Guidelines (figure 2).\n\nFigure 1: Screenshot of Alexandria Ocasio-Cortez\u2019s Instagram story with live captionsFigure 2: Screenshot of Sin\u00e9ad Burke\u2019s Instagram story with Sign Language Interpretation\nThat theme chimes with this year\u2019s publication of the World Wide Web Consortium (W3C)\u2019s Web Content Accessibility Guidelines (WCAG) 2.1. In last year\u2019s \u201cWeb Content Accessibility Guidelines\u2014for People Who Haven\u2019t Read Them\u201d, I mentioned the scale of the project to produce this update during 2018: \u201cthe editors have to update the guidelines to cover all the new ways that people interact with new technologies, while keeping the guidelines backwards-compatible\u201d. \nThe WCAG working group have added 17 success criteria to the 61 that they released way back in 2008\u2014for context, that was 1\u00bd 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. \nOnce again, let\u2019s rip off all the legalese and ambiguous terminology like wrapping paper, and get up to date.\nCan your users perceive the information on your website?\nThe first guideline has criteria that help you prevent your users from asking, \u201cWhat the **** is this thing here supposed to be?\u201d We\u2019ve seven new criteria for this guideline.\n1.3.4 Some people can\u2019t 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\u2014and expect your users to do likewise with your websites and apps. We\u2019ve had 18\u00bd years since John Allsopp\u2019s revelatory Dao of Web Design enlightened us to \u201cembrace the fact that the web doesn\u2019t have the same constraints\u201d as printed pages, and to \u201cdesign for this flexibility\u201d. So, even though this guideline doesn\u2019t apply to websites where \u201ca specific display orientation is essential,\u201d such as a piano tutorial, always ask yourself, \u201cWhat would John Allsopp do?\u201d\n1.3.5 You should help the user\u2019s browser to automatically complete\u2013or not complete\u2013form 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\u2019ve used microformats or microdata to mark up information about a person, the autocomplete attribute\u2019s range of values should seem familiar. I like how the W3\u2019s \u201cUsing HTML 5.2 autocomplete attributes\u201d says that autocompleted values in forms help \u201cthose 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\u201d (emphasis mine). Um\u2026\ud83d\ude4b\u200d\u2642\ufe0f\n1.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\u2019s ongoing work on Personalisation Semantics.\n1.4.10 If you were to find a Nintendo Switch and \u201cSuper Mario Odyssey\u201d 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\u2019re 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\u2019t 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\u2014better yet\u2014test it with real users.\n1.4.11 In \u201cWeb Content Accessibility Guidelines\u2014for People Who Haven\u2019t Read Them\u201d, I recommended bookmarking Lea Verou\u2019s 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\u2019t apply to controls that use the browser\u2019s default styling. Also, you should make sure that graphics that convey information have a 3:1 contrast ratio with the colour around them.\n1.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:\n\nline height to at least 1\u00bd \u00d7 the font size;\nspace below paragraphs to at least 2 \u00d7 the font size;\nletter spacing to at least 0.12 \u00d7 the font size;\nword spacing to at least 0.16 \u00d7 the font size.\n\nTo test this, check for text overlapping, text hiding behind other elements, or text disappearing.\n1.4.13 Sometimes when visiting a website, you hover over\u2014or tab on to\u2014something that unleashes a newsletter subscription pop-up, some suggested \u201crelated content\u201d, 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 \u201cClose\u201d button or \u201cX\u201d button to vanquish such intrusions. If the Esc key fails you, or if you either can\u2019t see or can\u2019t click the \u201cClose\u201d button\u2026well, you\u2019ll 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:\n\nyour user can dismiss that content without needing to move their pointer or tab on to some other element (this doesn\u2019t apply to error warnings, or well-behaved content that doesn\u2019t obscure or replace other content);\nthe new content remains visible while your user moves their cursor over it;\nthe new content remains visible as long as the user hovers over that element or dismisses that content\u2014or until the new content is no longer valid.\n\nThis doesn\u2019t apply to situations such as hovering over an element\u2019s title attribute, where the user\u2019s browser controls the display of the content that appears.\nCan users operate the controls and links on your website?\nThe second guideline has criteria that help you prevent your users from asking, \u201cHow the **** does this thing work?\u201d We\u2019ve nine new criteria for this guideline.\n2.1.4 Some websites offer keyboard shortcuts for users. For example, the keyboard shortcuts for Gmail allow the user to press the \u21e7 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\u2019t apply to single-character keyboard shortcuts that only work when a control, such as drop-down list, has focus.\n2.2.6 If your website uses a timeout for some process, you could store the user\u2019s 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. \n2.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 \u201cReduce Motion\u201d setting (or equivalent) in their device\u2019s operating system:\n@media (prefers-reduced-motion: reduce) {\n .MrFancyPants {\n animation: none;\n }\n}\n2.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 \u201cunpinch\u201d 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.\n2.5.2 This might be my favourite accessibility criterion ever! Did you ever touch or press a \u201cSend\u201d button but then immediately realise that you really didn\u2019t want to send the message, and so move your finger or cursor away from the \u201cSend\u201d button before lifting your finger?! Imagine how many arguments that functionality has prevented. \ud83d\ude0c 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\u2019t apply to actions that need to happen as soon as the user clicks or touches. For example, a user playing a \u201cWhac-A-Mole\u201d game or a piano emulator needs the action to happen as soon as they click or touch the screen.\n2.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:\n\nuse the label element to pair text with the corresponding input element;\nuse an alt attribute value that exactly matches any text that appears in an image;\nuse an aria-labelledby attribute value that exactly matches the text that appears in any complex component.\n\n2.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\u2019t apply to websites that require shaking, tilting, or gesturing; this includes some games and music programmes. John Gruber describes the iPhone\u2019s \u201cShake to Undo\u201d gesture as \u201cdreadful \u2014 impossible to discover through exploration of the on-screen [user interface], bad for accessibility, and risks your phone flying out of your hand\u201d. 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.\n2.5.5 Homer Simpson\u2019s telephone famously complained, \u201cThe fingers you have used to dial are too fat.\u201d I think we\u2019ve 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 \u00d7 44px high. Apple\u2019s \u201cHuman Interface Guidelines\u201d agree: \u201cProvide ample touch targets for interactive elements. Try to maintain a minimum tappable area of 44pt x 44pt for all controls.\u201d This doesn\u2019t apply to links within inline text, or to unsoiled elements.\n2.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\u2019t apply to websites that require a specific modality; this includes typing tutors and music programmes.\nCan users understand your content?\nThe third guideline has criteria that help you prevent your users from asking, \u201cWhat the **** does this mean?\u201d We\u2019ve no new criteria for this guideline. \nHave you made your website robust enough to work on your users\u2019 browsers and assistive technologies?\nThe fourth and final guideline has criteria that help you prevent your users from asking, \u201cWhy the **** doesn\u2019t this work on my device?\u201d We\u2019ve one new criterion for this guideline.\n4.1.3 Sometimes you need to let your user know the status of something: \u201cDid it work OK? What was the error? How far through it are we?\u201d 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: \n\nif your user needs to know, \u201cDid it work OK?\u201d, add role=\"status\u201d;\nif your user needs to know, \u201cWhat was the error?\u201d, add role=\"alert\u201d;\nif you user needs to know, \u201cHow far through it are we?\u201d, add role=\"log\" (for a chat window) or role=\"progressbar\" (for, well, a progress bar).\n\nBetter design for humans\nMy favourite of Luke Wroblewski\u2019s collection of Design Quotes is, \u201cDesign is the art of gradually applying constraints until only one solution remains,\u201d from that most prolific author, \u201cUnknown\u201d. I\u2019ve 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.\nSpending those book vouchers you got for Christmas\nWhat next? If you\u2019re looking for something to do to keep you busy this Christmas, I thoroughly recommend these four books for increasing your accessibility expertise:\n\n\u201cPro HTML5 Accessibility\u201d 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\u2014a long time in web design\u2014I 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.\n\u201cA Web for Everyone\u2014Designing Accessible User Experiences\u201d by Sarah Horton (the Paciello Group\u2019s UX Strategy Lead) and Whitney Quesenbery (the Center for Civic Design\u2019s 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\u2014including some 24ways authors\u2014keep its content practical and relevant throughout.\n\u201cAccessibility For Everyone\u201d by Laura Kalbag (Ind.ie\u2019s 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\u2014as 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\u2014in less than four hours.\n\u201cJust Ask: Integrating Accessibility Throughout Design\u201d by Shawn Lawton Henry (the World Wide Web Consortium (W3C)\u2019s Web Accessibility Initiative (WAI)\u2019s Outreach Coordinator): Although this book is 11\u00bd 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.", "year": "2018", "author": "Alan Dalton", "author_slug": "alandalton", "published": "2018-12-03T00:00:00+00:00", "url": "https://24ways.org/2018/wcag-for-people-who-havent-read-the-update/", "topic": "ux"} {"rowid": 260, "title": "The Art of Mathematics: A Mandala Maker Tutorial", "contents": "In front-end development, there\u2019s often a great deal of focus on tools that aim to make our work more efficient. But what if you\u2019re new to web development? When you\u2019re just starting out, the amount of new material can be overwhelming, particularly if you don\u2019t have a solid background in Computer Science. But the truth is, once you\u2019ve learned a little bit of JavaScript, you can already make some pretty impressive things.\nA 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:\nMandala Maker user interface\nThe coolest part about it is the fact that it\u2019s a tool: anyone can use it to create something original and brand new. \nIn this tutorial, we\u2019ll build a smaller version of this app \u2013 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\u2019re done, you\u2019re on your own and can tweak it as you please. Be creative!\nPreparations: a blank canvas\nThe first thing you\u2019ll need for this project is a designated drawing space. We\u2019ll 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).\nFiles\nCreate 3 files: index.html, styles.css, main.js. Don\u2019t forget to include your JS and CSS files in your HTML. \n\n\n\n \n \n \n\n\n \n

Your browser doesn't support canvas.

\n
\n\n\nI\u2019ll ask you to update your HTML file at a later point, but the CSS file we\u2019ll start with will stay the same throughout the project. This is the full CSS we are going to use:\nbody {\n background-color: #ccc;\n text-align: center;\n}\n\ncanvas {\n touch-action: none;\n background-color: #fff;\n}\n\nbutton {\n font-size: 110%;\n}\nNext steps\nWe are done with our preparations and ready to move on to the actual tutorial, which is made up of 4 parts:\n\nBuilding a simple drawing app with one line and one color \nAdding a Clear button and a color picker\nAdding more functionality: 2 line drawing (add the first reflection)\nAdding more functionality: 8 line drawing (add 6 more reflections!)\n\nInteractive demos\nThis 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.\nPart 1: A simple drawing app\nLet\u2019s 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:\nvar canvas, context, w, h,\n prevX = 0, currX = 0, prevY = 0, currY = 0,\n draw = false;\nThe 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. \n1. init\nResponsible 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. \nfunction init() {\n canvas = document.querySelector(\"canvas\");\n context = canvas.getContext(\"2d\");\n w = canvas.width;\n h = canvas.height;\n\n canvas.onpointermove = handlePointerMove;\n canvas.onpointerdown = handlePointerDown;\n canvas.onpointerup = stopDrawing;\n canvas.onpointerout = stopDrawing;\n}\n2. drawLine\nThis 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.\nlineWidth 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).\nfunction drawLine() {\n var a = prevX,\n b = prevY,\n c = currX,\n d = currY;\n\n context.lineWidth = 4;\n context.lineCap = \"round\";\n\n context.beginPath();\n context.moveTo(a, b);\n context.lineTo(c, d);\n context.stroke();\n context.closePath();\n}\n3. stopDrawing\nThis is used by init when the pointer is not down (onpointerup) or is out of bounds (onpointerout).\nfunction stopDrawing() {\n draw = false;\n}\n4. recordPointerLocation\nThis tracks the pointer\u2019s 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.\nfunction recordPointerLocation(e) {\n prevX = currX;\n prevY = currY;\n currX = e.clientX - canvas.offsetLeft;\n currY = e.clientY - canvas.offsetTop;\n}\n5. handlePointerMove\nThis 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.\nfunction handlePointerMove(e) {\n if (draw) {\n recordPointerLocation(e);\n drawLine();\n }\n}\n6. handlePointerDown\nThis 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\u2019s because we only want movement events from handlePointerMove to cause drawing if the pointer is down.\nfunction handlePointerDown(e) {\n recordPointerLocation(e);\n draw = true;\n}\nFinally, we have a working drawing app. But that\u2019s just the beginning!\nSee the Pen Mandala Maker Tutorial: Part 1 by Hagar Shilo (@hagarsh) on CodePen.\n\nPart 2: Add a Clear button and a color picker\nNow we\u2019ll update our HTML file, adding a menu div with an input of the type and class color and a button of the class clear.\n\n \n

Your browser doesn't support canvas.

\n
\n
\n \n \n
\n\nColor picker\nThis is our new color picker function. It targets the input element by its class and gets its value. \nfunction getColor() {\n return document.querySelector(\".color\").value;\n}\nUp 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\u2019ll update drawLine by adding strokeStyle to it and setting it to the input value by calling getColor.\nfunction drawLine() {\n //...code... \n context.strokeStyle = getColor();\n context.lineWidth = 4;\n context.lineCap = \"round\";\n\n //...code... \n}\nClear button\nThis 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.\nfunction clearCanvas() {\n if (confirm(\"Want to clear?\")) {\n context.clearRect(0, 0, w, h);\n }\n}\nThe 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. \nIf 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.\nLet\u2019s add this event handler to init:\nfunction init() {\n //...code...\n canvas.onpointermove = handleMouseMove;\n canvas.onpointerdown = handleMouseDown;\n canvas.onpointerup = stopDrawing;\n canvas.onpointerout = stopDrawing;\n document.querySelector(\".clear\").onclick = clearCanvas;\n}\nSee the Pen Mandala Maker Tutorial: Part 2 by Hagar Shilo (@hagarsh) on CodePen.\n\nPart 3: Draw with 2 lines\nIt\u2019s time to make a line appear where no pointer has gone before. A ghost line! \nFor 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\u2019s going to go over the y-axis or the x-axis. Since this is an arbitrary decision, it doesn\u2019t matter which one we choose. Let\u2019s go with the x-axis. \nHere 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!). \nNow, 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.\nA sketch illustrating the mathematics of reflecting a point.\nWhat happens to the x coordinates?\nThe variables a/a' and c/c' correspond to prevX and currX respectively, so we can call them \u201cthe x coordinates\u201d. We are reflecting across x, so their values remain the same, and therefore a' = a and c' = c. \nWhat happens to the y coordinates?\nWhat 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.\nThis is the new code for the app\u2019s variables and the two lines: the one that fills the pointer\u2019s path and the one mirroring it across the x-axis.\nfunction drawLine() {\n var a = prevX, a_ = a,\n b = prevY, b_ = h-b,\n c = currX, c_ = c,\n d = currY, d_ = h-d;\n\n //... code ...\n\n // Draw line #1, at the pointer's location\n context.moveTo(a, b);\n context.lineTo(c, d);\n\n // Draw line #2, mirroring the line #1\n context.moveTo(a_, b_);\n context.lineTo(c_, d_);\n\n //... code ...\n}\nIn case this was too abstract for you, let\u2019s look at some actual numbers to see how this works.\nLet\u2019s say we have a tiny canvas of w = h = 10. Now let a = 3, b = 2, c = 4 and d = 3.\nSo b' = 10 - 2 = 8 and d' = 10 - 3 = 7.\nWe 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\u2019s 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.\nIf you are still confused, I don\u2019t blame you. \nHere is the result. Draw something and see what happens.\nSee the Pen Mandala Maker Tutorial: Part 3 by Hagar Shilo (@hagarsh) on CodePen.\n\nPart 4: Draw with 8 lines\nI have made yet another confusing sketch, with points C and D, so you understand what we\u2019re trying to do. Later on we\u2019ll look at points E, F, G and H as well. The circled point is the one we\u2019re 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. \nA sketch illustrating points C and D.\nThis is the part where the math gets a bit mathier, as our drawLine function evolves further. We\u2019ll keep using the four new coordinates: a', b', c' and d', and reassign their values for each new location/line. Let\u2019s 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).\nfunction drawLine() {\n\n //... code ... \n\n // Reassign values\n a_ = w-a; b_ = b;\n c_ = w-c; d_ = d;\n\n // Draw the 3rd line\n context.moveTo(a_, b_);\n context.lineTo(c_, d_);\n\n // Reassign values\n a_ = w-a; b_ = h-b;\n c_ = w-c; d_ = h-d;\n\n // Draw the 4th line\n context.moveTo(a_, b_);\n context.lineTo(c_, d_);\n\n //... code ... \nWhat is happening?\nYou 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\u2019s because we want the symmetry to hold for a rectangular canvas as well, and this way it will. \nAlso, 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\u2019s 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). \nWhat happens to the x coordinates?\nAs you recall, our x coordinates are a (prevX) and c (currX).\nFor the third line we are adding, a' = w - a and c' = w - c, which means\u2026\nFor the fourth line, the same thing happens to our x coordinates a and c.\nWhat happens to the y coordinates?\nAs you recall, our y coordinates are b (prevY) and d (currY).\nFor 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. \nFor the fourth line, b' = h - b and d' = h - d, which we\u2019ve seen before: that\u2019s a reflection across the x-axis.\nWe have four more lines, or locations, to define. Note: the part of the code that\u2019s responsible for drawing a micro-line between the newly calculated coordinates is always the same:\n context.moveTo(a_, b_);\n context.lineTo(c_, d_);\nWe can leave it out of the next code snippets and just focus on the calculations, i.e, the reassignments. \nOnce again, we need some concrete examples to see where we\u2019re going, so here\u2019s 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.\nA sketch illustrating points E and F.\nThis is the code for E and F:\n // Reassign for 5\n a_ = w/2+h/2-b; b_ = w/2+h/2-a;\n c_ = w/2+h/2-d; d_ = w/2+h/2-c;\n\n // Reassign for 6\n a_ = w/2+h/2-b; b_ = h/2-w/2+a;\n c_ = w/2+h/2-d; d_ = h/2-w/2+c;\nTheir x coordinates are identical and their y coordinates are reversed to one another.\nThis 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).\nA sketch illustrating points G and H.\nThis is the code:\n // Reassign for 7\n a_ = w/2-h/2+b; b_ = w/2+h/2-a;\n c_ = w/2-h/2+d; d_ = w/2+h/2-c;\n\n // Reassign for 8\n a_ = w/2-h/2+b; b_ = h/2-w/2+a;\n c_ = w/2-h/2+d; d_ = h/2-w/2+c;\n //...code... \n}\nOnce again, the x coordinates of these two points are the same, while the y coordinates are different. And once again I won\u2019t go into the full details, since this has been a long enough journey as it is, and I think we\u2019ve 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.\nI hope you had fun learning! This is our final app:\nSee the Pen Mandala Maker Tutorial: Part 4 by Hagar Shilo (@hagarsh) on CodePen.", "year": "2018", "author": "Hagar Shilo", "author_slug": "hagarshilo", "published": "2018-12-02T00:00:00+00:00", "url": "https://24ways.org/2018/the-art-of-mathematics/", "topic": "code"} {"rowid": 263, "title": "Securing Your Site like It\u2019s 1999", "contents": "Running a website in the early years of the web was a scary business. The web was an evolving medium, and people were finding new uses for it almost every day. From book stores to online auctions, the web was an expanding universe of new possibilities.\nAs the web evolved, so too did the knowledge of its inherent security vulnerabilities. Clever tricks that were played on one site could be copied on literally hundreds of other sites. It was a normal sight to log in to a website to find nothing working because someone had breached its defences and deleted its database. Lessons in web security in those days were hard-earned.\nWhat follows are examples of critical mistakes that brought down several early websites, and how you can help protect yourself and your team from the same fate.\nBad input validation: Trusting anything the user sends you\nOur story begins in the most unlikely place: Animal Crossing. Animal Crossing was a 2001 video game set in a quaint town, filled with happy-go-lucky inhabitants that co-exist peacefully. Like most video games, Animal Crossing was the subject of many fan communities on the early web.\nOne such unofficial web forum was dedicated to players discussing their adventures in Animal Crossing. Players could trade secrets, ask for help, and share pictures of their virtual homes. This might sound like a model community to you, but you would be wrong.\nOne day, a player discovered a hidden field in the forum\u2019s user profile form. Normally, this page allows users to change their name, their password, or their profile photo. This person discovered that the hidden field contained their unique user ID, which identifies them when the forum\u2019s backend saves profile changes to its database. They discovered that by modifying the form to change the user ID, they could make changes to any other player\u2019s profile.\nNeedless to say, this idyllic online community descended into chaos. Users changed each other\u2019s passwords, deleted each other\u2019s messages, and attacked each-other under the cover of complete anonymity. What happened?\nThere aren\u2019t any official rules for developing software on the web. But if there were, my golden rule would be:\nNever trust user input. Ever.\nAlways ask yourself how users will send you data that isn\u2019t what it seems to be. If the nicest community of gamers playing the happiest game on earth can turn on each other, nowhere on the web is safe.\nMake sure you validate user input to make sure it\u2019s of the correct type (e.g. string, number, JSON string) and that it\u2019s the length that you were expecting. Don\u2019t forget that user input doesn\u2019t become safe once it is stored in your database; any data that originates from outside your network can still be dangerous and must be escaped before it is inserted into HTML.\nMake sure to check a user\u2019s actions against what they are allowed to do. Create a clear access control policy that defines what actions a user may take, and to whose data they are allowed access to. For example, a newly-registered user should not be allowed to change the user profile of a web forum\u2019s owner.\nFinally, never rely on client-side validation. Validating user input in the browser is a convenience to the user, not a security measure. Always assume the user has full control over any data sent from the browser and make sure you validate any data sent to your backend from the outside world.\nSQL injection: Allowing the user to run their own database queries\nA long time ago, my favourite website was a web forum dedicated to the Final Fantasy video game series. Like the users of the Animal Crossing forum, I\u2019d while away many hours arguing with other people on the internet about my favourite characters, my favourite stories, and the greatest controversies of the day.\nOne day, I noticed people were acting strangely. Users were being uncharacteristically nasty and posting in private areas of the forum they wouldn\u2019t normally have access to. Then messages started disappearing, and user accounts for well-respected people were banned.\nIt turns out someone had discovered a way of logging in to any other user account, using a secret password that allowed them to do literally anything they wanted. What was this password that granted untold power to those who wielded it?\n' OR '1'='1\nSQL is a computer language that is used to query databases. When you fill out a login form, just like the one above, your username and your password are usually inserted into an SQL query like this:\n\nSELECT COUNT(*)\nFROM USERS\nWHERE USERNAME='Alice'\nAND PASSWORD='hunter2'\nThis query selects users from the database that match the username Alice and the password hunter2. If there is at least one user matching record, the user will be granted access. Let\u2019s see what happens when we use our magic password instead!\n\nSELECT COUNT(*)\nFROM USERS\nWHERE USERNAME='Admin'\nAND PASSWORD='' OR '1'='1'\nDoes the password look like part of the query to you? That\u2019s because it is! This password is a deliberate attempt to inject our own SQL into the query, hence the term SQL injection. The query is now looking for users matching the username Admin, with a password that is blank, or 1=1. In an SQL query, 1=1 is always true, which makes this query select every single record in the database. As long as the forum software is checking for at least one matching user, it will grant the person logging in access. This password will work for any user registered on the forum!\nSo how can you protect yourself from SQL injection?\nNever build SQL queries by concatenating strings. Instead, use parameterised query tools. PHP offers prepared statements, and Node.JS has the knex package. Alternatively, you can use an ORM tool, such as Propel or sequelize.\nExpert help in the form of language features or software tools is a key ally for securing your code. Get all the help you can!\nCross site request forgery: Getting other users to do your dirty work for you\nDo you remember Netflix? Not the Netflix we have now, the Netflix that used to rent you DVDs by mailing them to you. My next story is about how someone managed to convince Netflix users to send him their DVDs - free of charge.\nHave you ever clicked on a hyperlink, only to find something that you weren\u2019t expecting? If you were lucky, you might have just gotten Rickrolled. If you were unlucky\u2026\nLet\u2019s just say there are older and fouler things than Rick Astley in the dark places of the web.\nWhat if you could convince people to visit a page you controlled? And what if those people were Netflix users, and they were logged in? In 2006, Dave Ferguson did just that. He created a harmless-looking page with an image on it:\n\nDid you notice the source URL of the image? It\u2019s deliberately crafted to add a particular DVD to your queue. Sprinkle in a few more requests to change the user\u2019s name and shipping address, and you could ship yourself DVDs completely free of charge!\nThis attack is possible when websites unconditionally trust a user\u2019s session cookies without checking where HTTP requests come from.\nThe first check you can make is to verify that a request\u2019s origin and referer headers match the location of the website. These headers can\u2019t be programmatically set.\nAnother check you can use is to add CSRF tokens to your web forms, to verify requests have come from an actual form on your website. Tokens are long, unpredictable, unique strings that are generated by your server and inserted into web forms. When users complete a form, the form data sent to the server can be checked for a recently generated token. This is an effective deterrent of CSRF attacks because CSRF tokens aren\u2019t stored in cookies.\nYou can also set SameSite=Strict when setting cookies with the Set-Cookie HTTP header. This communicates to browsers that cookies are not to be sent with cross-site requests. This is a relatively new feature, though it is well supported in evergreen browsers.\nCross site scripting: Someone else\u2019s code running on your website\nIn 2005, Samy Kamkar became famous for having lots of friends. Lots and lots of friends.\nSamy enjoyed using MySpace which, at the time, was the world\u2019s largest social network. Social networks at that time were more limited than today. For instance, MySpace let you upload photos to your photo gallery, but capped the limit at twelve. Twelve photos. At least you didn\u2019t have to wade through photos of avocado toast back then\u2026\nSamy discovered that MySpace also locked down the kinds of content that you could post on your MySpace page. He discovered he could inject and
tags into his headline, but ',\n ''\n ];\n const filterResult = result => {\n if (ignoreErrors.indexOf(result.context) > -1) {\n return false;\n }\n return true;\n };\nInitially we wanted to focus on fixing the major problems, so we added a rule to ignore notices and warnings. This made the list or errors much smaller and allowed us focus on fixing major issues such as colour contrast and missing alt text. The ignored notices and warnings can be added in later after these larger issues have been resolved. \nconst test = pa11y({\n ignore: [\n 'notice',\n 'warning'\n ],\n...\n});\nJenkins gotchas\nWhile using Jenkins we encountered a few problems. Sometimes Jenkins would indicate a build had passed when in reality it had failed. This was because Pa11y had timed out due to PhantomJS throwing an error, or the test didn\u2019t go past the first URL. Pa11y has recently released a new beta version that uses headless Chrome instead of PhantomJS, so hopefully these issues will less occur less often. \nWe tried a few approaches to solve these issues. First we added error handling, iterating over the array of test URLs so that if an unexpected error happened, we could catch it and exit the process with an error indicating that the job had failed (using process.exit(1)). \nfor (const url of urls) {\n try {\n console.log(url);\n let urlResult = await run(url);\n urlResult = urlResult.filter(filterResult);\n urlResult.forEach(result => console.log(result));\n }\n catch (e) {\n console.log('Error:', e);\n process.exit(1);\n }\n}\nWe also had issues with unhandled rejections sometimes caused by a session disconnecting or similar errors. To avoid Jenkins indicating our site was passing with 100% accessibility, when in reality it had not executed any tests, we instructed Jenkins to fail the job when an unhandled rejection or uncaught exception occurred:\nprocess.on('unhandledRejection', (reason, p) => {\n console.log('Unhandled Rejection at:', p, 'reason:', reason);\n process.exit(1);\n});\nprocess.on('uncaughtException', (err) => {\n console.log('Caught exception: ${err}n');\n process.exit(1);\n});\nNow it\u2019s your turn\nThat\u2019s it! That\u2019s how we automated accessibility testing for Elsevier ecommerce pages, allowing us to improve our site and make it more accessible for everyone. I hope our experience can help you automate accessibility tests on your own site, and bring the web a step closer to being accessible to all.", "year": "2017", "author": "Seren Davies", "author_slug": "serendavies", "published": "2017-12-07T00:00:00+00:00", "url": "https://24ways.org/2017/automating-your-accessibility-tests/", "topic": "code"} {"rowid": 196, "title": "Designing a Remote Project", "contents": "I came across an article recently, which I have to admit made my blood boil a little. Yes, I know it\u2019s the season of goodwill and all that, and I\u2019m going to risk sounding a little Scrooge-like, but I couldn\u2019t help it. It was written by someone who\u2019d tried out \u2018telecommuting\u2019 (big sigh) a.k.a. remote or distributed working. They\u2019d tested it in their company and decided it didn\u2019t work. \nWhy did it enrage me so much? Well, this person sounded like they\u2019d almost set it up to fail. To them, it was the latest buzzword, and they wanted to offer their employees a \u2018perk\u2019. But it was going to be risky, because, well, they just couldn\u2019t trust their employees not to be lazy and sit around in their pyjamas at home, watching TV, occasionally flicking their mousepad to \u2018appear online\u2019. Sounds about right, doesn\u2019t it?\nWell, no. This attitude towards remote working is baked in the past, where working from one office and people all sitting around together in a cosy circle singing kum-by-yah* was a necessity not an option. We all know the reasons remote working and flexibility can happen more easily now: fast internet, numerous communication channels, and so on. But why are companies like Yahoo! and IBM backtracking on this? Why is there still such a negative perception of this way of working when it has so much real potential for the future?\n*this might not have ever really happened in an office.\nSo what is remote working? It can come in various formats. It\u2019s actually not just the typical office worker, working from home on a specific day. The nature of digital projects has been changing over a number of years. In this era where organisations are squeezing budgets and trying to find the best value wherever they can, it seems that the days of whole projects being tackled by one team, in the same place, is fast becoming the past. What I\u2019ve noticed more recently is a much more fragmented way of putting together a project \u2013 a mixture of in-house and agency, or multiple agencies or organisations, or working with an offshore team. In the past we might have done the full integrated project from beginning to end, now, it\u2019s a piece of the pie. \nWhich means that everyone is having to work with people who aren\u2019t sat next to them even more than before. Whether that\u2019s a freelancer you\u2019re working with who\u2019s not in the office, an offshore agency doing development or a partner company in another city tackling UX\u2026 the future is looking more and more like a distributed workplace.\nSo why the negativity, man?\nAs I\u2019ve seen from this article, and from examples of large corporations changing their entire philosophy away from remote working, there\u2019s a lot of negativity towards this way of working. Of course if you decide to let everyone work from home when they want, set them off and then expect them all to check in at the right time or be available 24/7 it\u2019s going to be a bit of a mess. Equally if you just jump into work with a team on the other side of the world without any setup, should you expect anything less than a problematic project?\nOkay, okay so what about these people who are going to sit on Facebook all day if we let them work from home? It\u2019s the age old response to the idea of working from home. I can\u2019t see the person, so how do I know what they are doing?\nThis comes up regularly as one of the biggest fears of letting people work remotely. There\u2019s also the perceived lack of productivity and distractions at home. The limited collaboration and communication with distributed workers. The lack of availability. The lower response times. \nHang on a second, can\u2019t these all still be problems even if you\u2019ve got your whole team sat in the same place? \u201cThey won\u2019t focus on work.\u201d How many people will go on Facebook or Twitter whilst sat in an office? \u201cThey won\u2019t collaborate as much.\u201d How many people sit in the office with headphones on to block out distractions? I think we have to move away from the idea that being sat next to people automatically makes them work harder. If the work is satisfying, challenging, and relevant to a person \u2013 surely we should trust them to do it, wherever they are sat?\nThere\u2019s actually a lot of benefits to remote working, and having distributed teams. Offering this as a way of working can attract and retain employees, due to the improved flexibility. There can actually be fewer distractions and disruptions at home, which leads to increased productivity. To paraphrase Jason Fried in his talk \u2018Why work doesn\u2019t happen at work\u2019, at home there are voluntary distractions where you have to choose to distract yourself with something. At the office these distractions become involuntary. Impromptu meetings and people coming to talk to you all the time are actually a lot more disruptive. Often, people find it easier to focus away from the office environment. \nThere\u2019s also the big benefit for a lot of people of the time saved commuting. The employee can actually do a lot that\u2019s beneficial to them in this time, rather than standing squeezed into people\u2019s armpits on public transport. Hence increased job satisfaction. With a distributed team, say if you\u2019re working with an off-shore team, there could be a wider range of talent to pick from and it also encourages diversity. There can be a wider range of cultural differences and opinions brought to a project, which encourages more diverse ways of thinking.\nTackling the issues - or, how to set up a project with a remote team\nBut that isn\u2019t to say running projects with a distributed team or being a remote worker is easy, and can just happen, like that. It needs work \u2013 and good groundwork \u2013 to ensure you don\u2019t set it up to fail. So how do you help create a smoother remote project?\nStart with trust\nFirst of all, the basis of the team needs to be trust. Yes I\u2019m going to sound a little like a cheesy, self-help guru here (perhaps in an attempt to seem less Scrooge-like and inject some Christmas cheer) but you do need to trust the people working remotely as well as them trusting you. This extends to a distributed team. You can\u2019t just tell the offshore team what to do, and micromanage them, scared they won\u2019t do what you want, how you want it because you can\u2019t see them. You need to give them ownership and let them manage the tasks. Remember, people are less likely to criticise their own work. Make them own the work and they are more likely to be engaged and productive.\nSet a structure\nDistributed teams and remote workers can fail when there is no structure \u2013 just as much as teams sitting together fail without it too. It\u2019s not so much setting rules, as having a framework to work within. Eliminate blockers before they happen. Think about what could cause issues for the team, and think of ways to solve this. For example, what do you do if you won\u2019t be able to get hold of someone for a few hours because of a time difference? Put together a contingency, e.g. is there someone else on your time zone you could go to with queries after assessing the priority? Would it be put aside until that person is back in? Define team roles and responsibilities clearly. Sit down at the beginning of the project and clearly set out expectations. Also ask the team, what are their expectations of you?\nThere won\u2019t be a one size fits all framework either. Think about your team, the people in it, the type of project you\u2019re working with, the type of client and stakeholder. This should give you an idea of what sort of communications you\u2019ll need on the project. Daily calls, video calls, Slack channels, the choice is yours.\nDecide on the tools\nTo be honest, I could spend hours talking about the different tools you can use for communication. But you know them, right? And in the end it\u2019s not the tool that\u2019s important here - it\u2019s the communication that\u2019s being done on the tool. Tools need to match the type of communications needed for your team. One caveat here though, never rely solely on email! Emails are silos, and can become beasts to manage communications on.\nTransparency in communication\nGood communication is key. Make sure there are clear objectives for communication. Set up one time during the week where those people meet together, discuss all the work during that week that they\u2019ve done. If decisions are made between team members who are together, make sure everyone knows what these are. But try to make collective decisions where you can, when it doesn\u2019t impact on people\u2019s time.\nHave a face-to-face kick off\nYes, I know this might seem to counter my argument, but face-to-face comms are still really important. If it\u2019s feasible, have an in-person meeting to kick off your project, and to kick off your team working together. An initial meeting, to break the ice, discuss ways of working, set the goals, can go a long way to making working with distributed teams successful. If this is really not viable, then hold a video call with the team. Try to make this a little more informal. I know, I know, not the dreaded cringey icebreakers\u2026 but something to make everyone relax and get to know each other is really important. Bring everybody together physically on a regular basis if you can, for example with quarterly meetings. You\u2019ve got to really make sure people still feel part of a team, and it often takes a little more work with a remote team. Connect with new team members, one-on-one first, then you can have more of a \u2018remote\u2019 relationship. \nGet visual\nVisual communication is often a lot better tool to use than just a written sentence, and can help bring ideas to life. Encourage people to sketch things, take a photo and add this to your written communications. Or use a mockup tool to sketch ideas.\nBut what about Agile projects?\nThe whole premise of Agile projects is to have face-to-face contact I hear you cry. The Agile Manifesto itself states \u201cThe most efficient and effective method of conveying information to and within a development team is face-to-face conversation\u201d. However, this doesn\u2019t mean the death of remote working. In fact loads of successful companies still run Agile projects, whilst having a distributed team. With all the collaborative tools you can use for centralising code, tracking tasks, visualising products, it\u2019s not difficult to still communicate in a way that works. Just think about how to replicate the principles of Agile remotely - working together daily, a supportive environment, trust, and simplicity. How can you translate these to your remote or distributed team? \nOne last thought to leave you with before you run off to eat your mince pies (in your pyjamas, whilst working). A common mistake in working with a remote project team or working remotely yourself, is replacing distance with time. If you\u2019re away from the office you think you need to always be \u2018on\u2019 \u2013 messaging, being online, replying to requests. If you have a distributed team, you might think a lot of meetings, calls, and messages will be good to foster communication. But don\u2019t overload these meetings, calls, and communication. This can be disruptive in itself. Give people the gift of some uninterrupted time to actually do some work, and not feel like they have to check in every second.", "year": "2017", "author": "Suzanna Haworth", "author_slug": "suzannahaworth", "published": "2017-12-06T00:00:00+00:00", "url": "https://24ways.org/2017/designing-a-remote-project/", "topic": "business"} {"rowid": 195, "title": "Levelling Up for Junior Developers", "contents": "If you are a junior developer starting out in the web industry, things can often seem a little daunting. There are so many things to learn, and as soon as you\u2019ve learnt one framework or tool, there seems to be something new out there.\nI am lucky enough to lead a team of developers building applications for the web. During a recent One to One meeting with one of our junior developers, he asked me about a learning path and the basic fundamentals that every developer should know. After a bit of digging around, I managed to come up with a (not so exhaustive) list of principles that was shared with him.\n\nIn this article, I will share the list with you, and hopefully help you level up from junior developer and become a better developer all round. This list doesn\u2019t focus on an particular programming language, but rather coding concepts as a whole. The idea behind this list is that whether you are a front-end developer, back-end developer, full stack developer or just a curious one, these principles apply to everyone that writes code. \nI have tried to be technology agnostic, so that you can use these tips to guide you, whatever your tech stack might be.\nWithout any further ado and in no particular order, let\u2019s get started.\nRefactoring code like a boss\nThe Boy Scouts have a rule that goes \u201calways leave the campground cleaner than you found it.\u201d This rule can be applied to code too and ensures that you leave code cleaner than you found it. As a junior developer, it\u2019s almost certain that you will either create or come across older code that could be improved. The resources below are a guide that will help point you in the right direction.\n\nMy favourite book on this subject has to be Clean Code by Robert C. Martin. It\u2019s a must read for anyone writing code as it helps you identify bad code and shows you techniques that you can use to improve existing code.\nIf you find that in your day to day work you deal with a lot of legacy code, Improving Existing Technology through Refactoring is another useful read.\nDesign Patterns are a general repeatable solution to a commonly occurring problem in software design. My friend and colleague Ranj Abass likes to refer to them as a \u201ccommon language\u201d that helps developers discuss the way that we write code as a pattern. My favourite book on this subject is Head First Design Patterns which goes right back to the basics. Another great read on this topic is Refactoring to Patterns.\nWorking Effectively With Legacy Code is another one that I found really valuable.\n\nImproving your debugging skills\nA solid understanding of how to debug code is a must for any developer. Whether you write code for the web or purely back-end code, the ability to debug will save you time and help you really understand what is going on under the hood.\n\nIf you write front-end code for the web, one of my favourite resources to help you understand how to debug code in Chrome can be found on the Chrome Dev Tools website. While some of the tips are specific to Chrome, these techniques apply to any modern browser of your choice.\nAt Settled, we use Node.js for much of our server side code. Without a doubt, our most trusted IDE has to be Visual Studio Code and the built-in debuggers are amazing. Regardless of whether you use Node.js or not, there are a number of plugins and debuggers that you can use in the IDE. I recommend reading the website of your favourite IDE for more information. \nAs a side note, it is worth mentioning that Chrome Developer Tools actually has functionality that allows you to debug Node.js code too. This makes it a seamless transition from front-end code to server-side code debugging.\nThe Debugging Mindset is an informative online article by Devon H. O\u2019Dell and discusses the the psychology of learning strategies that lead to effective problem-solving skills. \n\nA good understanding of relational databases and NoSQL databases\nAlmost all developers will need to persist data at some point in their career. Even if you don\u2019t write SQL queries in your day to day job, a solid understanding of how they work will help you become a better developer.\n\nIf you are a complete newbie when it comes to databases, I recommend checking out Code Academy. They offer a free online course that can help you get your head around how relational databases work. The course is quite basic, but is a useful hands-on approach to learning this topic.\nThis article provides a great explainer for the difference between the SQL and NoSQL databases, and this Stackoverflow answer goes a little deeper into the subject of the two database types.\nIf you\u2019d like to learn more about NoSQL queries, I would recommend starting with this article on MongoDB queries. Unfortunately, there isn\u2019t one overall course as most NoSQL databases have their own syntax. \n\nYou may also have noticed that I haven\u2019t included other types of databases such as Graph or In-memory; it\u2019s worth focussing on the basics before going any deeper.\nPerformance on the web\nIf you build for the web today, it is important to understand how the browser receives and renders the content that you send it. I am pretty passionate about Web Performance, and hope that everyone can learn how to make websites faster and more efficient. It can be fun at the same time!\n\nSteve Souders High Performance Websites is the godfather of web performance books. While it was created a few years ago and many of the techniques might have changed slightly, it is the original book on the subject and set up many of the ground rules that we know about web performance today.\nA free online resource on this topic is the Google Developers website. The site is an up to date guide on the best web performance techniques for your site. It is definitely worth a read.\nThe network plays a key role in delivering data to your users, and it plays a big role in performance on the web. A fantastic book on this topic is Ilya Grigorik\u2019s High Performance Browser Networking. It is also available to read online at hpbn.co.\n\nUnderstand the end to end architecture of your software project\nI find that one of the best ways to improve my knowledge is to learn about the architecture of the software at the company I work at. It gives you a good understanding as to why things are designed the way they are, why certain decisions were made, and gives you an understanding of how you might do things differently with hindsight.\nTry and find someone more senior, such as a Technical Lead or Software Architect, at your company and ask them to explain the overall architecture and draw a few high-level diagrams for you. Not to mention that they will be impressed with your willingness to learn.\n\nI recommend reading Clean Architecture: A Craftsman\u2019s Guide to Software Structure and Design for more detail on this subject.\nFar too often, software projects can be over-engineered and over-architected, it is worth reading Just Enough Software Architecture. The book helps developers understand how the smallest of changes can affect the outcome of your software architecture.\n\nHow are things deployed\nA big part of creating software is actually shipping it! How is the software at your company released into the wild? Does your company do Continuous Integration? Continuous Deployment?\n\nEven if you answered no to any of these questions, it is worth finding someone with the knowledge in your company to explain these things to you. If it is not already documented, perhaps you could start a wiki to document everything you\u2019re learning about the system - this is a great way to level up and be appreciated and invaluable.\nA streamlined deployment process is a beautiful thing, and understanding how they work can help you grow your knowledge as a developer. \nContinuous Integration is a practical read on the ins and outs of implementing this deployment technique.\nDocker is another great tool to use when it comes to software deployment. It can be tricky at first to wrap your head around, but it is definitely worth learning about this great technology. The documentation on the website will teach and guide you on how to get started using Docker.\n\nWriting Tests\nTesting is an essential tool in the developer bag of skills. They help you to make big refactoring changes to your code, and feel a lot more confident knowing that your changes haven\u2019t broken anything. There are so many benefits to testing, which make it so important for developers at every level to become acquainted with it/them.\n\nThe book that started it all for me was Roy Osherove\u2019s The Art of Unit Testing. The code in the book is written in C#, but the principles apply to every language. It\u2019s a great, easy-to-understand read.\nAnother great read is How Google Tests Software and covers exactly what it says on the tin. It covers many different testing techniques such as exploratory, black box, white box, and acceptance testing and really helps you understand how large organisations test their code.\n\nSoft skills\nWhilst reading through this article, you\u2019ve probably noticed that a large chunk of it focusses on code and technical ability. Without a doubt, I\u2019d say that it is even more important to be a good teammate. If you look up the definition of soft skills in the dictionary, it is defined as \u201cpersonal attributes that enable someone to interact effectively and harmoniously with other people\u201d and I think that it sums this up perfectly. Working on your \u201csoft skills\u201d is something that can truly help you level up in your career. You may be the world\u2019s greatest coder, but if you colleagues can\u2019t get along with you, your coding skills won\u2019t matter!\nWhile you may not learn how to become the perfect co-worker overnight, I really try and live by the motto \u201cdon\u2019t be an arsehole\u201d. Think about how you like to be treated and then try and treat your co-workers with the same courtesy and respect. The next time you need to make a decision at work, ask yourself \u201cis this something an arsehole would do\u201d? If you answered yes to that question, you probably shouldn\u2019t do it!\nSummary\nLevelling up as a junior developer doesn\u2019t have to be scary. Focus on the fundamentals and they should hold you in good stead, regardless of the new things that come along. Software engineering is built on these great principles that have stood the test of time.\nWhilst researching for this article, I came across a useful Github repo that is worth mentioning. Things Every Programmer Should Know is packed with useful information. I have to admit, I didn\u2019t know everything on there!\nI hope that you have found this list helpful. Some of the topics I have mentioned might not be relevant for you at this stage in your career, but should give a nudge in the right direction. After all, knowledge is power!\nIf you are a junior developer reading this article, what would you add to it?", "year": "2017", "author": "Dean Hume", "author_slug": "deanhume", "published": "2017-12-05T00:00:00+00:00", "url": "https://24ways.org/2017/levelling-up-for-junior-developers/", "topic": "code"} {"rowid": 203, "title": "Jobs-to-Be-Done in Your UX Toolbox", "contents": "Part 1: What is JTBD?\nThe concept of a \u201cjob\u201d in \u201cJobs-To-Be-Done\u201d is neatly encapsulated by a oft-quoted line from Theodore Levitt:\n\n\u201cPeople want a quarter-inch hole, not a quarter inch drill\u201d.\n\nEven so, Don Norman pointed out that perhaps Levitt \u201cstopped too soon\u201d at what the real customer goal might be. In the \u201cThe Design of Everyday Things\u201d, he wrote:\n\n\u201cLevitt\u2019s example of the drill implying that the goal is really a hole is only partially correct, however. When people go to a store to buy a drill, that is not their real goal. But why would anyone want a quarter-inch hole? Clearly that is an intermediate goal. Perhaps they wanted to hang shelves on the wall. Levitt stopped too soon. Once you realize that they don\u2019t really want the drill, you realize that perhaps they don\u2019t really want the hole, either: they want to install their bookshelves. Why not develop methods that don\u2019t require holes? Or perhaps books that don\u2019t require bookshelves.\u201d\n\nIn other words, a \u201cjob\u201d in JTBD lingo is a way to express a user need or provide a customer-centric problem frame that\u2019s independent of a solution. As Tony Ulwick says:\n\n\u201cA job is stable, it doesn\u2019t change over time.\u201d\n\nAn example of a job is \u201ctiding you over from breakfast to lunch.\u201d You could hire a donut, a flapjack or a banana for that mid-morning snack\u2014whatever does the job. If you can arrive at a clearly identified primary job (and likely some secondary ones too), you can be more creative in how you come up with an effective solution while keeping the customer problem in focus.\nThe team at Intercom wrote a book on their application of JTBD. In it, Des Traynor cleverly characterised how JTBD provides a different way to think about solutions that compete for the same job: \n\n\u201cEconomy travel and business travel are both capable candidates applying for [the job: Get me face-to-face with my colleague in San Francisco], though they\u2019re looking for significantly different salaries. Video conferencing isn\u2019t as capable, but is willing to work for a far smaller salary. I\u2019ve a hiring choice to make.\u201d\n\nSo far so good: it\u2019s relatively simple to understand what a job is, once you understand how it\u2019s different from a \u201ctask\u201d. Business consultant and Harvard professor Clay Christensen talks about the concept of \u201chiring\u201d a product to do a \u201cjob\u201d, and firing it when something better comes along. If you\u2019re a company that focuses solutions on the customer job, you\u2019re more likely to succeed. You\u2019ll find these concepts often referred to as \u201cJobs-to-be-Done theory\u201d. But the application of Jobs-to-Be-Done theory is a little more complicated; it comprises several related approaches.\nI particularly like Jim Kalbach\u2019s description of how JTBD is a \u201clens through which to understand value creation\u201d. But it is also more. In my view, it\u2019s a family of frameworks and methods\u2014and perhaps even a philosophy.\nDifferent facets in a family of frameworks\nJTBD has its roots in market research and business strategy, and so it comes to the research table from a slightly different place compared to traditional UX or design research\u2014we have our roots in human-computer interaction and ergonomics. I\u2019ve found it helpful to keep in mind is that the application of JTBD theory is an evolving beast, so it\u2019s common to find contradictions across different resources. My own use of it has varied from project to project. In speaking to others who have adopted it in different measures, it seems that we have all applied it in somewhat multifarious ways. As we like to often say in interviews: there are no wrong answers.\nOutcome Driven Innovation\nTony Ulwick\u2019s version of the JTBD history began with Outcome Driven Innovation (ODI), and this approach is best outlined in his seminal article published in the Harvard Business Review in 2002. To understand his more current JTBD approach in his new book \u201cJobs to Be Done: Theory to Practice\u201d, I actually found it beneficial to read his approach in the original 2002 article for a clearer reference point.\nIn the earlier article, Ulwick presented a rigorous approach that combines interviews, surveys and an \u201copportunity\u201d algorithm\u2014a sequence of steps to determine the business opportunity. ODI centres around working with \u201cdesired outcome statements\u201d that you unearth through interviews, followed by a means to quantify the gap between importance and satisfaction in a survey to different types of customers. \nSince 2008, Ulwick has written about using job maps to make sense of what the customer may be trying to achieve. In a recent article, he describes the aim of the activity is \u201cto discover what the customer is trying to get done at different points in executing a job and what must happen at each juncture in order for the job to be carried out successfully.\u201d\nA job map is not strictly a journey map, however tempting it is to see it that way. From a UX perspective, is one of many models we can use\u2014and as our research team at Clearleft have found, how we use model can depend on the nature of the jobs we\u2019ve uncovered in interviews and the characteristics of the problem we\u2019re attempting to solve.\nFigure 1. Universal job map\nUlwick\u2019s current methodology is outlined in his new book, where he describes a complete end-to-end process: from customer and competitor research to framing market and product strategy.\nThe Jobs-To-Be-Done Interview\nBack in 2013, I attended a workshop by Chris Spiek and Bob Moesta from the ReWired Group on JTBD at the behest of a then-MailChimp colleague, and I came away excited about their approach to product research. It felt different from anything I\u2019d done before and for the first time in years, I felt that I was genuinely adding something new to my research toolbox.\nA key idea is that if you focus on the stories of those who switched to you, and those who switch away from you, you can uncover the core jobs through looking at these opposite ends of engagement.\nThis framework centres around the JTBD interview method, which harnesses the power of a narrative framework to elicit the real reasons why someone \u201chired\u201d something to do a job\u2014be it something physical like a new coffee maker, or a digital service, such as a to-do list app. As you interview, you are trying to unearth the context around the key moments on the JTBD timeline (Figure 2). A common approach is to begin from the point the customer might have purchased something, back to the point where the thought of buying this thing first occurred to them.\nFigure 2. JTBD Timeline\nFigure 3. The Four Forces\nThe Forces Diagram (Figure 3) is a post-interview analysis tool where you can map out what causes customers to switch to something new and what holds them back.\nThe JTBD interview is effective at identifying core and secondary jobs, as well as some context around the user need. Because this method is designed to extract the story from the interviewee, it\u2019s a powerful way to facilitate recall. Having done many such interviews, I\u2019ve noticed one interesting side effect: participants often remember more details later on after the conversation has formally ended. It is worth scheduling a follow-up phone call or keep the channels open.\nStrengths aside, it\u2019s good to keep in mind that the JTBD interview is still primarily an interview technique, so you are relying on the context from the interviewee\u2019s self-reported perspective. For example, a stronger research methodology combines JTBD interviews with contextual research and quantitative methods. \nJob Stories\nAlan Klement is credited for coming up with the term \u201cjob story\u201d to describe the framing of jobs for product design by the team at Intercom:\n\n\u201cWhen \u2026 I want to \u2026 so I can \u2026.\u201d\n\nFigure 4. Anatomy of a Job Story\nUnlike a user story that traditionally frames a requirement around personas, job stories frame the user need based on the situation and context. Paul Adams, the VP of Product at Intercom, wrote:\n\n\u201cWe frame every design problem in a Job, focusing on the triggering event or situation, the motivation and goal, and the intended outcome. [\u2026] We can map this Job to the mission and prioritise it appropriately. It ensures that we are constantly thinking about all four layers of design. We can see what components in our system are part of this Job and the necessary relationships and interactions required to facilitate it. We can design from the top down, moving through outcome, system, interactions, before getting to visual design.\u201d\n\nSystems of Progress\nApart from advocating using job stories, Klement believes that a core tenet of applying JTBD revolves around our desire for \u201cself-betterment\u201d\u2014and that focusing on everyone\u2019s desire for self-betterment is core to a successful strategy.\nIn his book, Klement takes JTBD further to being a tool for change through applying systems thinking. There, he introduces the systems of progress and how it can help focus product strategy approach to be more innovative.\nCoincidentally, I applied similar thinking on mapping systemic change when we were looking to improve users\u2019 trust with a local government forum earlier this year. It\u2019s not just about capturing and satisfying the immediate job-to-be-done, it\u2019s about framing the job so that you can a clear vision forward on how you can help your users improve their lives in the ways they want to.\nThis is really the point where JTBD becomes a philosophy of practice.\nPart 2: Mixing It Up\nThere has been some misunderstanding about how adopting JTBD means ditching personas or some of our existing design tools or research techniques. This couldn\u2019t have been more wrong.\nFigure 5: Jim Kalbach\u2019s JTBD model\nJim Kalbach has used Outcome-Driven Innovation for around 10 years. In a 2016 article, he presents a synthesised model of how to think about that has key elements from ODI, Christensen\u2019s theories and the structure of the job story.\nMore interestingly, Kalbach has also combined the use of mental models with JTBD.\nClaire Menke of UDemy has written a comprehensive article about using personas, JTBD and customer journey maps together in order to communicate more complete story from the users\u2019 perspective. Claire highlights an especially interesting point in her article as she described her challenges:\n\u201cAfter much trial and error, I arrived at a foundational research framework to suit every team\u2019s needs \u2014 allowing everyone to share the same holistic understanding, but extract the type of information most applicable to their work.\u201d\nIn other words, the organisational context you are in likely can dictate what works best\u2014after all the goal is to arrive at the best user experience for your audiences. Intercom can afford to go full-on on applying JTBD theory as a dominant approach because they are a start-up, but a large company or organisation with multiple business units may require a mix of tools, outputs and outcomes.\nJTBD is an immensely powerful approach on many fronts\u2014you\u2019ll find many different references that lists the ways you can apply JTBD. However, in the context of this discussion, it might also be useful to we examine where it lies in our models of how we think about our UX and product processes.\nJTBD in the UX ecosystem\nFigure 6. The Elements of User Experience (source)\nThere are many ways we have tried to explain the UX discipline but I think Jesse James Garrett\u2019s Elements of User Experience is a good place to begin.\nI sometimes also use little diagram to help me describe the different levels you might work at when you work through the complexity of designing and developing a product. A holistic UX strategy needs to address all the different levels for a comprehensive experience: your individual product UI, product features, product propositions and brand need to have a cohesive definition.\nFigure 7. Which level of product focus?\nWe could, of course, also think about where it fits best within the double diamond.\nAgain, bearing in mind that JTBD has its roots in business strategy and market research, it is excellent at clarifying user needs, defining high-level specifications and content requirements. It is excellent for validating brand perception and value proposition \u2014all the way down to your feature set. In other words, it can be extremely powerful all the way through to halfway of the second diamond. You could quite readily combine the different JTBD approaches because they have differences as much as overlaps. However, JTBD generally starts getting a little difficult to apply once we get to the details of UI design.\nThe clue lies in JTBD\u2019s raison d\u2019\u00eatre: a job statement is solution independent. Hence, once we get to designing solutions, we potentially fall into a existential black hole.\nThat said, Jim Kalbach has a quick case study on applying JTBD to content design tucked inside the main article on a synthesised JTBD model. Alan Klement has a great example of how you could use UI to resolve job stories. You\u2019ll notice that the available language of \u201cjobs\u201d drops off at around that point.\nJob statements and outcome statements provide excellent \u201cmini north-stars\u201d as customer-oriented focal points, but purely satisfying these statements would not necessarily guarantee that you have created a seamless and painless user experience.\nPlaying well with others\nYou will find that JTBD plays well with Lean, and other strategy tools like the Value Proposition Canvas. With every new project, there is potential to harness the power of JTBD alongside our established toolbox.\nWhen we need to understand complex contexts where cultural or socioeconomic considerations have to be taken into account, we are better placed with combining JTBD with more anthropological approaches. And while we might be able to evaluate if our product, website or app satisfies the customer jobs through interviews or surveys, without good old-fashioned usability testing we are unlikely to be able to truly validate why the job isn\u2019t being represented as it should. In this case, individual jobs solved on the UI can be set up as hypotheses to be proven right or wrong. \nThe application of Jobs-to-be-Done is still evolving. I\u2019ve found it to be very powerful and I struggle to remember what my UX professional life was like before I encountered it\u2014it has completely changed my approach to research and design.\nThe fact JTBD is still evolving as a practice means we need to be watchful of dogma\u2014there\u2019s no right way to get a UX job done after all, it nearly always depends. At the end of the day, isn\u2019t it about having the right tool for the right job?", "year": "2017", "author": "Steph Troeth", "author_slug": "stephtroeth", "published": "2017-12-04T00:00:00+00:00", "url": "https://24ways.org/2017/jobs-to-be-done-in-your-ux-toolbox/", "topic": "ux"} {"rowid": 193, "title": "Web Content Accessibility Guidelines\u2014for People Who Haven't Read Them", "contents": "I\u2019ve 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\u2019ve found them practical and future-proof, and I\u2019ve 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.\nToday, the United Nations International Day of Persons with Disabilities, seems like a good time to re-read Laura Kalbag\u2019s explanation of why we should bother with accessibility. That should motivate you to devour this article.\nIf you haven\u2019t 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\u2014such as \u201ctime-based media\u201d and \u201cprogrammatically determined\u201d\u2014can 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.\nThis festive season, let\u2019s rip off that legalese and ambiguous terminology like wrapping paper, and see\u2014in a single article\u2014what gifts the Web Content Accessibility Guidelines 2.0 editors have bestowed upon us.\nCan your users perceive the information on your website?\nThe first guideline has criteria that help you prevent your users from asking \u201cWhat the **** is this thing here supposed to be?\u201d\n1.1.1 Text is the most accessible format for information. Screen readers\u2014such as the \u201cVoiceOver\u201d setting on your iPhone or the \u201cTalkBack\u201d app on your Android phone\u2014understand 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\u2019s not text, you must add some text that gives your user the same information. You probably know how to do this already; for example:\n\nfor images in webpages, put some alternative text in an alt attribute to tell your user what the image conveys to the user;\nfor photos in tweets, add a description to make the images accessible;\nfor Instagram posts, write a caption that conveys the photo\u2019s information.\n\nThe 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\u2014might\u2014be appropriate.\nYou can probably think of a few exceptions where providing text to describe an image might not make sense. Remember I described these guidelines as \u201cpractical\u201d? They cover all those exceptions:\n\nUser interface controls such as buttons and text inputs must have names or labels to tell your user what they do.\nIf your webpage has video or audio (more about these later on!), you must\u2014at least\u2014have text to tell the user what they are.\nMaybe 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.\nIf your webpage features a work of art, tell your user the experience it evokes.\nIf you have to include a Captcha on your webpage\u2014and please avoid Captchas if at all possible, because some users cannot get past them\u2014you must include text to tell your user what it is, and make sure that it doesn\u2019t rely on only one sense, such as vision.\nIf you\u2019ve included something just as decoration, you must make sure that your user\u2019s 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\u2019re better than that.)\n\n(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!)\n1.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. \nSimilarly, if your website includes recorded video without audio\u2014such as an animation or a promotional video\u2014you 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 \u201cAbout Us\u201d 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.\n1.2.2 If your website includes recorded videos with audio, you must add captions to those videos for users who can\u2019t 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\u2014such as the speech that a politician read or the bedtime story that an actor read\u2014you 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\u2019s track element\u2014or 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.)\n1.2.3 If your website has recorded videos that have audio, you must add an \u201caudio description\u201d 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, \u201cI\u2019d like to explain our new TPS reports\u201d while \u201cBill Lumbergh, division Vice President of Initech\u201d appears on the bottom of the screen. In that case, you should add an audio description to the video that announces \u201cBill Lumbergh, division Vice President of Initech\u201d, 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, \u201cI\u2019m Bill Lumbergh, division Vice President of Initech, and I\u2019d like to explain our new TPS reports\u201d\u2014so you won\u2019t need to spend time adding an audio description afterwards. \n1.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\u2019ll 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\u2014or failing that, publish a transcription as soon as possible.\n1.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.\n1.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\u2019t need to caption a video of a sign language version of audio information.)\n1.2.7 If your website has recorded videos that have audio, and you need to add an audio description, but the audio doesn\u2019t have enough pauses for you to add an \u201caudio description\u201d narration, you could provide a separate version of that video where you have added pauses to fit the audio description into.\n1.2.8 Let\u2019s 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.\n1.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.\n(Congratulations on making it this far! I know that seems like a lot to remember, but keep in mind that we\u2019ve covered a complex area: helping your users to understand multimedia information that they can\u2019t see and/or hear. Grab a mince pie to celebrate, and let\u2019s keep going.)\n1.3.1 You must mark up your website\u2019s content so that your user\u2019s 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\u2019re 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\u2019t know, or that you\u2019ve 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\u2014you might be surprised at how much you can do with just HTML! Once you\u2019ve mastered those, you can make your website much more usable for your all of your users.\n1.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\u2019t rely on CSS or whitespace to create that order visually. Check that the order of the information makes sense when CSS and whitespace aren\u2019t 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.\n1.3.3 You must not presume that your users can identify sensory characteristics of things on your webpage. Some users can\u2019t tell what you\u2019ve positioned where on the screen. For example, instead of asking your users to \u201cChoose one of the options on the left\u201d, you could ask them to \u201cChoose one of our new products\u201d and link to that section of the webpage.\n1.4.1 You must not rely on colour as the only way to convey something to your users. Some of your users can\u2019t see, and some of your users can\u2019t 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.\n1.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\u2019t 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!\n1.4.3 You should make sure that your text contrasts enough with its background, so that your users can read it. Bookmark Lea Verou\u2019s 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:\n\nnormal text that set at 24px or larger has a ratio of at least 3:1;\nbold text that set at 18.75px or larger has a ratio of at least 3:1;\nall other text has a ratio of at least 4\u00bd:1.\n\nYou don\u2019t have to do this for disabled form controls, decorative stuff, or logos\u2014but you could!\n1.4.4 You should make sure your users can resize the text on your website up to 200% without using their assistive technology\u2014and still access all your content and functionality. You don\u2019t have to do this for subtitles or images of text.\n1.4.5 You should avoid using images of text and just use text instead. In 1998, Jeffrey Veen\u2019s first Hot Design Tip said, \u201cText is text. Graphics are graphics. Don\u2019t confuse them.\u201d 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\u2014but I\u2019ve never seen that on a real website. Also, this doesn\u2019t apply to logos.\n1.4.6 Let\u2019s 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\u2019s Contrast Ratio calculator to make sure that:\n\nnormal text that is 24px or larger has a ratio of at least 4\u00bd:1;\nbold text that 18.75px or larger has a ratio of at least 4\u00bd:1;\nall other text has a ratio of at least 7:1.\n\n1.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\u2019s 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\u2019t apply to audio Captchas, audio logos, singing, or rapping. (Yes, these guidelines mention rapping!)\n1.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:\n\nspecify the colours of the text and the background, and\nmake the blocks of text less than 80-characters wide, and \nalign text to the left (or right for right-to-left languages), and \nset the line height to 150%, and \nset the vertical distance between paragraphs to 1\u00bd times the line height of the text, and \nresize the text (without using their assistive technology) up to 200% and still not have to scroll horizontally to read it.\n\nBy the way, when you specify a colour for text, always specify a colour for its background too. Don\u2019t rely on default background colours!\n1.4.9 Let\u2019s return to images of text for a second. You could make sure that you use them only for decoration and logos.\nCan users operate the controls and links on your website?\nThe second guideline has criteria that help you prevent your users from asking, \u201cHow the **** does this thing work?\u201d\n2.1.1 You must make sure that you users can carry out all of your website\u2019s activities with just their keyboard, without time limits for pressing keys. (This doesn\u2019t 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.\n2.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 \u201ckeyboard traps\u201d 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.\n2.1.3 Let\u2019s revisit making sure that you users can carry out all of your website\u2019s 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.\n2.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: \n\nlet your users turn off the time limit before they encounter it; or\nlet your users increase the time limit to at least 10 times the default time limit before they encounter it; or\nwarn 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.\n\nRemember: 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\u2019t 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!\n2.2.2 In my experience, this criterion remains the least well-known\u2014even 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:\n\npause, stop, or hide the other content if it\u2019s not essential and lasts more than 5 seconds; and\npause, stop, hide, or control the frequency of the other content if it automatically updates.\n\nIt\u2019s OK if your users miss live information such as stock price updates or football scores; you can\u2019t do anything about that! Also, this doesn\u2019t apply to animations such as progress bars that you put on a website to let all users know that the webpage isn\u2019t frozen.\n(If this one sounds complex, just add a pause button to anything that might distract your users.)\n2.2.3 Let\u2019s 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\u2019t need to interact with a timer at all.\n2.2.4 You could let your users turn off all interruptions\u2014server updates, promotions, and so on\u2014apart from any emergency information.\n2.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\u2019ll be on everyone\u2019s Nice List this Christmas.\n2.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\u2026\n2.3.2 \u2026or you could just make sure that nothing flashes more than three times per second on your website. This is usually an easier goal.\n2.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\u2019s 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 \u201cSkip Navigation\u201d links allows everyone to get to your main content faster.\n2.4.2 You must add a proper title to describe each webpage\u2019s topic. Your webpage won\u2019t even validate without a title element, so make it a useful one.\n2.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.\n2.4.4 You must make sure that your users can understand the purpose of a link when they read:\n\nthe text of the link; or\nthe text of the paragraph, list item, table cell, or table header for the cell that contains the link; or\nthe heading above the link.\n\nYou don\u2019t have to do that for games and quizzes.\n2.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\u2019re done!\nThis doesn\u2019t 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).\n2.4.6 You should help your users to understand your content by providing:\n\nheadings that describe the topics of you content;\nlabels that describe the purpose of the native form widgets on the webpage.\n\n2.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\u2019t, search your CSS to see whether you\u2019ve applied outline: 0; to all elements\u2014that\u2019s usually the culprit. Use the :focus pseudo-element to define how elements should appear when they have focus.\n2.4.8 You could help your user to understand where the current webpage is located within your website. Add \u201cbreadcrumb navigation\u201d and/or a site map and you\u2019re done.\n2.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\u2019t have to do that for games and quizzes.\n2.4.10 You could use headings to organise your content by topic. \nCan users understand your content?\nThe third guideline has criteria that help you prevent your users from asking, \u201cWhat the **** does this mean?\u201d\n3.1.1 Let\u2019s start this section with the criterion that possibly takes the least time to implement; you must make sure that the user\u2019s browser can identify the main language that your webpage\u2019s content is written in. For a webpage that has mainly English content, use . \n3.1.2 You must specify when content in another language appears in your webpage, like so: I wish you a Joyeux No\u00ebl.. You don\u2019t have to do this for proper names, technical terms, or words that you can\u2019t identify a language for. You also don\u2019t have to do it for words from a different language that people consider part of the language around those words; for example, Come to our Christmas rendezvous! is OK.\n3.1.3 You could make sure that your users can find out the meaning of any unusual words or phrases, including idioms like \u201cstocking filler\u201d or \u201cBah! Humbug!\u201d and jargon such as \u201cVoiceOver\u201d and \u201cTalkBack\u201d. Provide a glossary or link to a dictionary.\n3.1.4 You could make sure that your users can find out the meaning of any abbreviation. For example, VoiceOver pronounces \u201cXmas\u201d as \u201cSmas\u201d instead of \u201cChristmas\u201d. Using the abbr element and linking to a glossary can help. (Interestingly, VoiceOver pronounces \u201cabbr\u201d as \u201cabbreviation\u201d!)\n3.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\u2019t require that level of reading ability, or you could provide images, videos, or audio to explain your content. (You don\u2019t have to add captions or audio description to those videos.)\n3.1.6 You could make sure that your users can access the pronunciation of any word in your content if that word\u2019s meaning depends on its pronunciation. For example, the word \u201cclose\u201d could have one of two meanings, depending on pronunciation, in a phrase such as, \u201cReady for Christmas? Close now!\u201d\n3.2.1 Some users need to focus on elements to access information about them. You must make sure that focusing on an element doesn\u2019t trigger any major changes, such as opening a new window, focusing on another element, or submitting a form.\n3.2.2 Webpages are easier for users when the controls do what they\u2019re 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\u2019t trigger any major changes, such as opening a new window, focusing on another element, or submitting a form.\n3.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\u2019t apply when your user has changed their preferences or when they use assistive technology to change how your content appears.) \n3.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\u2019t use the word \u201cSearch\u201d for the search box on one webpage and \u201cFind\u201d for the search box on another webpage within that set of webpages.\n3.2.5 Let\u2019s 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 \u201copens in new window\u201d to the link text.\n3.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.\n3.3.2 You must include labels or instructions (and possibly examples) in your website\u2019s forms, to help your users to avoid making mistakes. \n3.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\u2019t apply in scenarios where those suggestions could affect the security of the content.\n3.3.4 Whenever your user submits information that:\n\nhas legal or financial consequences; or\naffects information that they have previously saved in your website; or\nis part of a test\n\n\u2026you should make sure that they can:\n\nundo it; or\ncorrect any mistakes, after your webpage checks their information; or\nreview, confirm, and correct the information before they finally submit it.\n\n3.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.\n3.3.6 Whenever your user submits any information, you could make sure that they can:\n\nundo it; or\ncorrect any mistakes, after your webpage checks their information; or\nreview, confirm, and correct the information before they finally submit it.\n\nHave you made your website robust enough to work on your users\u2019 browsers and assistive technologies?\nThe fourth and final guideline has criteria that help you prevent your users from asking, \u201cWhy the **** doesn\u2019t this work on my device?\u201d\n4.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\u2019t expect their users to be unwrapping the Wii U Browser five years ago\u2014who knows what browsers and assistive technologies our users will be unwrapping in five years\u2019 time? Avoid hacks, and use the W3C Markup Validation Service to make sure that your HTML has no errors.\n4.1.2 If you develop your own user interface components, you must make their name, role, state, properties, and values available to your user\u2019s browsers and assistive technologies. That should make them almost as accessible as standard HTML elements such as links, buttons, and checkboxes.\n\u201c\u2026and a partridge in a pear tree!\u201d\n\u2026as that very long Christmas song goes. We\u2019ve covered a lot in this article\u2014because 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. \nTo start applying what we\u2019ve covered, you might like to look at Sarah Horton and Whitney Quesenbery\u2019s 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\u2019ve covered today, to help users like them to do what they need to do on your website.\nHow to know when your website is perfectly accessible for everyone\nLOL! There will never be a time when your website becomes perfectly accessible for everyone. Don\u2019t aim for that. Instead, aim for regularly testing and making your website more accessible.\nWeb Content Accessibility Guidelines (WCAG) 2.1\nThe W3C hope to release the Web Content Accessibility Guidelines (WCAG) 2.1 as a \u201crecommendation\u201d (that\u2019s 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!\nYou\u2019ll go down in history\nOne last point: I\u2019ve 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\u2019t try again unless you let them know that things have improved. A quick Twitter search for your website\u2019s name alongside phrases like \u201cassistive technology\u201d, \u201cdoesn\u2019t work\u201d, or \u201c#fail\u201d can let you find frustrated users\u2014so you can tell them about how you\u2019re making your website more accessible. Start making your websites work better for everyone\u2014and please, let everyone know.", "year": "2017", "author": "Alan Dalton", "author_slug": "alandalton", "published": "2017-12-03T00:00:00+00:00", "url": "https://24ways.org/2017/wcag-for-people-who-havent-read-them/", "topic": "code"} {"rowid": 201, "title": "Lint the Web Forward With Sonarwhal", "contents": "Years ago, when I was in a senior in college, much of my web development courses focused on two things: the basics like HTML and CSS (and boy, do I mean basic), and Adobe Flash. I spent many nights writing ActionScript 3.0 to build interactions for the websites that I would add to my portfolio. A few months after graduating, I built one website in Flash for a client, then never again. Flash was dying, and it became obsolete in my r\u00e9sum\u00e9 and portfolio. \nThat was my first lesson in the speed at which things change in technology, and what a daunting realization that was as a new graduate looking to enter the professional world. Now, seven years later, I work on the Microsoft Edge team where I help design and build a tool that would have lessened my early career anxieties: sonarwhal. \nSonarwhal is a linting tool, built by and for the web community. The code is open source and lives under the JS Foundation. It helps web developers and designers like me keep up with the constant change in technology while simultaneously teaching how to code better websites. \nIntroducing sonarwhal\u2019s mascot Nellie\nGood web development is hard. It is more than HTML, CSS, and JavaScript: developers are expected to have a grasp of accessibility, performance, security, emerging standards, and more, all while refreshing this knowledge every few months as the web evolves. It\u2019s a lot to keep track of.\n\u00a0\nWeb development is hard \nStaying up-to-date on all this knowledge is one of the driving forces for developing this scanning tool. Whether you are just starting out, are a student, or you have over a decade of experience, the sonarwhal team wants to help you build better websites for all browsers. \nCurrently sonarwhal checks for best practices in five categories: Accessibility, Interoperability, Performance, PWAs, and Security. Each check is called a \u201crule\u201d. You can configure them and even create your own rules if you need to follow some specific guidelines for your project (e.g. validate analytics attributes, title format of pages, etc.). \nYou can use sonarwhal in two ways:\n\nAn online version, that provides a quick and easy way to scan any public website.\nA command line tool, if you want more control over the configuration, or want to integrate it into your development flow.\n\nThe Online Scanner\nThe online version offers a streamlined way to scan a website; just enter a URL and you will get a web page of scan results with a permalink that you can share and revisit at any time.\nThe online version of sonarwal\nWhen my team works on a new rule, we spend the bulk of our time carefully researching each subject, finding sources, and documenting it rather than writing the rule\u2019s code. Not only is it important that we get you the right results, but we also want you to understand why something is failing. Next to each failing rule you\u2019ll find a link to its detailed documentation, explaining why you should care about it, what exactly we are testing, examples that pass and examples that don\u2019t, and useful links to even more in-depth documentation if you are interested in the subject.\nWe hope that between reading the documentation and continued use of sonarwhal, developers can stay on top of best practices. As devs continue to build sites and identify recurring issues that appear in their results, they will hopefully start to automatically include those missing elements or fix those pieces of code that are producing errors. This also isn\u2019t a one-way communication: the documentation is not only available on the sonarwhal site, but also on GitHub for editing so you can help us make it even better!\nA results report\nThe current configuration for the online scanner is very strict, so it might hurt your feelings (it did when I first tested it on my personal website). But you can configure sonarwhal to any level of strictness as well as customize the command line tool to your needs! \nSonarwhal\u2019s CLI\u00a0\nThe CLI gives you full control of sonarwhal: what rules to use, tweaks to them, domains that are out of your control, and so on. You will need the latest node LTS (v8) or Stable (v9) and your favorite package manager, such as npm:\nnpm install -g sonarwhal\nYou can now run sonarwhal from anywhere via:\nsonarwhal https://example.com\nUsing the CLI\nThe configuration is done via a .sonarwhalrc file. When analyzing a site, if no file is available, you will be prompted to answer a series of questions:\n\nWhat connector do you want to use? Connectors are what sonarwhal uses to access a website and gather all the information about the requests, resources, HTML, etc. Currently it supports jsdom, Microsoft Edge, and Google Chrome.\nWhat formatter? This is how you want to see the results: summary, stylish, etc. Make sure to look at the full list. Some are concise for, perfect for a quick build assessment, while others are more verbose and informative.\nDo you want to use the recommended rules configuration? Rules are the things we are validating. Unless you\u2019ve read the documentation and know what you are doing, first timers should probably use the recommended configuration.\nWhat browsers are you targeting? One of the best features of sonarwhal is that rules can adapt their feedback depending on your targeted browsers, suggesting to add or remove things. For example, the rule \u201cHighest Document Mode\u201d will tell you to add the \u201cX-UA-Compatible\u201d header if IE10 or lower is targeted or remove if the opposite is true. \n\nsonarwhal configuration generator questions\nOnce you answer all these questions the scan will start and you will have a .sonarwhalrc file similar to the following:\n{\n \"connector\": {\n \"name\": \"jsdom\",\n \"options\": {\n \"waitFor\": 1000\n }\n },\n \"formatters\": \"stylish\",\n \"rulesTimeout\": 120000,\n \"rules\": {\n \"apple-touch-icons\": \"error\",\n \"axe\": \"error\",\n \"content-type\": \"error\",\n \"disown-opener\": \"error\",\n \"highest-available-document-mode\": \"error\",\n \"validate-set-cookie-header\": \"warning\",\n // ...\n }\n}\nYou should see the scan initiate in the command line and within a few seconds the results should start to appear. Remember, the scan results will look different depending on which formatter you selected so try each one out to see which one you like best. \nsonarwhal results on my website and hurting my feelings \ud83d\udc94\nNow that you have a list of errors, you can get to work improving the site! Note though, that when you scan your website, it scans all the resources on that page and if you\u2019ve added something like analytics or fonts hosted elsewhere, you are unable to change those files. You can configure the CLI to ignore files from certain domains so that you are only getting results for files you are in control of.\nThe documentation should give enough guidance on how to fix the errors, but if it\u2019s insufficient, please help us and suggest edits or contribute back to it. This is a community effort and chances are someone else will have the same question as you.\nWhen I scanned both my websites, sonarwhal alerted me to not having an Apple Touch Icon. If I search on the web as opposed to using the sonarwhal documentation, the first top 3 results give me outdated information: I need to include many different icon sizes. I don\u2019t need to include all the different size icons that target different devices. Declaring one icon sized 180px x 180px will provide a large enough icon for devices and it will scale down as appropriate for people on older devices. \nThe information at the top of the search results isn\u2019t always the correct answer to an issue and we don\u2019t want you to have to search through outdated documentation. As sonarwhal\u2019s capabilities expand, the goal is for it to be the one stop shop for helping preflight your website. \nThe journey up until now and looking forward\n\nOn the Microsoft Edge team, we\u2019re passionate about empowering developers to build great websites. Every day we see so many sites come through our issue tracker. (Thanks for filing those bugs, they help us make Microsoft Edge better and better!) Some issues we see over and over are honest mistakes or outdated \u2018best practices\u2019 that could be avoided, so we built this tool to help everyone help make the web a better place.\nWhen we decided to create sonarwhal, we wanted to create a tool that would help developers write better and more up-to-date code for their websites. We want sonarwhal to be useful to anyone so, early on, we defined three guiding principles we\u2019ve used along the way:\n\nCommunity Driven. We build for the community\u2019s best interests. The web belongs to everyone and this project should too. Not only is it open source, we\u2019ve also donated it to the JS Foundation and have an inclusive governance model that welcomes the collaboration of anyone, individual or company.\nUser Centric. We want to put the user at the center, making sonarwhal configurable for your needs and easy to use no matter what your skill level is.\nCollaborative. We didn\u2019t want to reinvent the wheel, so we collaborated with existing tools and services that help developers build for the web. Some examples are aXe, snyk.io, Cloudinary, etc.\n\nThis is just the beginning and we still have lots to do. We\u2019re hard at work on a backlog of exciting features for future releases, such as:\n\nNew rules for a variety of areas like\u00a0performance,\u00a0accessibility,\u00a0security,\u00a0progressive web apps, and more.\nA plug-in for Visual Studio Code: we want sonarwhal to help you write better websites, and what better moment than when you are in your editor.\nConfiguration options for the online service: as we fine tune the infrastructure, the rule configuration for our scanner is locked, but we look forward to adding CLI customization options here in the near future.\n\nThis is a tool for the web community by the web community so if you are excited about sonarwhal, making a better web, and want to contribute, we have a\u00a0few issues where you might be able to help. Also, don\u2019t forget to check the rest of the\u00a0sonarwhal GitHub organization. PRs are always welcome and appreciated! \nLet us know what you think about the scanner at @NarwhalNellie on Twitter and we hope you\u2019ll help us lint the web forward!", "year": "2017", "author": "Stephanie Drescher", "author_slug": "stephaniedrescher", "published": "2017-12-02T00:00:00+00:00", "url": "https://24ways.org/2017/lint-the-web-forward-with-sonarwhal/", "topic": "code"} {"rowid": 204, "title": "Cascading Web Design with Feature Queries", "contents": "Feature queries, also known as the @supports rule, were introduced as an extension to the CSS2 as part of the CSS Conditional Rules Module Level 3, which was first published as a working draft in 2011. It is a conditional group rule that tests if the browser\u2019s user agent supports CSS property:value pairs, and arbitrary conjunctions (and), disjunctions (or), and negations (not) of them.\nThe motivation behind this feature was to allow authors to write styles using new features when they were supported but degrade gracefully in browsers where they are not. Even though the nature of CSS already allows for graceful degradation, for example, by ignoring unsupported properties or values without disrupting other styles in the stylesheet, sometimes we need a bit more than that.\nCSS is ultimately a holistic technology, in that, even though you can use properties in isolation, the full power of CSS shines through when used in combination. This is especially evident when it comes to building web layouts. Having native feature detection in CSS makes it much more convenient to build with cutting-edge CSS for the latest browsers while supporting older browsers at the same time.\nBrowser support\nOpera first implemented feature queries in November 2012, both Chrome and Firefox had it since May 2013. There have been several articles about feature queries written over the years, however, it seems that awareness of its broad support isn\u2019t that well-known. Much of the earlier coverage on feature queries was not written in English, and perhaps that was a limiting factor.\n\n@supports \u2015 CSS\u306eFeature Queries by Masataka Yakura, August 8 2012\nNative CSS Feature Detection via the @supports Rule by Chris Mills, December 21 2012\nCSS @supports by David Walsh, April 3 2013\nResponsive typography with CSS Feature Queries by Aral Balkan, April 9 2013\nHow to use the @supports rule in your CSS by Lea Verou, January 31 2014\nCSS Feature Queries by Amit Tal, June 2 2014\nComing Soon: CSS Feature Queries by Adobe Web Platform Team, August 21 2014\nCSS feature queries mittels @supports by Daniel Erlinger, November 27 2014\n\nAs of December 2017, all current major browsers and their previous 2 versions support feature queries. Feature queries are also supported on Opera Mini, UC Browser and Samsung Internet. The only browsers that do not support feature queries are Internet Explorer and Blackberry Mobile, but that may be less of an issue than you might think.\n\n Can I Use css-featurequeries? Data on support for the css-featurequeries feature across the major browsers from caniuse.com.\n\nGranted, there is still a significant number of organisations that require support of Internet Explorer. Microsoft still continues to support IE11 for the life-cycle of Windows 7, 8 and 10. They have, however, stopped supporting older versions since January 12, 2016. It is inevitable that there will be organisations that, for some reason or another, make it mandatory to support IE, but as time goes on, this number will continue to shrink.\nJen Simmons wrote an extensive article called Using Feature Queries in CSS which discussed a matrix of potential situations when it comes to the usage of feature queries. The following image is a summary of the aforementioned matrix.\n\nThe most tricky situation we have to deal with is the box in the top-left corner, which are \u201cbrowsers that don\u2019t support feature queries, yet do support the feature in question\u201d. For cases like those, it really depends on the specific CSS feature you want to use and a subsequent evaluation of the pros and cons of not including that feature in spite of the fact the browser (most likely Internet Explorer) supports it.\nThe basics of feature queries\nAs with any conditional, feature queries operate on boolean logic, in other words, if the query resolves to true, apply the CSS properties within the block, or else just ignore the entire block altogether. The syntax of a simple feature query is as follows:\n.selector {\n /* Styles that are supported in old browsers */\n}\n\n@supports (property:value) {\n .selector {\n /* Styles for browsers that support the specified property */\n }\n}\nNote that the parentheses around the property:value pair are mandatory and the rule is invalid without them. Styles that apply to older browsers, i.e. fallback styles, should come first, followed by the newer properties, which are contained within the @supports conditional. Because of the cascade, fallback styles will be overridden by the newer properties in the modern browsers that support them.\nmain {\n background-color: red;\n}\n\n@supports (display:grid) {\n main {\n background-color: green;\n }\n}\nIn this example, browsers that support CSS grid will have a main element with a green background colour because the conditional resolves to true, while browsers that do not support grid will have a main element with a red background colour.\nThe implication of such behaviour means that we can layer on enhanced styles based on the features we want to use and these styles will show up in browsers that support them. But for those that do not, they will get a more basic look that still works anyway. And that will be our approach moving forward.\nBoolean operators for feature queries\nThe and operator allows us to test for support of multiple properties within a single conditional. This would be useful for cases where the desired output requires multiple cutting-edge features to be supported at the same time to work. All the property:value pairs listed in the conditional must resolve to true for the styles within the rule to be applied.\n@supports (transform: rotate(45deg)) and\n (writing-mode: vertical-rl) {\n /* Some CSS styles */\n}\nThe or operator allows us to list multiple property:value pairs in the conditional and as long as one of them resolves to true, the styles within the block will be applied. A relevant use-case would be for properties with vendor-prefixes.\n@supports (background: -webkit-gradient(linear, left top, left bottom, from(white), to(black))) or\n (background: -o-linear-gradient(top, white, black)) or\n (background: linear-gradient(to bottom, white, black)) {\n /* Some CSS styles */\n}\nThe not operator negates the resolution of the property:value pair in the conditional, resolving to false when the property is supported and vice versa. This is useful when there are two distinct sets of styles to be applied depending on the support of a specific feature. However, we do need to keep in mind the case where a browser does not support feature queries, and handle the styles for those browsers accordingly.\n@supports not (shape-outside: polygon(100% 80%,20% 0,100% 0)) {\n /* Some CSS styles */\n}\nTo avoid confusion between and and or, these operators must be explicitly declared as opposed to using commas or spaces. To prevent confusion caused by precedence rules, and, or and not operators cannot be mixed without a layer of parentheses.\nThis rule is not valid and the styles within the block will be ignored.\n@supports (transition-property: background-color) or\n (animation-name: fade) and\n (transform: scale(1.5)) {\n /* Some CSS styles */\n}\nTo make it work, parentheses must be added either around the two properties adjacent to the or or the and operator like so:\n@supports ((transition-property: background-color) or\n (animation-name: fade)) and\n (transform: scale(1.5)) {\n /* Some CSS styles */\n}\n@supports (transition-property: background-color) or\n ((animation-name: fade) and\n (transform: scale(1.5))) {\n /* Some CSS styles */\n}\nThe current specification states that whitespace is required after a not and on both sides of an and or or, but this may change in a future version of the specification. It is acceptable to add extra parentheses even when they are not needed, but omission of parentheses is considered invalid.\nCascading web design\nI\u2019d like to introduce the concept of cascading web design, an approach made possible with feature queries. Browser update cycles are much shorter these days, so new features and bug fixes are being pushed out a lot more frequently as compared to the early days of the web.\nWith the maturation of web standards, browser behaviour is less unpredictable than before, but each browser will still have their respective quirks. Chances are, the latest features will not ship across all browsers at the same time. But you know what? That\u2019s perfectly fine. If we accept this as a feature of the web, instead of a bug, we\u2019ve just opened up a lot more web design possibilities.\nThe following example is a basic, responsive grid layout of items laid out with flexbox, as viewed on IE11.\n\nWe can add a block of styles within an @supports rule to apply CSS grid properties for browsers that support them to enhance this layout, like so:\n\nThe web is not a static medium. It is dynamic and interactive and we manipulate this medium by writing code to tell the browser what we want it to do. Rather than micromanaging the pixels in our designs, maybe it\u2019s time we cede control of our designs to the browsers that render them. This means being okay with your designs looking different across browsers and devices.\nAs mentioned earlier, CSS works best when various properties are combined. It\u2019s one of those things whose whole is greater than the sum of its parts. So feature queries, when combined with media queries, allow us to design layouts that are most effective in the environment they have to perform in.\nSuch an approach requires interpolative thinking, on multiple levels. As web designers and developers, we don\u2019t just think in one fixed dimension, we get to think about how our design will morph on a narrow screen, or on an older browser, in addition to how it will appear on a browser with the latest features.\nIn the following example, the layout on the left is what IE11 users will see, the one in the middle is what Firefox users will see, because Firefox doesn\u2019t support CSS shapes yet, but once it does, it will then look like the layout on the right, which is what Chrome users see now.\n\nWith the release of CSS Grid this year, we\u2019ve hit another milestone in the evolution of the web as a medium. The beauty of the web is its backwards compatibility and generous fault tolerance. Browser features are largely additive, holding onto the good parts and building on top of them, while deprecating the bits that didn\u2019t work well.\nFeature queries allow us to progressively enhance our CSS, establishing a basic level of user experience across the widest range of browsers, while building in more advanced functionality for browsers who can use them. And hopefully, this will allow more of us to create designs that truly embrace the nature of the web.", "year": "2017", "author": "Chen Hui Jing", "author_slug": "chenhuijing", "published": "2017-12-01T00:00:00+00:00", "url": "https://24ways.org/2017/cascading-web-design/", "topic": "code"} {"rowid": 300, "title": "Taking Device Orientation for a Spin", "contents": "When The Police sang \u201cDon\u2019t Stand So Close To Me\u201d they weren\u2019t 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\u2019re there, we\u2019re 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.\nBut if you can\u2019t beat them, join them.\nA brave new world\nA 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\u2019t work in anything and went off disheartened into the corner for a bit of a sob.\nTurns 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\u2014we\u2019re still talking about browsers, after all.\nNow, of course they\u2019re 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\u2019re still trying to locate the documentation, right? Well, no! \nSo 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\u2019s find out.\nThe Device Orientation API\nThe phone-wavy API is more formally known as the DeviceOrientation Event Specification. It does a bunch of stuff that basically doesn\u2019t 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.\nThe 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.\nThe API calls those pitch, roll and yaw values alpha, beta and gamma. Chocks away:\nwindow.addEventListener('deviceorientation', function(e) {\n console.log(e.alpha);\n console.log(e.beta);\n console.log(e.gamma);\n});\nIf 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.\nOne important note\nLike may of these newfangled APIs, Device Orientation is only available over HTTPS. We\u2019re not allowed to have too much fun without protection, so make sure that you\u2019re working on a secure line. I\u2019ve found a quick and easy way to share my local dev environment over TLS with my devices is to use an ngrok tunnel.\nngrok http -host-header=rewrite mylocaldevsite.dev:80\nngrok will then set up a tunnel to your dev site with both HTTP and HTTPS URL options. You, of course, want the HTTPS option.\nRight, where were we?\nMake something to look at\nIt\u2019s all well and good having a bunch of numbers, but they\u2019re 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\u2019re not trying to be too clever here). Yeah, let\u2019s just build one of those.\nOur 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 \u2018window\u2019 so that the part we want to show is visible.\nHere 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.)\nThe details of the slider aren\u2019t important (we\u2019re 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 \u2018alt-nazi\u2019 or whatever).\nvar position_image = function(percent) {\n var pos = (img_W / 100)*percent;\n img.style.transform = 'translate(-'+pos+'px)'; \n};\nAll this does is figure out what that percentage means in terms of the image width, and set the transform: translate(\u2026); CSS property to move the image. (We use translate because it might be a bit faster to animate than left/right positioning.)\nOk. 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\u2019re done. (We\u2019re so not done.)\nThe maths bit\nIf 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\u2019ll note that the main value that is changing as we swing back and forth is the \u2018alpha\u2019 value. That\u2019s the one we want to track.\nAs our goal here is hey, these APIs are interesting and fun and not let\u2019s build the world\u2019s best panoramic image viewer, we\u2019ll start by making a few assumptions and simplifications:\n\nWhen the image loads, we\u2019ll centre the image and take the current nose-forward orientation reading as the middle.\nMoving left, we\u2019ll track to the left of the image (lower percentage).\nMoving right, we\u2019ll track to the right (higher percentage).\nIf the user spins round, does cartwheels or loads the page then hops on a plane and switches earthly hemispheres, they\u2019re on their own.\n\nNose-forward\nWhen 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\u2019t really matter to us, as we don\u2019t know which direction the user might be facing in anyway \u2014 we just need to record that initial state and then use it to compare any new readings.\nvar initial_position = null;\n\nwindow.addEventListener('deviceorientation', function(e) {\n if (initial_position === null) {\n initial_position = Math.floor(e.alpha);\n };\n\n var current_position = initial_position - Math.floor(e.alpha);\n});\n(I\u2019m rounding down the values with Math.floor() to make debugging easier - we\u2019ll take out the rounding later.)\nWe get our initial position if it\u2019s not yet been set, and then calculate the current position as a difference between the new value and the stored one.\nThese values are weird\nOne 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\u2019d expect if you do a forward roll.\nWhat I\u2019m 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\u2019t see it.\nvar rotation = current_position;\nif (current_position > 180) rotation = current_position-360;\nWhich way up?\nSince we\u2019re 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\u2019s easy to account for when you know which way up the device is, but in true browser style, the API for that bit isn\u2019t well supported. The best I can come up with is:\nvar screen_portrait = false;\nif (window.innerWidth < window.innerHeight) {\n screen_portrait = true;\n}\nIt works. Then we can use screen_portrait to branch our code:\nif (screen_portrait) {\n if (current_position > 180) rotation = current_position-360;\n} else {\n if (current_position < -180) rotation = 360+current_position;\n}\nHere\u2019s the code in action so you can see the values for yourself. If you change screen orientation you\u2019ll need to refresh the page (it\u2019s a demo!).\nLimiting rotation\nNow, 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\u00b0 to view a photo. Instead, we need to limit the range of movement to something like 60\u00b0-from-nose in either direction and normalise our values to pan the entire image across that 120\u00b0 range. -60 would be full-left (0%) and 60 would be full-right (100%).\nIf we set max_rotation = 60, that code ends up looking like this:\nif (rotation > max_rotation) rotation = max_rotation;\nif (rotation < (0-max_rotation)) rotation = 0-max_rotation;\n\nvar percent = Math.floor(((rotation + max_rotation)/(max_rotation*2))*100);\nWe should now be able to get a rotation from -60\u00b0 to +60\u00b0 expressed as a percentage. Try it for yourself.\nThe big reveal\nAll that\u2019s left to do is pass that percentage to our image positioning function and would you believe it, it might actually work.\nposition_image(percent);\nYou can see the final result and take it for a spin. Literally.\nSo 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. \nWhat we have made is progress. We\u2019ve 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\u2019t have this morning. Something we probably didn\u2019t 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\u2019ve learned that our browsers are just a little bit more capable than we thought.\nThe 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. \nThe 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\u2019s create things.", "year": "2016", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2016-12-24T00:00:00+00:00", "url": "https://24ways.org/2016/taking-device-orientation-for-a-spin/", "topic": "code"} {"rowid": 305, "title": "CSS Writing Modes", "contents": "Since you may not have a lot of time, I\u2019m going to start at the end, with the dessert.\nYou can use a little-known, yet important and powerful CSS property to make text run vertically. Like this.\n\nOr instead of running text vertically, you can layout a set of icons or interface buttons in this way. Or, of course, with anything on your page. \nThe CSS I\u2019ve applied makes the browser rethink the orientation of the world, and flow the layout of this element at a 90\u00b0 angle to \u201cnormal\u201d. Check out the live demo, highlight the headline, and see how the cursor is now sideways.\nSee the Pen Writing Mode Demo \u2014 Headline by Jen Simmons (@jensimmons) on CodePen.\n\nThe code for accomplishing this is pretty simple. \nh1 { \n writing-mode: vertical-rl;\n}\nThat\u2019s all it takes to switch the writing mode from the web\u2019s default horizontal top-to-bottom mode to a vertical right-to-left mode. If you apply such code to the html element, the entire page is switched, affecting the scroll direction, too. \nIn my example above, I\u2019m telling the browser that only the h1 will be in this vertical-rl mode, while the rest of my page stays in the default of horizontal-tb.\nSo now the dessert course is over. Let me serve up this whole meal, and explain the the CSS Writing Mode Specification.\nWhy learn about writing modes?\nThere are three reasons I\u2019m teaching writing modes to everyone\u2014including western audiences\u2014and explaining the whole system, instead of quickly showing you a simple trick.\n\n\nWe live in a big, diverse world, and learning about other languages is fascinating. Many of you lay out pages in languages like Chinese, Japanese and Korean. Or you might be inspired to in the future.\n\n\nUsing writing-mode to turn bits sideways is cool. This CSS can be used in all kinds of creative ways, even if you are working only in English.\n\nMost importantly, I\u2019ve found understanding Writing Modes incredibly helpful when understanding Flexbox and CSS Grid. Before I learned Writing Mode, I felt like there was still a big hole in my knowledge, something I just didn\u2019t get about why Grid and Flexbox work the way they do. Once I wrapped my head around Writing Modes, Grid and Flexbox got a lot easier. Suddenly the Alignment properties, align-* and justify-*, made sense.\n\nWhether you know about it or not, the writing mode is the first building block of every layout we create. You can do what we\u2019ve been doing for 25 years \u2013 and leave your page set to the default left-to-right direction, horizontal top-to-bottom writing mode. Or you can enter a world of new possibilities where content flows in other directions.\nCSS properties\nI\u2019m going to focus on the CSS writing-mode property in this article. It has five possible options:\n writing-mode: horizontal-tb;\n writing-mode: vertical-rl;\n writing-mode: vertical-lr;\n writing-mode: sideways-rl;\n writing-mode: sideways-lr;\nThe CSS Writing Modes Specification is designed to support a wide range of written languages in all our human and linguistic complexity. Which\u2014spoiler alert\u2014is pretty insanely complex. The global evolution of written languages has been anything but simple. \nSo I\u2019ve got to start with explaining some basic concepts of web page layout and writing systems. Then I can show you what these CSS properties do. \nInline Direction, Block Direction, and Character Direction\nIn the world of the web, there\u2019s a concept of \u2018block\u2019 and \u2018inline\u2019 layout. If you\u2019ve ever written display: block or display: inline, you\u2019ve leaned on these concepts. \nIn the default writing mode, blocks stack vertically starting at the top of the page and working their way down. Think of how a bunch of block-levels elements stack\u2014like a bunch of a paragraphs\u2014that\u2019s the block direction. \n\nInline is how each line of text flows. The default on the web is from left to right, in horizontal lines. Imagine this text that you are reading right now, being typed out one character at a time on a typewriter. That\u2019s the inline direction. \n\nThe character direction is which way the characters point. If you type a capital \u201cA\u201d for instance, on which side is the top of the letter? Different languages can point in different directions. Most languages have their characters pointing towards the top of the page, but not all.\n\nPut all three together, and you start to see how they work as a system. \nThe default settings for the web work like this.\nNow that we know what block, inline, and character directions mean, let\u2019s see how they are used in different writing systems from around the world.\nThe four writing systems of CSS Writing Modes\nThe CSS Writing Modes Specification handles all the use cases for four major writing systems; Latin, Arabic, Han and Mongolian. \nLatin-based systems\nOne writing system dominates the world more than any other, reportedly covering about 70% of the world\u2019s population. \n\nThe text is horizontal, running from left to right, or LTR. The block direction runs from top to bottom. \nIt\u2019s called the Latin-based system because it includes all languages that use the Latin alphabet, including English, Spanish, German, French, and many others. But there are many non-Latin-alphabet languages that also use this system, including Greek, Cyrillic (Russian, Ukrainian, Bulgarian, Serbian, etc.), and Brahmic scripts (Devanagari, Thai, Tibetan), and many more.\nYou don\u2019t need to do anything in your CSS to trigger this mode. This is the default. \nBest practices, however, dictate that you declare in your opening element which language and which direction (LTR or RTL) you are using. This website, for instance, uses to let the browser know this content is published in Great Britian\u2019s version of English, in a left to right direction. \nArabic-based systems\nArabic, Hebrew and a few other languages run the inline direction from right to left. This is commonly known as RTL. \nNote that the inline direction still runs horizontally. The block direction runs from top to bottom. And the characters are upright.\n\nIt\u2019s not just the flow of text that runs from right to left, but everything about the layout of the website. The upper right-hand corner is the starting position. Important things are on the right. The eyes travel from right to left. So, typically RTL websites use layouts that are just like LTR websites, only flipped.\nOn websites that support both LTR and RTL, like the United Nations\u2019 site at un.org, the two layouts are mirror images of each other.\nFor many web developers, our experiences with internationalization have focused solely on supporting Arabic and Hebrew script. \nCSS layout hacks for internationalization & RTL\nTo prepare an LTR project to support RTL, developers have had to create all sorts of hacks. For example, the Drupal community started a convention of marking every margin-left and -right, every padding-left and -right, every float: left and float: right with the comment /* LTR */. Then later developers could search for each instance of that exact comment, and create stylesheets to override each left with right, and vice versa. It\u2019s a tedious and error prone way to work. CSS itself needed a better way to let web developers write their layout code once, and easily switch language directions with a single command.\nOur new CSS layout system does exactly that. Flexbox, Grid and Alignment use start and end instead of left and right. This lets us define everything in relationship to the writing system, and switch directions easily. By writing justify-content: flex-start, justify-items: end, and eventually margin-inline-start: 1rem we have code that doesn\u2019t need to be changed. \nThis is a much better way to work. I know it can be confusing to think through start and end as replacements for left and right. But it\u2019s better for any multiligual project, and it\u2019s better for the web as a whole.\nSadly, I\u2019ve seen CSS preprocessor tools that claim to \u201cfix\u201d the new CSS layout system by getting rid of start and end and bringing back left and right. They want you to use their tool, write justify-content: left, and feel self-righteous. It seems some folks think the new way of working is broken and should be discarded. It was created, however, to fulfill real needs. And to reflect a global internet. As Bruce Lawson says, WWW stands for the World Wide Web, not the Wealthy Western Web. Please don\u2019t try to convince the industry that there\u2019s something wrong with no longer being biased towards western culture. Instead, spread the word about why this new system is here. \nSpend a bit of time drilling the concept of inline and block into your head, and getting used to start and end. It will be second nature soon enough. \nI\u2019ve also seen CSS preprocessors that let us use this new way of thinking today, even as all the parts aren\u2019t fully supported by browsers yet. Some tools let you write text-align: start instead of text-align: left, and let the preprocessor handle things for you. That is terrific, in my opinion. A great use of the power of a preprocessor to help us switch over now. \nBut let\u2019s get back to RTL. \nHow to declare your direction\nYou don\u2019t want to use CSS to tell the browser to switch from an LTR language to RTL. You want to do this in your HTML. That way the browser has the information it needs to display the document even if the CSS doesn\u2019t load.\nThis is accomplished mainly on the html element. You should also declare your main language. As I mentioned above, the 24 ways website is using to declare the LTR direction and the use of British English. The UN Arabic website uses to declare the site as an Arabic site, using a RTL layout. \nThings get more complicated when you\u2019ve got a page with a mix of languages. But I\u2019m not going to get into all of that, since this article is focused on CSS and layouts, not explaining everything about internationalization. \nLet me just leave direction here by noting that much of the heavy work of laying out the characters which make up each word is handled by Unicode. If you are interested in learning more about LTR, RTL and bidirectional text, watch this video: Introduction to Bidirectional Text, a presentation by Elika Etemad. \nMeanwhile, let\u2019s get back to CSS.\nThe writing mode CSS for Latin-based and Arabic-based systems\nFor both of these systems\u2014Latin-based and Arabic-based, whether LTR or RTL\u2014the same CSS property applies for specifying the writing mode: writing-mode: horizontal-tb. That\u2019s because in both systems, the inline text flow is horizontal, while the block direction is top-to-bottom. This is expressed as horizontal-tb.\nhorizontal-tb is the default writing mode for the web, so you don\u2019t need to specify it unless you are overriding something else higher up in the cascade. You can just imagine that every site you\u2019ve ever built came with:\nhtml {\n writing-mode: horizontal-tb;\n}\nNow let\u2019s turn our attention to the vertical writing systems. \nHan-based systems\nThis is where things start to get interesting. \nHan-based writing systems include CJK languages, Chinese, Japanese, Korean and others. There are two options for laying out a page, and sometimes both are used at the same time.\nMuch of CJK text is laid out like Latin-based languages, with a horizontal top-to-bottom block direction, and a left-to-right inline direction. This is the more modern way to doing things, started in the 20th century in many places, and further pushed into domination by the computer and later the web. \nThe CSS to do this bit of the layouts is the same as above:\nsection {\n writing-mode: horizontal-tb;\n}\nOr, you know, do nothing, and get that result as a default. \nAlternatively Han-based languages can be laid out in a vertical writing mode, where the inline direction runs vertically, and the block direction goes from right to left. \nSee both options in this diagram:\n\nNote that the horizontal text flows from left to right, while the vertical text flows from right to left. Wild, eh? \nThis Japanese issue of Vogue magazine is using a mix of writing modes. The cover opens on the left spine, opposite of what an English magazine does. \n\nThis page mixes English and Japanese, and typesets the Japanese text in both horizontal and vertical modes. Under the title \u201cRichard Stark\u201d in red, you can see a passage that\u2019s horizontal-tb and LTR, while the longer passage of text at the bottom of the page is typeset vertical-rl. The red enlarged cap marks the beginning of that passage. The long headline above the vertical text is typeset LTR, horizontal-tb.\n\nThe details of how to set the default of the whole page will depend on your use case. But each element, each headline, each section, each article can be marked to flow the opposite of the default however you\u2019d like.\nFor example, perhaps you leave the default as horizontal-tb, and specify your vertical elements like this:\ndiv.articletext {\n writing-mode: vertical-rl;\n}\nOr alternatively you could change the default for the page to a vertical orientation, and then set specific elements to horizontal-tb, like this:\nhtml { \n writing-mode: vertical-rl;\n}\nh2, .photocaptions, section {\n writing-mode: horizontal-tb;\n}\nIf your page has a sideways scroll, then the writing mode will determine whether the page loads with upper left corner as the starting point, and scroll to the right (horizontal-tb as we are used to), or if the page loads with the upper right corner as the starting point, scrolling to the left to display overflow. Here\u2019s an example of that change in scrolling direction, in a CSS Writing Mode demo by Chen Hui Jing. Check out her demo \u2014 you can switch from horizontal to vertical writing modes with a checkbox and see the difference. \n\nMongolian-based systems\nNow, hopefully so far all of this kind of makes sense. It might be a bit more complicated than expected, but it\u2019s not so hard. Well, enter the Mongolian-based systems.\nMongolian is also a vertical script language. Text runs vertically down the page. Just like Han-based systems. There are two major differences. First, the block direction runs the other way. In Mongolian, block-level elements stack from left to right. \nHere\u2019s a drawing of how Wikipedia would look in Mongolian if it were laid out correctly.\nPerhaps the Mongolian version of Wikipedia will be redone with this layout.\nNow you might think, that doesn\u2019t look so weird. Tilt your head to the left, and it\u2019s very familiar. The block direction starts on the left side of the screen and goes to the right. The inline direction starts on the top of the page and moves to the bottom (similar to RTL text, just turned 90\u00b0 counter-clockwise). But here comes the other huge difference. The character direction is \u201cupside down\u201d. The top of the Mongolian characters are not pointing to the left, towards the start edge of the block direction. They point to the right. Like this:\n\nNow you might be tempted to ignore all this. Perhaps you don\u2019t expect to be typesetting Mongolian content anytime soon. But here\u2019s why this is important for everyone \u2014 the way Mongolian works defines the results writing-mode: vertical-lr. And it means we cannot use vertical-lr for typesetting content in other languages in the way we might otherwise expect. \nIf we took what we know about vertical-rl and guessed how vertical-lr works, we might imagine this:\n\nBut that\u2019s wrong. Here\u2019s how they actually compare:\n\nSee the unexpected situation? In both writing-mode: vertical-rl and writing-mode: vertical-lr latin text is rotated clockwise. Neither writing mode let\u2019s us rotate text counter-clockwise. \nIf you are typesetting Mongolian content, apply this CSS in the same way you would apply writing-mode to Han-based writing systems. To the whole page on the html element, or to specific pages of the page like this:\nsection {\n writing-mode: vertical-lr;\n}\nNow, if you are using writing-mode for a graphic design effect on a language that is otherwise typesets horizontally, I don\u2019t think writing-mode: vertical-lr is useful. If the text wraps onto two lines, it stacks in a very unexpected way. So I\u2019ve sort of obliterated it from my toolkit. I find myself using writing-mode: vertical-rl a lot. And never using -lr. Hm.\nWriting modes for graphic design\nSo how do we use writing-mode to turn English headlines sideways? We could rely on transform: rotate()\nHere are two examples, one for each direction. (By the way, each of these demos use CSS Grid for their overall layout, so be sure to test them in a browser that supports CSS Grid, like Firefox Nightly.)\n\nIn this demo 4A, the text is rotated clockwise using this code: \nh1 {\n writing-mode: vertical-rl;\n}\n\nIn this demo 4B, the text is rotated counter-clockwise using this code: \nh1 {\n writing-mode: vertical-rl;\n transform: rotate(180deg);\n text-align: right;\n}\nI use vertical-rl to rotate the text so that it takes up the proper amount of space in the overall flow of the layout. Then I rotate it 180\u00b0 to spin it around to the other direction. And then I use text-align: right to get it to rise up to the top of it\u2019s container. This feels like a hack, but it\u2019s a hack that works.\nNow what I would like to do instead is use another CSS value that was designed for this use case \u2014 one of the two other options for writing mode.\nIf I could, I would lay out example 4A with:\nh1 {\n writing-mode: sideways-rl;\n}\nAnd layout example 4B with: \nh1 {\n writing-mode: sideways-lr;\n}\nThe problem is that these two values are only supported in Firefox. None of the other browsers recognize sideways-*. Which means we can\u2019t really use it yet. \nIn general, the writing-mode property is very well supported across browsers. So I\u2019ll use writing-mode: vertical-rl for now, with the transform: rotate(180deg); hack to fake the other direction. \nThere\u2019s much more to what we can do with the CSS designed to support multiple languages, but I\u2019m going to stop with this intermediate introduction. \nIf you do want a bit more of a taste, look at this example that adds text-orientation: upright; to the mix \u2014 turning the individual letters of the latin font to be upright instead of sideways.\n\nIt\u2019s this demo 4C, with this CSS applied: \nh1 {\n writing-mode: vertical-rl;\n text-orientation: upright;\n text-transform: uppercase;\n letter-spacing: -25px;\n}\nYou can check out all my Writing Modes demos at labs.jensimmons.com/#writing-modes. \n\nI\u2019ll leave you with this last demo. One that applies a vertical writing mode to the sub headlines of a long article. I like how small details like this can really bring a fresh feeling to the content. \nSee the Pen Writing Mode Demo \u2014 Article Subheadlines by Jen Simmons (@jensimmons) on CodePen.", "year": "2016", "author": "Jen Simmons", "author_slug": "jensimmons", "published": "2016-12-23T00:00:00+00:00", "url": "https://24ways.org/2016/css-writing-modes/", "topic": "code"} {"rowid": 312, "title": "Preparing to Be Badass Next Year", "contents": "Once we\u2019ve eaten our way through the holiday season, people will start to think about new year\u2019s resolutions. We tend to focus on things that we want to change\u2026 and often things that we don\u2019t like about ourselves to \u201cfix\u201d. We set rules for ourselves, or try to start new habits or stop bad ones. We focus in on things we will or won\u2019t do. \nFor many of us the list of things we \u201cought\u201d to be spending time on is just plain overwhelming \u2013 family, charity/community, career, money, health, relationships, personal development. \nIt\u2019s kinda scary even just listing it out, isn\u2019t it? I want to encourage you to think differently about next year.\nThe ever-brilliant Kathy Sierra articulates a better approach really well when talking about the attitude we should have to building great products. She tells us to think not about what the user will do with our product, but about what they are trying to achieve in the real world and how our product helps them to be badass1.\nWhen we help the user be badass, then we are really making a difference. \nI suppose this is one way of saying: focus not on what you will do, focus on what it will help you achieve. How will it help you be awesome?\nIn what ways do you want to be more badass next year?\nA professional lens\nThough of course you might want to focus in on health or family or charity or community or another area next year, many people will want to become more badass in their chosen career. \nSo let\u2019s talk about a scaffold to help you figure out your professional / career development next year. \nFirst up, an assumption: everyone wants to be awesome. Nobody gets up in the morning aiming to be crap at their job. Nobody thinks to themselves \u201cToday I am aiming for just south of mediocre, and if I can mess up everybody else\u2019s ability to do good work then that will be just perfect2\u201d. \nErgo, you want to be awesome. So what does awesome look like? \nDanger!\nThe big trap that people fall into when think about their professional development is to immediately focus on the things that they aren\u2019t good at. When you ask people \u201cwhat do you want to work on getting better at next year?\u201d they frequently gravitate to the things that they believe they are bad at. \nWhy is this a trap? Because if you focus all your time and energy on improving the areas that you suck at, you are going to end up middling at everything. Going from bad \u2192 mediocre at a given skill / behaviour takes a bunch of time and energy. So if you spend all your time going from bad \u2192 mediocre at things, what do you think you end up? That\u2019s right, mediocre. \nMediocrity is not a great career goal, kids. \nWhat do you already rock at?\nThe much better investment of time and energy is to go from good \u2192 awesome. It often takes the same amount of relative time and energy, but wow the end result is better! So first, ask yourself and those who know you well what you are already pretty damn good at. Combat imposter syndrome by asking others. \nThen figure out how to double down on those things. What does brilliant look like for a given skill? What\u2019s the knowledge or practice that you need to level yourself up even further in that thing?\nBut what if I really really suck?\nAdmittedly, sometimes something you suck at really is holding you back. But it\u2019s important to separate out weaknesses (just something you suck at) from controlling weaknesses (something you suck at that actually matters for your chosen career). \nIf skill x is just not an important thing for you to be good at, you may never need to care that you aren\u2019t good at it. If your current role or the one you aspire to next really really requires you to be great at x, then it\u2019s worth investing your time and energy (and possibly money too) getting better at it.\nSo when you look at the things that you aren\u2019t good at, which of those are actually essential for success?\nThe right ratio\nA good rule of thumb is to pick three things you are already good at to work on becoming awesome at and limit yourself to one weakness that you are trying to improve on. That way you are making sure that you get to awesome in areas where you already have an advantage, and limit the amount of time you are spending on going from bad \u2192 mediocre. \nLevelling up learning\nSo once you\u2019ve figured out your areas you want to focus on next year, what do you actually decide to do? \nMost of all, you should try to design your day-to-day work in a way that it is also an effective learning experience. This means making sure you have a good feedback loop \u2013 you get to try something, see if it works, learn from it, rinse and repeat. \nIt\u2019s also about balance: you want to be challenged enough for work to be interesting, without it being so hard it\u2019s frustrating. You want to do similar / the same things often enough that you get to learn and improve, without it being so repetitive that it\u2019s boring. \nContinuously getting better at things you are already good at is actually both easier and harder than it sounds. The advantage is that it\u2019s pretty easy to add the feedback loop to make sure that you are improving; the disadvantage is that you\u2019re already good at these skills so you could easily just \u201cdo\u201d without ever stopping to reflect and improve. Build in time for personal retrospectives (\u201cWhat went well? What didn\u2019t? What one thing will I choose to change next time?\u201d) and find a way of getting feedback from outside sources as well. \nAs for the new skills, it\u2019s worth knowing that skill development follows a particular pattern:\n\nWe all start out unconsciously incompetent (we don\u2019t know what to do and if we tried we\u2019d unwittingly get it wrong), progress on to conscious incompetence (we now know we\u2019re doing it wrong) then conscious competence (we\u2019re doing it right but wow it takes effort and attention) and eventually get to unconscious competence (automatically getting it right). \nYour past experiences and knowledge might let you move faster through these stages, but no one gets to skip them. Invest the time and remember you need the feedback loop to really improve. \nWhat about keeping up?\nEverything changes very fast in our industry. We need to invest in not falling behind, in keeping on top of what great looks like. There are a bunch of ways to do this, from reading blog posts, following links on Twitter, reading books to attending conferences or workshops, or just finding time to build things in new ways or with new technologies. \nWhich will work best for you depends on how you best learn. Do you prefer to swallow a book? Do you learn most by building or experimenting? \nWhatever your learning style though, remember that there are three real needs:\n\nScan the landscape (what\u2019s changing, does it matter)\nGain the knowledge or skills (get the detail)\nApply the knowledge or skills (use it in reality)\n\nWhen you remember that you need all three of these things it can help you get more of what you do. \nFor me personally, I use a combination of conferences and blogs / Twitter to scan the landscape. Half of what I want out of a conference is just a list of things to have on my radar that might become important. I then pick a couple of things to go read up on more (I personally learn most effectively by swallowing a book or spec or similar). And then I pick one thing at a time to actually apply in real life, to embed the skill / knowledge. \nIn summary\n\nAim to be awesome (mediocrity is not a career goal).\nFigure out what you already rock at.\nOnly care about stuff you suck at that matters for your career.\nPick three things to go from good \u2192 awesome and one thing to go from bad \u2192 mediocre (or mediocre \u2192 good) this year.\nDesign learning into your daily work.\nScan the landscape, learn new stuff, apply it for real. \nBe badass!\n\n\n\n\n\nShe wrote a whole book about it. You should read it: Badass: Making Users Awesome\u00a0\u21a9\n\n\nBefore you argue too vehemently: I suppose some antisocial sociopathic bastards do exist. Identify them, and then RUN AWAY FAST AS YOU CAN #realtalk\u00a0\u21a9", "year": "2016", "author": "Meri Williams", "author_slug": "meriwilliams", "published": "2016-12-22T00:00:00+00:00", "url": "https://24ways.org/2016/preparing-to-be-badass-next-year/", "topic": "business"} {"rowid": 301, "title": "Stretching Time", "contents": "Time is valuable. It\u2019s a precious commodity that, if we\u2019re not too careful, can slip effortlessly through our fingers. When we think about the resources at our disposal we\u2019re often guilty of forgetting the most valuable resource we have to hand: time.\nWe 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.\nIt doesn\u2019t matter if we\u2019re rich or we\u2019re 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.\nI believe we can \u2018stretch\u2019 time, ensuring we make the most of every second and maximising the opportunities that time affords us.\nThrough a combination of \u2018Structured Procrastination\u2019 and \u2018Focused Finishing\u2019 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\u2019s required. A win win, I\u2019m sure you\u2019ll agree.\nStructured Procrastination\nI\u2019m a terrible procrastinator. I used to think that was a curse \u2013 \u201cWhy didn\u2019t I just get started earlier?\u201d \u2013 over time, however, I\u2019ve started to see procrastination as a valuable tool if it is used in a structured manner.\nDon Norman refers to procrastination as \u2018late binding\u2019 (a term I\u2019ve happily hijacked). As he argues, in Why Procrastination Is Good, late binding (delay, or procrastination) offers many benefits:\n\nDelaying decisions until the time for action is beneficial\u2026 it provides the maximum amount of time to think, plan, and determine alternatives.\n\nWe live in a world that is constantly changing and evolving, as such the best time to execute is often \u2018just in time\u2019. By delaying decisions until the last possible moment we can arrive at solutions that address the current reality more effectively, resulting in better outcomes.\nProcrastination isn\u2019t 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 \u2018prime the brain\u2019.\nAs 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.\nBy 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\u2019re working on and, perhaps, discover other elements that will serve you well in future tasks.\nWhen 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 \u2013 if not useful for this article \u2013 would serve me well in the future. \nRon Burgundy summarises this neatly:\n\nProcrastinator? No. I just wait until the last second to do my work because I will be older, therefore wiser.\n\nAn \u2018older, therefore wiser\u2019 mind is a good thing. We\u2019re incredibly fortunate to live in a world where we have a wealth of information at our fingertips. Don\u2019t 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.\nDeadlines 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.\nLike everyone I\u2019ll 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.\nAt this point we need to focus.\nFocused Finishing\nWe live in an age of constant distraction. Smartphones are both a blessing and a curse, they keep us connected, but if we\u2019re not careful the constant connection they provide can interrupt our flow.\nWhen a deadline is accelerating towards us it\u2019s important to set aside the distractions and carve out a space where we can work in a clear and focused manner.\nWhen it\u2019s time to finish, it\u2019s important to avoid context switching and focus. All those micro-interactions throughout the day \u2013 triaging your emails, checking social media and browsing the web \u2013 can get in the way of you hitting your deadline. At this point, they\u2019re distractions.\nChunking tasks and managing when they\u2019re scheduled can improve your productivity by a surprising order of magnitude. At this point it\u2019s important to remove distractions which result in \u2018attention residue\u2019, where your mind is unable to focus on the current task, due to the mental residue of other, unrelated tasks.\nBy focusing on a single task in a focused manner, it\u2019s possible to minimise the negative impact of attention residue, allowing you to maximise your performance on the task at hand.\nCal Newport explores this in his excellent book, Deep Work, which I would highly recommend reading. As he puts it:\n\nEfforts to deepen your focus will struggle if you don\u2019t simultaneously wean your mind from a dependence on distraction.\n\nTo help you focus on finishing it\u2019s helpful to set up a work-focused environment that is purposefully free from distractions. There\u2019s a time and a place for structured procrastination, but \u2013 equally \u2013 there\u2019s a time and a place for focused finishing.\nThe French term \u2018mise en place\u2019 is drawn from the world of fine cuisine \u2013 I discovered it when I was procrastinating \u2013 and it\u2019s applicable in this context. The term translates as \u2018putting in place\u2019 or \u2018everything in its place\u2019 and it refers to the process of getting the workplace ready before cooking.\nJust like a professional chef organises their utensils and arranges their ingredients, so too can you.\nThanks to the magic of multiple users on computers, it\u2019s possible to create a separate user on your computer \u2013 without access to email and other social tools \u2013 so that you can switch to that account when you need to focus and hit the deadline.\nAnother, less technical way of achieving the same result \u2013 depending, of course, upon your line of work \u2013 is to close your computer and find some non-digital, unconnected space to work in.\nThe goal is to carve out time to focus so you can finish. As Newport states:\n\nIf you don\u2019t produce, you won\u2019t thrive \u2013 no matter how skilled or talented you are.\n\nProcrastination is fine, but only if it\u2019s accompanied by finishing. Create the space to finish and you\u2019ll enjoy the best of both worlds.\nIn closing\u2026\nThere 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.\nBy combining the processes of \u2018Structured Procrastination\u2019 and \u2018Focused Finishing\u2019 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.\nMake the most of your time, you only get so much. Use every second productively and you\u2019ll be thankful that you did. Don\u2019t waste your time, once it\u2019s gone, it\u2019s gone\u2026 and you can never get it back.", "year": "2016", "author": "Christopher Murphy", "author_slug": "christophermurphy", "published": "2016-12-21T00:00:00+00:00", "url": "https://24ways.org/2016/stretching-time/", "topic": "process"} {"rowid": 304, "title": "Five Lessons From My First 18 Months as a Dev", "contents": "I recently moved from Sydney to London to start a dream job with Twitter as a software engineer. A software engineer! Who would have thought.\nHaving started my career as a journalist, the title \u2018engineer\u2019 is very strange to me. The notion of writing in first person is also very strange. Journalists are taught to be objective, invisible, to keep yourself out of the story. And here I am writing about myself on a public platform. Cringe.\nSince I started learning to code I\u2019ve often felt compelled to write about my experience. I want to share my excitement and struggles with the world! But as a junior I\u2019ve been held back by thoughts like \u2018whatever you have to say won\u2019t be technical enough\u2019, \u2018any time spent writing a blog would be better spent writing code\u2019, \u2018blogging is narcissistic\u2019, etc.\u00a0\nWell, I\u2019ve been told that your thirties are the years where you stop caring so much about what other people think. And I\u2019m almost 30. So here goes!\nThese are five key lessons from my first year and a half in tech:\nDeployments should delight, not dread \n\nLesson #1: Making your deployment process as simple as possible is worth the investment.\n\nIn my first dev job, I dreaded deployments. We would deploy every Sunday night at 8pm. Preparation would begin the Friday before. A nominated deployment manager would spend half a day tagging master, generating scripts, writing documentation and raising JIRAs. The only fun part was choosing a train gif to post in HipChat: \u2018All aboard! The deployment train leaves in 3, 2, 1\u2026\u201d\n\nWhen Sunday night came around, at least one person from every squad would need to be online to conduct smoke tests. Most times, the deployments would succeed. Other times they would fail. Regardless, deployments ate into people\u2019s weekend time\u200a\u2014\u200aand they were intense. Devs would rush to have their code approved before the Friday cutoff. Deployment managers who were new to the process would fear making a mistake.\u00a0\nThe team knew deployments were a problem. They were constantly striving to improve them. And what I\u2019ve learnt from Twitter is that when they do, their lives will be bliss.\nTweetDeck\u2019s deployment process fills me with joy and delight. It\u2019s quick, easy and stress free. In fact, it\u2019s so easy I deployed code on my first day in the job! Anyone can deploy, at any time of day, with a single command. Rollbacks are just as simple. There\u2019s no rush to make the deployment train. No manual preparation. No fuss. Value\u200a\u2014\u200awhether in the form of big new features, simple UI improvements or even production bug fixes\u200a\u2014\u200acan be shipped in an instant. The team assures me the process wasn\u2019t always like this. They invested lots of time in making their deployments better. And it\u2019s clearly paid off.\nCode reviews need love, time and acceptance \n\nLesson #2: Code reviews are a three-way gift. Every time I review someone else\u2019s code, I help them, the team and myself.\n\nCode reviews were another pain point in my previous job. And to be honest, I was part of the problem. I would raise code reviews that were far too big. They would take days, sometimes weeks, to get merged. One of my reviews had 96 comments! I would rarely review other people\u2019s code because I felt too junior, like my review didn\u2019t carry any weight.\u00a0\nThe review process itself was also tiring, and was often raised in retrospectives as being slow. In order for code to be merged it needed to have ticks of approval from two developers and a third tick from a peer tester. It was the responsibility of the author to assign the reviewers and tester. It was felt that if it was left to team members to assign themselves to reviews, the \u201csomeone else will do it\u201d mentality would kick in, and nothing would get done.\nAt TweetDeck, no-one is specifically assigned to reviews. Instead, when a review is raised, the entire team is notified. Without fail, someone will jump on it. Reviews are seen as blocking. They\u2019re seen to be equally, if not more important, than your own work. I haven\u2019t seen a review sit for longer than a few hours without comments.\u00a0\nWe also don\u2019t work on branches. We push single commits for review, which are then merged to master. This forces the team to work in small, incremental changes. If a review is too big, or if it\u2019s going to take up more than an hour of someone\u2019s time, it will be sent back.\nWhat I\u2019ve learnt so far at Twitter is that code reviews must be small. They must take priority. And they must be a team effort. Being a new starter is no \u201cget out of jail free card\u201d. In fact, it\u2019s even more of a reason to be reviewing code. Reviews are a great way to learn, get across the product and see different programming styles. If you\u2019re like me, and find code reviews daunting, ask to pair with a senior until you feel more confident. I recently paired with my mentor at Twitter and found it really helpful.\nGet friendly with feature flagging \n\nLesson #3: Feature flagging gives you complete control over how you build and release a project.\n\nSay you\u2019re implementing a new feature. It\u2019s going to take a few weeks to complete. You\u2019ll complete the feature in small, incremental changes. At what point do these changes get merged to master? At what point do they get deployed? Do you start at the back end and finish with the UI, so the user won\u2019t see the changes until they\u2019re ready? With feature flagging\u200a\u2014\u200ait doesn\u2019t matter. In fact, with feature flagging, by the time you are ready to release your feature, it\u2019s already deployed, sitting happily in master with the rest of your codebase.\u00a0\nA feature flag is a boolean value that gets wrapped around the code relating to the thing you\u2019re working on. The code will only be executed if the value is true.\nif (TD.decider.get(\u2018new_feature\u2019)) {\n //code for new feature goes here\n}\nIn my first dev job, I deployed a navigation link to the feature I\u2019d been working on, making it visible in the product, even though the feature wasn\u2019t ready. \u201cWhy didn\u2019t you use a feature flag?\u201d a senior dev asked me. An honest response would have been: \u201cBecause they\u2019re confusing to implement and I don\u2019t understand the benefits of using them.\u201d The fix had to wait until the next deployment.\nThe best thing about feature flagging at TweetDeck is that there is no need to deploy to turn on or off a feature. We set the status of the feature via an interface called Deckcider, and the code makes regular API requests to get the status.\u00a0\nAt TweetDeck we are also able to roll our features out progressively. The first rollout might be to a staging environment. Then to employees only. Then to 10 per cent of users, 20 per cent, 30 per cent, and so on. A gradual rollout allows you to monitor for bugs and unexpected behaviour, before releasing the feature to the entire user base.\nSometimes a piece of work requires changes to existing business logic. So the code might look more like this:\nif (TD.decider.get(\u2018change_to_existing_feature\u2019)) {\n //new logic goes here\n} else {\n //old logic goes here\n}\nThis seems messy, right? Riddling your code with if else statements to determine which path of logic should be executed, or which version of the UI should be displayed. But at Twitter, this is embraced. You can always clean up the code once a feature is turned on. This isn\u2019t essential, though. At least not in the early days. When a cheeky bug is discovered, having the flag in place allows the feature to be very quickly turned off again. \nLet data and experimentation drive development \n\nLesson #4: Use data to determine the direction of your product and measure its success.\n\nThe first company I worked for placed a huge amount of emphasis on data-driven decision making. If we had an idea, or if we wanted to make a change, we were encouraged to \u201cbring data\u201d to show why it was necessary. \u201cWithout data, you\u2019re just another person with an opinion,\u201d the chief data scientist would say. This attitude helped to ensure we were building the right things for our customers. Instead of just plucking a new feature out of thin air, it was chosen based on data that reflected its need.\nBut how do you design that feature? How do you know that the design you choose will have the desired impact? That\u2019s where experiments come into play.\u00a0\nAt TweetDeck we make UI changes that we hope will delight our users. But the assumptions we make about our users are often wrong. Our front-end team recently sat in a room and tried to guess which UIs from A/B tests had produced better results. Half the room guessed incorrectly every time.\nWe can\u2019t assume a change we want to make will have the impact we expect. So we run an experiment. Here\u2019s how it works. Users are placed into buckets. One bucket of users will have access to the new feature, the other won\u2019t. We hypothesise that the bucket exposed to the new feature will have better results. The beauty of running an experiment is that we\u2019ll know for sure. Instead of blindly releasing the feature to all users without knowing its impact, once the experiment has run its course, we\u2019ll have the data to make decisions accordingly.\nHire the developer, not the degree\n\nLesson #5: Testing candidates on real world problems will allow applicants from all backgrounds to shine.\n\nSurely, a company like Twitter would give their applicants insanely difficult code tests, and the toughest technical questions, that only the cleverest CS graduates could pass, I told myself when applying for the job. Lucky for me, this wasn\u2019t the case. The process was insanely difficult\u2014don\u2019t get me wrong\u2014but the team at TweetDeck gave me real world problems to solve.\nThe first code test involved bug fixes, performance and testing. The second involved DOM traversal and manipulation. Instead of being put on the spot in a room with a whiteboard and pen I was given a task, access to the internet, and time to work on it. Similarly, in my technical interviews, I was asked to pair program on real world problems that I was likely to face on the job.\nIn one of my phone screenings I was told Twitter wanted to increase diversity in its teams. Not just gender diversity, but also diversity of experience and background. Six months later, with a bunch of new hires, team lead Tom Ashworth says TweetDeck has the most diverse team it\u2019s ever had. \u201cWe designed an interview process that gave us a way to simulate the actual job,\u201d he said. \u201cIt\u2019s not about testing whether you learnt an algorithm in school.\u201d\nIs this lowering the bar? No. The bar is whether a candidate has the ability to solve problems they are likely to face on the job. I recently spoke to a longstanding Atlassian engineer who said they hadn\u2019t seen an algorithm in their seven years at the company.\nThese days, only about 50 per cent of developers have computer science degrees. The majority of developers are self taught, learn on the job or via online courses. If you want to increase diversity in your engineering team, ensure your interview process isn\u2019t excluding these people.", "year": "2016", "author": "Amy Simmons", "author_slug": "amysimmons", "published": "2016-12-20T00:00:00+00:00", "url": "https://24ways.org/2016/my-first-18-months-as-a-dev/", "topic": "process"} {"rowid": 310, "title": "Fairytale of new Promise", "contents": "There are only four good Christmas songs.\nI know, yeah, JavaScript or whatever. We\u2019ll get to that in a minute, I promise.\nFirst\u2014and I cannot stress this enough\u2014 there are four good Christmas songs. You\u2019re free to disagree with me here, of course, but please try to understand that you will be wrong.\nThey don\u2019t all have the most safe-for-work titles; I can\u2019t list all of them here, but if you choose to let your fingers do the walkin\u2019 to your nearest search engine, I will say that one was released by the band FEAR way back in 1982 and one was on Run the Jewels\u2019 self-titled debut album. The lyrics are a hell of a lot worse than the titles, so maybe wait until you get home from work before you queue them up. Wear headphones, if you\u2019ve got thin walls.\nFor my money, though, the two I can reference by name are the top of that small heap: Tom Waits\u2019 Christmas Card from a Hooker in Minneapolis, and The Pogues\u2019 Fairytale of New York. The former once held the honor of being the only good Christmas song\u2014about which which I was also unequivocally correct, right up until I changed my mind. It\u2019s not the song up for discussion today, but feel free to familiarize yourself just the same\u2014I\u2019ll wait.\nFairytale of New York\u2014the top of the list\u2014starts out by hinting at some pretty standard holiday fare; dreams and cheer and whatnot. Typical seasonal stuff, so long as you ignore that the story seems to be recounted as a drunken flashback in a jail cell. You can probably make a few guesses at the underlying spirit of the song based on that framing: following a lucky break, our bright-eyed protagonists move to New York in search of fame and fortune, only to quickly descend into bad decisions, name-calling, and vaguely festive chaos.\nThis song speaks to me on a couple of levels, not the least of which is as a retelling of my day-to-day interactions with JavaScript. Each day\u2019s melody might vary a little bit, granted, but the lyrics almost always follow a pretty clear arc toward \u201cPARENTAL ADVISORY: EXPLICIT CONTENT.\u201d You might have heard a similar tune yourself; it goes a little somethin\u2019 like setTimeout(function() { console.log( \"this should be happening last\" ); }, 1000); . Callbacks are calling callbacks calling callbacks and something is happening somewhere, as the JavaScript interpreter plods through our code start-to-finish, line-by-line, step-by-step. If we need to take actions based on the results of something that could take its sweet time resolving, well, we\u2019d better fiddle with the order of things to make sure those actions don\u2019t happen too soon.\n\u201cBut I can see a better time,\u201d as the song says, \u201cwhen all our dreams come true.\u201d So, with that Pogues brand of holiday spirit squarely in mind\u2014by which I mean that your humble narrator is almost certainly drunk, and may be incarcerated at the time of publication\u2014gather \u2019round for a story of hope, of hardships, of semi-asynchronous JavaScript programming, and ultimately: of Promise unfulfilled.\nThe Main Thread\nJavaScript is single-minded, in a manner of speaking. Anything we tell the JavaScript runtime to do goes into a single-file queue; you\u2019ll see it referred to as the \u201cmain thread,\u201d or \u201cUI thread.\u201d That thread can be shared by a number of critical browser processes, like rendering and re-rendering parts of the page, and user interactions ranging from the simple\u2014say, highlighting text\u2014to the more complex\u2014interacting with form elements.\nIf that sounds a little scary to you, well, that\u2019s because it is. The more complex our scripts, the more we\u2019re cramming into that single-file main thread, to be processed along with\u2014say\u2014some of our CSS animations. Too much JavaScript clogging up the main thread means a lot of user-facing performance jankiness. Getting away from that single thread is a big part of all the excitement around Web Workers, which allow us to offload entire scripts into their own dedicated background threads\u2014though not without limitations of their own. Outside of Web Workers, that everything-thread is the only game in town: scripts executed one thing at a time, functions calling functions calling functions, taking numbers and crowding up the same deli counter as a user\u2019s interactions\u2014which, in this already strained metaphor, would be ham, I guess?\nAsynchronous JavaScript\nNow, those queued actions may include asynchronous things. For example: AJAX callbacks, setTimeout/setInterval, and addEventListener won\u2019t block the main thread while we\u2019re waiting for a request to come back, a timer to tick away, or an event to trigger. Once those things do kick in, though, the actions they\u2019re meant to perform will get shuffled right back into that single-thread queue.\nThere are a couple of places you might have written asynchronously-fired JavaScript, even if you\u2019re not super familiar with the overarching concept: XMLHttpRequest\u2014\u201cAJAX,\u201d if ya nasty\u2014or just kicking off a function once a user triggers a click or mouseenter event. Event-driven development is writ a little larger, with the overall flow of the script dictated by events, both internal and external. Writing event-driven JavaScript applications is a step in the right direction for sure\u2014it won\u2019t cure what ails the main thread, but it does work with the medium in a reasonable way. Event-driven development allows us to manage our use of the main thread in a way that makes sense. If any of this rings a bell for you, the motivation for Promises should feel familiar.\nFor example, a custom init event might kick things off, and fire a create event that applies our classes and restructures our markup which, on completion, fires a bindEvents event to handle all the event listeners for user interaction. There might not sound like much difference between that and one big function that kicks off, manipulates the DOM, and binds our events line-by-line\u2014but in a script of sufficient size and complexity we\u2019re not only provided with a decoupled flow through the script, but obvious touchpoints for future updates and a predictable structure for ongoing maintenance. \nThis pattern falls apart a little where we were still creating, binding, and listening for events in the same top-to-bottom, one-item-at-a-time way\u2014we had to set a listener on a given object before the event fires, or nothing would happen:\n// Create the event:\nvar event = document.createEvent( \"Event\" );\n\n// Name the event:\nevent.initEvent( \"doTheStuff\", true, true );\n\n// Listen for the custom `doTheStuff` event on `window`:\nwindow.addEventListener( \"doTheStuff\", initializeEverything );\n\n// Fire the custom event\nwindow.dispatchEvent( event );\nThis example is a little contrived, and this stuff is a lot more manageable for sure with the addition of a framework, but that\u2019s the basic gist: create and name the event, add a listener for the event, and\u2014after setting our listener\u2014dispatch the event.\nEvents and callbacks aren\u2019t the only game in town for weaving our way in and out of the main thread, though\u2014at least, not anymore. \nPromises\nA Promise is, at the risk of sounding sentimental, pure potential\u2014an empty container into which a value eventually results. A Promise can exist in several states: \u201cpending,\u201d while the computation they contain is being performed or \u201cresolved\u201d once that computation is complete. Once resolved, a Promise is \u201cfulfilled\u201d if it gave us back something we expect, or \u201crejected\u201d if it didn\u2019t.\nThe Promise constructor accepts a callback with two arguments: resolve and reject. We perform an action\u2014asynchronous or otherwise\u2014within that callback. If everything in there has gone according to plan, we call resolve. If something has gone awry, we call reject\u2014with an error, conventionally. To illustrate, let\u2019s tack something together with a pretty decent chance of doing what we don\u2019t want: a promise meant only to give us the number 1, but has a chance of giving us back a 2. No reasonable person would ever do this, of course, but I wouldn\u2019t necessarily put it past me.\nvar promisedOne = new Promise( function( resolve, reject ) {\n var coinToss = Math.floor( Math.random() * 2 ) + 1;\n\n if( coinToss === 1 ) {\n resolve( coinToss );\n } else {\n reject( new Error( \"That ain\u2019t a one.\" ) );\n }\n});\nThere\u2019s nothing too surprising in there, after you boil it all down. It\u2019s a little return-y, with the exception that we\u2019re flagging results as \u201cas expected\u201d or \u201csomething went wrong.\u201d\nTapping into that Promise uses another new keyword: then\u2014and as someone who attempts to make sense of JavaScript by breaking it down to plain ol\u2019 human-language, I\u2019m a big fan of this syntax. then is tacked onto our Promise identifier, and does just what it says on the tin: once the Promise is resolved, then do one of two things, both supplied as callbacks: the first in the case of a fulfilled promise, and the second in the case of a rejected one. Those two callbacks will have, as arguments, the results we specified with resolve orreject, respectively. It sounds like a lot in prose, but in code it\u2019s a pretty simple pattern:\npromisedOne.then( function( result ) {\n console.log( result );\n}, function( error ) {\n console.error( error );\n});\nIf you\u2019ve spent any time working with AJAX\u2014jQuery-wise, in particular\u2014you\u2019ve seen something like this pattern before: a success callback and an error callback. The state of a promise, once fulfilled or rejected, cannot be changed\u2014any reference we make to promisedOne will have a single, fixed result.\nIt may not look like too much the way I\u2019m using it here, but it\u2019s powerful stuff\u2014a pattern for asynchronously resolving anything. I\u2019ve recently used Promises alongside a script that emulates Font Load Events, to apply webfonts asynchronously and avoid a potential performance hit. Font Face Observer allows us to, as the name implies, determine when the files referenced by our @font-face rules have finished loading. \nvar fontObserver = new FontFaceObserver( \"Fancy Font\" );\n\nfontObserver.check().then(function() {\n document.documentElement.className += \" fonts-loaded\";\n}, function( error ) {\n console.error( error );\n});\nfontObserver.check() gives us back a Promise, allowing us to chain on a then containing our callbacks for success and failure. We use the fulfilled callback to bolt a class onto the page once the font file has been fully transferred. We don\u2019t bother including an argument in the first function, since we don\u2019t care about the result itself so much as we care that the promise resolved without error\u2014we\u2019re not doing anything with the resolved value, just adding a class to the page. We do include the error argument, since we\u2019ll want to know what happened should something go wrong.\nNow, this isn\u2019t the tidiest syntax around\u2014at least to my eyes\u2014with those two functions just kinda floating in a then. Luckily there\u2019s an similar alternative syntax; one that I find a bit easier to parse at-a-glance:\nfontObserver.check()\n .then(function() {\n document.documentElement.className += \" fonts-loaded\";\n })\n .catch(function( error ) {\n console.log( error );\n });\nThe first callback inside then provides us with our success state, while the catch provides us with a single, explicit \u201csomething went wrong\u201d callback. The two syntaxes aren\u2019t completely identical in all situations, but for a simple case like this, I find it a little neater.\nThe Common Thread\nI guess I still owe you an explanation, huh. Not about the JavaScript-whatever; I think I\u2019ve explained that plenty. No, I mean Fairytale of New York, and why it\u2019s perched up there at the top of the four (4) song heap.\nFairytale is a sad song, ostensibly. If you follow the main thread\u2014start to finish, line-by-line, step by step\u2014 Fairytale is a sad song. And I can see you out there, visions of Die Hard dancing in your heads: \u201cbut is it a Christmas song?\u201d\nWell, for my money, nothing says \u201cholidays\u201d quite like unreliable narration.\nShane MacGowan, the song\u2019s author, has placed the first verse about \u201cChristmas Eve in the drunk tank\u201d as happening right after the \u201clucky one, came in eighteen-to-one\u201d\u2014not at the chronological end of the story. That means the song might not be mostly drunken flashback, but all of it a single, overarching flashback including a Christmas Eve in protective custody. It could be that the man and woman are, together, recounting times long past\u2014good times and bad times\u2014maybe not even in chronological order. Hell, the \u201cNYPD Choir\u201d mentioned in the chorus? There\u2019s no such thing.\nWe\u2019re not big Christmas folks, my family and I. But just the same, every year, the handful of us get together, and every year\u2014like clockwork\u2014there\u2019s a lull in conversation, there\u2019s a sharp exhale, and Ma says \u201cwe all made it.\u201d Not to a house, not to a dinner, but through another year, to another Christmas. At this point, without fail, someone starts telling a story\u2014and one begets another, and so on. Sometimes the stories are happy, sometimes they\u2019re sad, more often than not they\u2019re both. Some are about things we were lucky to walk away from, some are about a time when another one of us didn\u2019t.\nStart-to-finish, line-by-line, step-by-step, the main thread through the year doesn\u2019t change, and maybe there isn\u2019t a whole lot we can do to change it. But by carefully weaving our way in and out of that thread\u2014stories all out of sync and resolving one way or the other, with the results determined by questionably reliable narrators\u2014we can change the way we interact with it and, little by little, we can start making sense of it.", "year": "2016", "author": "Mat Marquis", "author_slug": "matmarquis", "published": "2016-12-19T00:00:00+00:00", "url": "https://24ways.org/2016/fairytale-of-new-promise/", "topic": "code"} {"rowid": 294, "title": "New Tricks for an Old Dog", "contents": "Much of my year has been spent helping new team members find their way around the expansive and complex codebase that is the TweetDeck front-end, trying to build a happy and productive group of people around a substantial codebase with many layers of legacy.\nI\u2019ve loved doing this. Everything from writing new documentation, drawing diagrams, and holding technical architecture sessions teaches you something you didn\u2019t know or exposes an area of uncertainty that you can go work on.\nIn this article, I hope to share some experiences and techniques that will prove useful in your own situation and that you can impress your friends in some new and exciting ways!\nHow do you do, fellow kids?\nTo start with I\u2019d like to introduce you to our JavaScript framework, Flight. Right now it\u2019s used by twitter.com and TweetDeck although, as a company, Twitter is largely moving to React.\nOver time, as we used Flight for more complex interfaces, we found it wasn\u2019t scaling with us.\nComposing components into trees was fiddly and often only applied for a specific parent-child pairing. It seems like an obvious feature with hindsight, but it didn\u2019t come built-in to Flight, and it made reusing components a real challenge.\nThere was no standard way to manage the state of a component; they all did it slightly differently, and the technique often varied by who was writing the code. This cost us in maintainability as you just couldn\u2019t predict how a component would be built until you opened it.\nMaking matters worse, Flight relied on events to move data around the application. Unfortunately, events aren\u2019t good for giving structure to complex logic. They jump around in a way that\u2019s hard to understand and debug, and force you to search your code for a specific string \u2014 the event name\u201a to figure out what\u2019s going on.\nTo find fixes for these problems, we looked around at other frameworks. We like React for it\u2019s simple, predictable state management and reactive re-render flow, and Elm for bringing strict functional programming to everyone.\nBut when you have lots of existing code, rewriting or switching framework is a painful and expensive option. You have to understand how it will interact with your existing code, how you\u2019ll test it alongside existing code, and how it will affect the size and performance of the application. This all takes time and effort!\nInstead of planning a rewrite, we looked for the ideas hidden within other frameworks that we could reapply in our own situation or bring to the tools we already were using.\nBoiled down, what we liked seemed quite simple:\n\nComponent nesting & composition\nEasy, predictable state management\nNormal functions for data manipulation\n\nMaking these ideas applicable to Flight took some time, but we\u2019re in a much better place now. Through persistent trial-and-error, we have well documented, testable and standard techniques for creating complex component hierarchies, updating and reacting to state changes, and passing data around the app.\nWhile the specifics of our situation and Flight aren\u2019t really important, this experience taught me something: \n\nDistill good tech into great ideas. You can apply great ideas anywhere.\n\nYou don\u2019t have to use cool kids\u2019 latest framework, hottest build tool or fashionable language to benefit from them. If you can identify a nugget of gold at the heart of it all, why not use it to improve what you have already?\nTimes, they are a changin\u2019\nApart from stealing ideas from the new and shiny, how can we keep make the most of improved tooling and techniques? Times change and so should the way we write code.\nGoing back in time a bit, TweetDeck used some slightly outmoded tools for building and bundling. Without a transpiler like Babel we were missing out new language features, and without a more advanced build tools like Webpack, every module\u2019s source was encased in AMD boilerplate.\nIn fact, we found ourselves with a mix of both AMD syntaxes:\ndefine([\"lodash\"], function (_) {\n // . . .\n});\n\ndefine(function (require) {\n var _ = require(\"lodash\");\n // . . .\n});\nThis just wouldn\u2019t do. And besides, what we really wanted was CommonJS, or even ES2015 module syntax:\nimport _ from \"lodash\";\nThese days we\u2019re using Babel, Webpack, ES2015 modules and many new language features that make development just\u2026 better. But how did we get there?\nTo explain, I want to introduce you to codemods and jscodeshift.\nA codemod is a large-scale refactor of a whole codebase, often mechanical or repetitive. Think of renaming a module or changing an API like URL(\"...\") to new URL(\"...\").\njscodeshift is a toolkit for running automated codemods, where you express a code transformation using code. The automated codemod operates on each file\u2019s syntax tree \u2013 a data-structure representation of the code \u2014 finding and modifying in place as it goes.\nHere\u2019s an example that renames all instances of the variable foo to bar:\nmodule.exports = function (fileInfo, api) {\n return api\n .jscodeshift(fileInfo.source)\n .findVariableDeclarators('foo')\n .renameTo('bar')\n .toSource();\n};\nIt\u2019s a seriously powerful tool, and we\u2019ve used it to write a series of codemods that:\n\nrename modules,\nunify our use of AMD to a single syntax,\ntransition from one testing framework to another, and\nswitch from AMD to CommonJS.\n\nThese changes can be pretty huge and far-reaching. Here\u2019s an example commit from when we switched to CommonJS:\ncommit 8f75de8fd4c702115c7bf58febba1afa96ae52fc\nDate: Tue Jul 12 2016\n\n Run AMD -> CommonJS codemod\n\n 418 files changed, 47550 insertions(+), 48468 deletions(-)\n\nYep, that\u2019s just under 50k lines changed, tested, merged and deployed without any trouble. AMD be gone!\n\nFrom this step-by-step approach, using codemods to incrementally tweak and improve, we extracted a little codemod recipe for making significant, multi-stage changes:\n\nFind all the existing patterns\nChoose the two most similar\nUnify with a codemod\nRepeat.\n\nFor example:\n\nFor module loading, we had 2 competing AMD patterns plus some use of CommonJS\nThe two AMD syntaxes were the most similar\nWe used a codemod to move to unify the AMD patterns\nLater we returned to AMD to convert it to CommonJS\n\nIt\u2019s worked for us, and if you\u2019d like to know more about codemods then check out Evolving Complex Systems Incrementally by Facebook engineer, Christoph Pojer.\nWelcome aboard!\nAs TweetDeck has gotten older and larger, the amount of things a new engineer has to learn about has exploded. The myriad of microservices that manage our data and their layers of authentication, security and business logic around them make for an overwhelming amount of information to hand to a newbie.\nInspired by Amy\u2019s amazing Guide to the Care and Feeding of Junior Devs, we realised it was important to take time to design our onboarding that each of our new hires go through to make the most of their first few weeks.\nJoining a new company, team, or both, is stressful and uncomfortable. Everything you can do to help a new hire will be valuable to them. So please, take time to design your onboarding!\nAnd as you build up an onboarding process, you\u2019ll create things that are useful for more than just new hires; it\u2019ll force you to write documentation, for example, in a way that\u2019s understandable for people who are unfamiliar with your team, product and codebase. This can lead to more outside contributions: potential contributors feel more comfortable getting set up on your product without asking for help.\nThis is something that\u2019s taken for granted in open source, but somehow I think we forget about it in big companies.\nAfter all, better documentation is just a good thing. You will forget things from time to time, and you\u2019d be surprised how often the \u201cbeginner\u201d docs help!\nFor TweetDeck, we put together system and architecture diagrams, and one-pager explanations of important concepts:\n\nWhat are our dependencies?\nWhere are the potential points of failure?\nWhere does authentication live? Storage? Caching?\nWho owns \u201cX\u201d?\n\n\nOf course, learning continues long after onboarding. The landscape is constantly shifting; old services are deprecated, new APIs appear and what once true can suddenly be very wrong. Keeping up with this is a serious challenge, and more than any one person can track.\nTo address this, we\u2019ve thought hard about our knowledge sharing practices across the whole team. For example, we completely changed the way we do code review.\nIn my opinion, code review is the single most effective practice you can introduce to share knowledge around, and build the quality and consistency of your team\u2019s work. But, if you\u2019re not doing it, here\u2019s my suggestion for getting started:\n\nEvery pull request gets a +1 from someone else.\n\nThat\u2019s all \u2014 it\u2019s very light-weight and easy. Just ask someone to have a quick look over your code before it goes into master.\nAt Twitter, every commit gets a code review. We do a lot of reviewing, so small efficiency and effectiveness improvements make a big difference. Over time we learned some things:\n\nDon\u2019t review for more than hour 1\nKeep reviews smaller than ~400 lines 2\nCode review your own code first 2\n\nAfter an hour, and above roughly 400 lines, your ability to detect issues in a code review starts to decrease. So review little and often. The gaps around lunch, standup and before you head home are ideal. And remember, if someone\u2019s put code up for a review, that review is blocking them doing other work. It\u2019s your job to unblock them.\nOn TweetDeck, we actually try to keep reviews under 250 lines. It doesn\u2019t sound like much, but this constraint applies pressure to make smaller, incremental changes. This makes breakages easier to detect and roll back, and leads to a very natural feature development process that encourages learning and iteration.\nBut the most important thing I\u2019ve learned personally is that reviewing my own code is the best way to spot issues. I try to approach my own reviews the way I approach my team\u2019s: with fresh, critical eyes, after a break, using a dedicated code review tool.\nIt\u2019s amazing what you can spot when you put a new in a new interface around code you\u2019ve been staring at for hours!\nAnd yes, this list features science. The data backs up these conclusions, and if you\u2019d like to learn more about scientific approaches to software engineering then I recommend you buy Making Software: What Really Works, and Why We Believe It. It\u2019s ace.\nFor more dedicated information sharing, we\u2019ve introduced regular seminars for everyone who works on a specific area or technology. It works like this: a team-member shares or teaches something to everyone else, and next time it\u2019s someone else\u2019s turn. Giving everyone a chance to speak, and encouraging a wide range of topics, is starting to produce great results.\nIf you\u2019d like to run a seminar, one thing you could try to get started: run a point at the thing you least understand in our architecture session \u2014 thanks to James for this idea. And guess what\u2026 your onboarding architecture diagrams will help (and benefit from) this!\nMore, please!\nThere\u2019s a few ideas here to get you started, but there are even more in a talk I gave this year called Frontend Archaeology, including a look at optimising for confidence with front-end operations.\nAnd finally, thanks to Amy for proof reading this and to Passy for feedback on the original talk.\n\n\n\n\nDunsmore et al. 2000. Object-Oriented Inspection in the Face of Delocalisation. Beverly, MA: SmartBear Software.\u00a0\u21a9\n\n\nCohen, Jason. 2006. Best Kept Secrets of Peer Code Review. Proceedings of the 22nd ICSE 2000: 467-476.\u00a0\u21a9 \u21a9", "year": "2016", "author": "Tom Ashworth", "author_slug": "tomashworth", "published": "2016-12-18T00:00:00+00:00", "url": "https://24ways.org/2016/new-tricks-for-an-old-dog/", "topic": "code"} {"rowid": 289, "title": "Front-End Developers Are Information Architects Too", "contents": "The theme of this year\u2019s World IA Day was \u201cInformation Everywhere, Architects Everywhere\u201d. This article isn\u2019t about what you may consider an information architect to be: someone in the user-experience field, who maybe studied library science, and who talks about taxonomies. This is about a realisation I had a couple of years ago when I started to run an increasing amount of usability-testing sessions with people who have disabilities: that the structure, labelling, and connections that can be made in front-end code is information architecture. People\u2019s ability to be successful online is unequivocally connected to the quality of the code that is written.\nPlaces made of information\nIn information architecture we talk about creating places made of information. These places are made of ones and zeros, but we talk about them as physical structures. We talk about going onto a social media platform, posting in blogs, getting locked out of an environment, and building applications. In 2002, Andrew Hinton stated:\n\nPeople live and work in these structures, just as they live and work in their homes, offices, factories and malls. These places are not virtual: they are as real as our own minds.\n25 Theses\n\nWe\u2019re creating structures which people rely on for significant parts of their lives, so it\u2019s critical that we carry out our work responsibly. This means we must use our construction materials correctly. Luckily, our most important material, HTML, has a well-documented specification which tells us how to build robust and accessible places. What is most important, I believe, is to understand the semantics of HTML.\nSemantics\nThe word \u201csemantic\u201d has its origin in Greek words meaning \u201csignificant\u201d, \u201csignify\u201d, and \u201csign\u201d. In the physical world, a structure can have semantic qualities that tell us something about it. For example, the stunning Westminster Abbey inspires awe and signifies much about the intent and purpose of the structure. The building\u2019s size; the quality of the stone work; the massive, detailed stained glass: these are all signs that this is a building meant for something the creators deemed important. Alternatively consider a set of large, clean, well-positioned, well-lit doors on the ground floor of an office block: they don\u2019t need an \u201centrance\u201d sign to communicate their use and to stop people trying to use a nearby fire exit to get into the building. The design of the doors signify their usage. Sometimes a more literal and less awe-inspiring approach to communicating a building\u2019s purpose happens, but the affect is similar: the building is signifying something about its purpose.\nHTML has over 115 elements, many of which have semantics to signify structure and affordance to people, browsers, and assistive technology. The HTML 5.1 specification mentions semantics, stating:\n\nElements, attributes, and attribute values in HTML are defined \u2026 to have certain meanings (semantics). For example, the
    element represents an ordered list, and the lang attribute represents the language of the content.\nHTML 5.1 Semantics, structure, and APIs of HTML documents\n\nHTML\u2019s baked-in semantics means that developers can architect their code to signify structure, create relationships between elements, and label content so people can understand what they\u2019re interacting with. Structuring and labelling information to make it available, usable, and understandable to people is what an information architect does. It\u2019s also what a front-end developer does, whether they realise it or not.\nA brief introduction to information architecture\nWe\u2019re going to start by looking at what an information architect is. There are many definitions, and I\u2019m going to quote Richard Saul Wurman, who is widely regarded as the father of information architecture. In 1976 he said an information architect is:\n\nthe individual who organizes the patterns inherent in data, making the complex clear; a person who creates the structure or map of information which allows others to find their personal paths to knowledge; the emerging 21st century professional occupation addressing the needs of the age focused upon clarity, human understanding, and the science of the organization of information.\nOf Patterns And Structures\n\nTo me, this clearly defines any developer who creates code that a browser, or other user agent (for example, a screen reader), uses to create a structured, navigable place for people.\nJust as there are many definitions of what an information architect is, there are for information architecture itself. I\u2019m going to use the definition from the fourth edition of Information Architecture For The World Wide Web, in which the authors define it as:\nThe structural design of shared information environments.\nThe synthesis of organization, labeling, search, and navigation systems within digital, physical, and cross-channel ecosystems.\nThe art and science of shaping information products and experiences to support usability, findability, and understanding.\nInformation Architecture For The World Wide Web, 4th Edition\nTo me, this describes front-end development. Done properly, there is an art to creating robust, accessible, usable, and findable spaces that delight all our users. For example, at 2015\u2019s State Of The Browser conference, Edd Sowden talked about the accessibility of s. He discovered that by simply not using the semantically-correct
    element to mark up headings, in some situations browsers will decide that a
    is being used for layout and essentially make it invisible to assistive technology. Another example of how coding practices can affect the usability and findability of content is shown by L\u00e9onie Watson in her How ARIA landmark roles help screen reader users video. By using ARIA landmark roles, people who use screen readers are quickly able to identify and jump to common parts of a web page.\nOur definitions of information architects and information architecture mention patterns, rules, organisation, labelling, structure, and relationships. There are numerous different models for how these elements get boiled down to their fundamentals. In his Understanding Context book, Andrew Hinton calls them Labels, Relationships, and Rules; Jorge Arango calls them Links, Nodes, And Order; and Dan Klyn uses Ontology, Taxonomy, and Choreography, which is the one we\u2019re going to use. Dan defines these terms as:\nOntology\nThe definition and articulation of the rules and patterns that govern the meaning of what we intend to communicate.\nWhat we mean when we say what we say.\nTaxonomy\nThe arrangements of the parts. Developing systems and structures for what everything\u2019s called, where everything\u2019s sorted, and the relationships between labels and categories\nChoreography\nRules for interaction among the parts. The structures it creates foster specific types of movement and interaction; anticipating the way users and information want to flow and making affordance for change over time.\n\nWe now have definitions of an information architect, information architecture, and a model of the elements of information architecture. But is writing HTML really creating information or is it just wrangling data and metadata? When does data turn into information? In his book Managing For The Future Peter Drucker states:\n\n\u2026 data is not information. Information is data endowed with relevance and purpose.\nManaging For The Future\n\nIf we use the correct semantic element to mark up content then we\u2019re developing with purpose and creating relevance. For example, if we follow the advice of the HTML 5.1 specification and mark up headings using heading rank instead of the outline algorithm, we\u2019re creating a structure where the depth of one heading is relevant to the previous one. Architected correctly, an

    element should be relevant to its parent, which should be the

    . By following the HTML specification we can create a structured, searchable, labeled document that will hopefully be relevant to what our users need to be successful. If you\u2019ve never used a screen reader, you might be wondering how the headings on a page are searchable. Screen readers give users the ability to interact with headings in a couple of ways:\n\nby creating a list of headings so users can quickly scan the page for information\nby using a keyboard command to cycle through one heading at a time\n\nIf we had a document for Christmas Day TV we might structure it something like this:\n

    Christmas Day TV schedule

    \n

    BBC1

    \n

    Morning

    \n

    Evening

    \n

    BBC2

    \n

    Morning

    \n

    Evening

    \n

    ITV

    \n

    Morning

    \n

    Evening

    \n

    Channel 4

    \n

    Morning

    \n

    Evening

    \nIf I use VoiceOver to generate a list of headings, I get this:\n\nOnce I have that list I can use keyboard commands to filter the list based on the heading level. For example, I can press 2 to hear just the

    s:\n\nIf we hadn\u2019t used headings, of if we\u2019d nested them incorrectly, our users would be frustrated.\nPutting this together\nLet\u2019s put this together with an example of a button that, when pressed, toggles the appearance of a panel of links. There are numerous ways we could create a button on a web page, but the best way is to just use a \n\n
    \n \n
    \nThere\u2019s quite a bit going on here. We\u2019re using the:\n\naria-controls attribute to architect a connection between the \nAn 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:\nOpen video\n A screen reader announcing a button with a title.\nHowever, 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\u2019t 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:\nThe mobile GitHub view with and without external fonts.\nEven 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\u2019t load.\n\nProviding 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.\n\nThis also reads just fine in screen readers:\nOpen video\n A screen reader announcing the revised button.\nClever usability enhancements don\u2019t stop at a technical implementation level. Take the BBC iPlayer pages as an example: when a user navigates the \u201ccaptioned videos\u201d or \u201caudio description\u201d 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\u2019t 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.\nMore information\nW3C 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 \u201cHow People with Disabilities Use the Web\u201d, there are \u201cTips for Getting Started\u201d 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.\nConclusion\nYou 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\u2019t notice when those fundamental aspects of good website design and development are done right. But they\u2019ll always know when they are implemented poorly.\nIf you take all this into consideration, you can create accessibility solutions based on the available data and bring accessibility to people who didn\u2019t know they\u2019d need it:\nOpen video\n \nIn this video from the latest Apple keynote, the Apple TV is operated by voice input through a remote. When the user asks \u201cWhat did she say?\u201d 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.", "year": "2015", "author": "Eric Eggert", "author_slug": "ericeggert", "published": "2015-12-17T00:00:00+00:00", "url": "https://24ways.org/2015/the-accessibility-mindset/", "topic": "code"} {"rowid": 58, "title": "Beyond the Style Guide", "contents": "Much like baking a Christmas cake, designing for the web involves creating an experience in layers. Starting with a solid base that provides the core experience (the fruit cake), we can add further layers, each adding refinement (the marzipan) and delight (the icing).\nDon\u2019t worry, this isn\u2019t a misplaced cake recipe, but an evaluation of modular design and the role style guides can play in acknowledging these different concerns, be they presentational or programmatic.\nThe auteur\u2019s style guide\nAlthough trained as a graphic designer, it was only when I encountered the immediacy of the web that I felt truly empowered as a designer. Given a desire to control every aspect of the resulting experience, I slowly adopted the role of an auteur, exploring every part of the web stack: front-end to back-end, and everything in between. A few years ago, I dreaded using the command line. Today, the terminal is a permanent feature in my Dock.\nIn straddling the realms of graphic design and programming, it\u2019s the point at which they meet that I find most fascinating, with each dicipline valuing the creation of effective systems, be they for communication or code efficiency. Front-end style guides live at this intersection, demonstrating both the modularity of code and the application of visual design.\nPainting by numbers\nIn our rush to build modular systems, design frameworks have grown in popularity. While enabling quick assembly, these come at the cost of originality and creative expression \u2013 perhaps one reason why we\u2019re seeing the homogenisation of web design.\nIn editorial design, layouts should accentuate content and present it in an engaging manner. Yet on the web we see a practice that seeks templated predictability. In \u2018Design Machines\u2019 Travis Gertz argued that (emphasis added):\n\nDesign systems still feel like a novelty in screen-based design. We nerd out over grid systems and modular scales and obsess over style guides and pattern libraries. We\u2019re pretty good at using them to build repeatable components and site-wide standards, but that\u2019s sort of where it ends. [\u2026] But to stop there is to ignore the true purpose and potential of a design system.\n\nUnless we consider how interface patterns fully embrace the design systems they should be built upon, style guides may exacerbate this paint-by-numbers approach, encouraging conformance and suppressing creativity.\nAnatomy of a button\nLet\u2019s take a look at that most canonical of components, the button, and consider what we might wish to document and demonstrate in a style guide.\nThe different layers of our button component.\nContent\nThe most variable aspect of any component. Content guidelines will exert the most influence here, dictating things like tone of voice (whether we should we use stiff, formal language like \u2018Submit form\u2019, or adopt a more friendly tone, perhaps \u2018Send us your message\u2019) and appropriate language. For an internationalised interface, this may also impact word length and text direction or orientation.\nStructure\nHTML provides a limited vocabulary which we can use to structure content and add meaning. For interactive elements, the choice of element can also affect its behaviour, such as whether a button submits form data or links to another page:\n\nButton text\nNote: One of the reasons I prefer to use

    \n \n \n \n \n
    \n .col-md-8\n \n \n \n \n \n
    \n .col-md-6\n \n .col-md-6\n
    \n
    \n .col-md-4\n
    \nGrid and flexbox layouts do not need to be described in markup. The layout description happens entirely in the CSS, meaning that elements can be moved around from within the presentation layer.\nFlexbox gives us the ability to reverse the flow of elements, but also to set the order of elements with the order property. This is demonstrated here, where Widget the cat is in position 1 in the source, but I have used the order property to display him after the things that are currently unimpressive to him.\nSee the Pen Flexbox: order by rachelandrew (@rachelandrew) on CodePen.\n\nGrid layout takes this a step further. Where flexbox lets us set the order of items in a single dimension, grid layout gives us the ability to position things in two dimensions: both rows and columns. Defined in the CSS, this positioning can be changed at any breakpoint without needing additional markup. Compare the source order with the display order in this example (requires a CSS grid-supporting browser):\nSee the Pen Grid positioning in two dimensions by rachelandrew (@rachelandrew) on CodePen.\n\nLaying out our items in two dimensions using grid layout.\nAs these demos show, a straightforward way to decide if you should use grid layout or flexbox is whether you want to position items in one dimension or two. If two, you want grid layout.\nA note on accessibility and reordering\nThe issues arising from this powerful ability to change the way items are ordered visually from how they appear in the source have been the subject of much discussion. The current flexbox editor\u2019s draft states\n\n\u201cAuthors must use order only for visual, not logical, reordering of content. Style sheets that use order to perform logical reordering are non-conforming.\u201d\n\u2014CSS Flexible Box Layout Module Level 1, Editor\u2019s Draft (3 December 2015)\n\nThis is to ensure that non-visual user agents (a screen reader, for example) can rely on the document source order as being correct. Take care when reordering that you do so from the basis of a sound document that makes sense in terms of source order. Avoid using visual order to convey meaning.\nAutomatic content placement with rules\nHaving control over the order of items, or placing items on a predefined grid, is nice. However, we can often do that already with one method or another and we have frameworks and tools to help us. Tools such as Susy mean we can even get away from stuffing our markup full of grid classes. However, our new layout methods give us some interesting new possibilities.\nSomething that is useful to be able to do when dealing with content coming out of a CMS or being pulled from some other source, is to define a bunch of rules and then say, \u201cDisplay this content, using these rules.\u201d\nAs an example of this, I will leave you with a Christmas poem displayed in a document alongside Widget the cat and some of the decorations that are bringing him no Christmas cheer whatsoever.\nThe poem is displayed first in the source as a set of paragraphs. I\u2019ve added a class identifying each of the four paragraphs but they are displayed in the source as one text. Below that are all my images, some landscape and some portrait; I\u2019ve added a class of landscape to the landscape ones.\nThe mobile-first grid is a single column and I use line-based placement to explicitly position my poem paragraphs. The grid layout auto-placement rules then take over and place the images into the empty cells left in the grid.\nAt wider screen widths, I declare a four-track grid, and position my poem around the grid, keeping it in a readable order.\nI also add rules to my landscape class, stating that these items should span two tracks. Once again the grid layout auto-placement rules position the rest of my images without my needing to position them. You will see that grid layout takes items out of source order to fill gaps in the grid. It does this because I have set the property grid-auto-flow to dense. The default is sparse meaning that grid will not attempt this backfilling behaviour.\nTake a look and play around with the full demo (requires a CSS grid layout-supporting browser):\nSee the Pen Grid auto-flow with rules by rachelandrew (@rachelandrew) on CodePen.\n\nThe final automatic placement example.\nMy wish for 2016\nI really hope that in 2016, we will see CSS grid layout finally emerge from behind browser flags, so that we can start to use these features in production \u2014 that we can start to move away from using the wrong tools for the job.\nHowever, I also hope that we\u2019ll see developers fully embracing these tools as the new system that they are. I want to see people exploring the possibilities they give us, rather than trying to get them to behave like the grid systems of 2015. As you discover these new modules, treat them as the new paradigm that they are, get creative with them. And, as you find the edges of possibility with them, take that feedback to the CSS Working Group. Help improve the layout systems that will shape the look of the future web.\nSome further reading\n\nI maintain a site of grid layout examples and resources at Grid by Example.\nThe three CSS specifications I\u2019ve discussed can be found as editor\u2019s drafts: CSS grid, flexbox, box alignment.\nI wrote about the last three years of my interest in CSS grid layout, which gives something of a history of the specification.\nMore examples of box alignment and grid layout.\nMy presentation at Fronteers earlier this year, in which I explain more about these concepts.", "year": "2015", "author": "Rachel Andrew", "author_slug": "rachelandrew", "published": "2015-12-15T00:00:00+00:00", "url": "https://24ways.org/2015/grid-flexbox-box-alignment-our-new-system-for-layout/", "topic": "code"} {"rowid": 67, "title": "What I Learned about Product Design This Year", "contents": "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. \nThe 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.\nI had (and still have) grand ideas for what thoughtful design can do for a product, and the smaller-scale product design work I\u2019ve 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\u2019s 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\u2019d like to share a few of those lessons.\nProduct design is very different from marketing design\nThe 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.\nProduct 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\u2019ve created for our marketing materials, but big gradients, textures, and display fonts made no sense in this new context.\nThat\u2019s because the product isn\u2019t about us, and it isn\u2019t 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 \u201cus\u201d out of the equation took some work after years of creating gorgeous imagery and content for the sales-driven side of businesses.\nI\u2019ve learned it\u2019s very valuable to design both sides of the experience, because marketing and product design flex different muscles. If you\u2019re currently in an environment where the two are separate, consider switching teams in 2016. Designing for product when you\u2019ve mostly done marketing, or vice versa, will deepen your knowledge as a designer overall. You\u2019ll face new unexpected challenges, which is the only way to grow.\nProduct design can not start with what looks good on Dribbble\nI 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\u200a\u2014\u200awhen applied to our actual product\u200a\u2014\u200alooked like a toddler beauty pageant. It added up to a lot of unusable shininess, noise, and silliness.\nI was disappointed; these elements seemed so lovely in isolation, but in context, they felt tacky and overblown. I realized: I\u2019m not here to design the world\u2019s 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\u2019m 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\u200a\u2014\u200ato make life a little better for the good people who keep my company in business.\nThis 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\u2019t 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.\nJust accept that designing a great product \u2013 like many worthwhile pursuits \u2013 is initially laborious and messy\nOnce I realized I couldn\u2019t start by creating the most Dribbble-worthy thing, I knew I\u2019d have to begin with the unglamorous, frustrating, but weirdly wonderful work of mapping out how the product\u2019s content could better be structured. Since we\u2019re 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.\nI started by handing off a few wireframes of the key screens to the developer, and that\u2019s when the questions began rolling in: \u201cIf we move this content into a modal, how will it affect this similar action here?\u201d \u201cWhat happens if they don\u2019t add video tags, but they do add a description?\u201d \u201cWhat if the user has a title that is 500 characters long?\u201d \u201cWhat if they want their video to be private to some users, but accessible to others?\u201d.\nHow annoying (but really, fantastic) that people use our product in so many ways. Turns out, product design isn\u2019t about laying out elements in the most ideal scenario for the user that\u2019s most convenient for you. As product designers, we have to foresee every outcome, and anticipate every potential user need.\nWhich 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\u2019d 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\u2019s incredibly frustrating, because an elegant solution for users with one goal will complicate life for users with another goal. It\u2019s vital to solve as many scenarios as possible, even though this is slow, sometimes mind-bending work.\nAs a side bonus, wireframing and prototyping every potential state in a product is tedious, but your developers will thank you for it. It\u2019s not their job to solve what happens when there\u2019s an empty state, error, or edge case. Showing you\u2019ve accounted for these scenarios will win a developer\u2019s respect; failing to do so will frustrate them.\nWhen you\u2019ve created and tested a system that supports user needs, it will be beautiful\nRemember 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.\nI 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.\n\nA 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\u2019re about to undertake the biggest test of our work; we\u2019re going to launch a small part of the product redesign to our users. If I\u2019ve learned anything, it\u2019s that I will continue to be humbled by the ongoing effort of making the best product I can, which is a wonderful thing.\nNext 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.", "year": "2015", "author": "Meagan Fisher", "author_slug": "meaganfisher", "published": "2015-12-14T00:00:00+00:00", "url": "https://24ways.org/2015/what-i-learned-about-product-design-this-year/", "topic": "design"} {"rowid": 72, "title": "Designing with Contrast", "contents": "When an appetite for aesthetics over usability becomes the bellwether of user interface design, it\u2019s time to reconsider who we\u2019re designing for.\nOver the last few years, we have questioned the signifiers that gave obvious meaning to the function of interface elements. Strong textures, deep shadows, gradients \u2014 imitations of physical objects \u2014 were discarded. And many, rightfully so. Our audiences are now more comfortable with an experience that feels native to the technology, so we should respond in kind.\nYet not all of the changes have benefitted users. Our efforts to simplify brought with them a trend of ultra-minimalism where aesthetics have taken priority over legibility, accessibility and discoverability. The trend shows no sign of losing popularity \u2014 and it is harming our experience of digital content.\n\nA thin veneer\nWe are in a race to create the most subdued, understated interface. Visual contrast is out. In its place: the thinnest weights of a typeface and white text on bright color backgrounds. Headlines, text, borders, backgrounds, icons, form controls and inputs: all grey.\nWhile we can look back over the last decade and see minimalist trends emerging on the web, I think we can place a fair share of the responsibility for the recent shift in priorities on Apple. The release of iOS 7 ushered in a radical change to its user interface. It paired mobile interaction design to the simplicity and eloquence of Apple\u2019s marketing and product design. It was a catalyst. We took what we saw, copied and consumed the aesthetics like pick-and-mix.\nNew technology compounds this trend. Computer monitors and mobile devices are available with screens of unprecedented resolutions. Ultra-light type and subtle hues, difficult to view on older screens, are more legible on these devices. It would be disingenuous to say that designers have always worked on machines representative of their audience\u2019s circumstances, but the gap has never been as large as it is now. We are running the risk of designing VIP lounges where the cost of entry is a Mac with a Retina display.\nMinimalist expectations\nLike progressive enhancement in an age of JavaScript, many good and sensible accessibility practices are being overlooked or ignored. We\u2019re driving unilateral design decisions that threaten accessibility. We\u2019ve approached every problem with the same solution, grasping on to the integrity of beauty, focusing on expression over users\u2019 needs and content. \nSomeone once suggested to me that a client\u2019s website should include two states. The first state would be the ideal experience, with low color contrast, light font weights and no differentiation between links and text. It would be the default. The second state would be presented in whatever way was necessary to meet accessibility standards. Users would have to opt out of the default state via a toggle if it wasn\u2019t meeting their needs. A sort of first-class, upper deck cabin equivalent of graceful degradation. That this would divide the user base was irrelevant, as the aesthetics of the brand were absolute. \nIt may seem like an unusual anecdote, but it isn\u2019t uncommon to see this thinking in our industry. Again and again, we place the burden of responsibility to participate in a usable experience on others. We view accessibility and good design as mutually exclusive. Taking for granted what users will tolerate is usually the forte of monopolistic services, but increasingly we apply the same arrogance to our new products and services.\n\nImitation without representation\nAll of us are influenced in one way or another by one another\u2019s work. We are consciously and unconsciously affected by the visual and audible activity around us. This is important and unavoidable. We do not produce work in a vacuum. We respond to technology and culture. We channel language and geography. We absorb the sights and sounds of film, television, news. To mimic and copy is part and parcel of creating something an audience of many can comprehend and respond to. Our clients often look first to their competitors\u2019 products to understand their success.\nHowever, problems arise when we focus on style without context; form without function; mimicry as method. Copied and reused without any of the ethos of the original, stripped of deliberate and informed decision-making, the so-called look and feel becomes nothing more than paint on an empty facade.\nThe typographic and color choices so in vogue today with our popular digital products and services have little in common with the brands they are meant to represent.\n\nFor want of good design, the message was lost\nThe question to ask is: does the interface truly reflect the product? Is it an accurate characterization of the brand and organizational values? Does the delivery of the content match the tone of voice?\nThe answer is: probably not. Because every organization, every app or service, is unique. Each with its own personality, its own values and wonderful quirks. Design is communication. We should do everything in our role as professionals to use design to give voice to the message. Our job is to clearly communicate the benefits of a service and unreservedly allow access to information and content. To do otherwise, by obscuring with fashionable styles and elusive information architecture, does a great disservice to the people who chose to engage with and trust our products.\nWe can achieve hierarchy and visual rhythm without resorting to extreme reduction. We can craft a beautiful experience with fine detail and curiosity while meeting fundamental standards of accessibility (and strive to meet many more).\nStandards of excellence\nIt isn\u2019t always comfortable to step back and objectively question our design choices. We get lost in the flow of our work, using patterns and preferences we\u2019ve tried and tested before. That our decisions often seem like second nature is a gift of experience, but sometimes it prevents us from finding our blind spots.\nI was first caught out by my own biases a few years ago, when designing an interface for the Bank of England. After deciding on the colors for the typography and interactive elements, I learned that the site had to meet AAA accessibility standards. My choices quickly fell apart. It was eye-opening. I had to start again with restrictions and use size, weight and placement instead to construct the visual hierarchy.\nEven now, I make mistakes. On a recent project, I used large photographs on an organization\u2019s website to promote their products. Knowing that our team had control over the art direction, I felt confident that we could compose the photographs to work with text overlays. Despite our best effort, the cropped images weren\u2019t always consistent, undermining the text\u2019s legibility. If I had the chance to do it again, I would separate the text and image.\nSo, what practical things can we consider to give our users the experience they deserve?\nPut guidelines in place\n\nThink about your brand values. Write down keywords and use them as a framework when choosing a typeface. Explore colors that convey the organization\u2019s personality and emotional appeal.\nDefine a color palette that is web-ready and meets minimum accessibility standards. Note which colors are suitable for use with text. Only very dark hues of grey are consistently legible so keep them for non-essential text (for example, as placeholders in form inputs).\nFind which background colors you can safely use with white text, and consider integrating contrast checks into your workflow.\nUse roman and medium weights for body copy. Reserve lighter weights of a typeface for very large text. Thin fonts are usually the first to break down because of aliasing differences across platforms and screens.\nCheck that the size, leading and length of your type is always legible and readable. Define lower and upper limits. Small text is best left for captions and words in uppercase.\nAvoid overlaying text on images unless it\u2019s guaranteed to be legible. If it\u2019s necessary to optimize space in the layout, give the text a container. Scrims aren\u2019t always reliable: the text will inevitably overlap a part of the photograph without a contrasting ground.\n\nTest your work\n\nReview legibility and contrast on different devices. It\u2019s just as important as testing the layout of a responsive website. If you have a local device lab, pay it a visit.\nFind a computer monitor near a window when the sun is shining. Step outside the studio and try to read your content on a mobile device with different brightness levels. \nAsk your friends and family what they use at home and at work. It\u2019s one way of making sure your feedback isn\u2019t always coming from a closed loop.\n\nPush your limits\n\nYou define what the user sees. If you\u2019ve inherited brand guidelines, question them. If you don\u2019t agree with the choices, make the case for why they should change.\nExperiment with size, weight and color to find contrast. Objects with low contrast appear similar to one another and undermine the visual hierarchy. Weak relationships between figure and ground diminish visual interest. A balanced level of contrast removes ambiguity and creates focal points. It captures and holds our attention.\nIf you\u2019re lost for inspiration, look to graphic design in print. We have a wealth of history, full of examples that excel in using contrast to establish visual hierarchy.\nEmbrace limitations. Use boundaries as an opportunity to explore possibilities.\n\nMore than just a facade\nDesigning with standards encourages legibility and helps to define a strong visual hierarchy. Design without exclusion (through neither negligence or intent) gets around discussions of demographics, speaks to a larger audience and makes good business sense. Following the latest trends not only weakens usability but also hinders a cohesive and distinctive brand.\nUsers will make means when they need to, by increasing browser font sizes or enabling system features for accessibility. But we can do our part to take as much of that burden off of the user and ask less of those who need it most.\nIn architecture, it isn\u2019t buildings that mimic what is fashionable that stand the test of time. Nor do we admire buildings that tack on separate, poorly constructed extensions to meet a bare minimum of safety regulations. We admire architecture that offers well-considered, remarkable, usable spaces with universal access.\nPerhaps we can take inspiration from these spaces. Let\u2019s give our buildings a bold voice and make sure the doors are open to everyone.", "year": "2015", "author": "Mark Mitchell", "author_slug": "markmitchell", "published": "2015-12-13T00:00:00+00:00", "url": "https://24ways.org/2015/designing-with-contrast/", "topic": "design"} {"rowid": 63, "title": "Be Fluid with Your Design Skills: Build Your Own Sites", "contents": "Just five years ago in 2010, when we were all busy trying to surprise and delight, learning CSS3 and trying to get whole websites onto one page, we had a poster on our studio wall. It was entitled \u2018Designers Vs Developers\u2019, an infographic that showed us the differences between the men(!) who created websites. \nDesigners wore skinny jeans and used Macs and developers wore cargo pants and brought their own keyboards to work. We began to learn that designers and developers were not only doing completely different jobs but were completely different people in every way. This opinion was backed up by hundreds of memes, millions of tweets and pages of articles which used words like void and battle and versus.\nThankfully, things move quickly in this industry; the wide world of web design has moved on in the last five years. There are new devices, technologies, tools \u2013 and even a few women. Designers have been helped along by great apps, software, open source projects, conferences, and a community of people who, to my unending pride, love to share their knowledge and their work.\nSo the world has moved on, and if Miley Cyrus, Ruby Rose and Eliot Sumner are identifying as gender fluid (an identity which refers to a gender which varies over time or is a combination of identities), then I would like to come out as discipline fluid! \nOK, I will probably never identify as a developer, but I will identify as fluid! How can we be anything else in an industry that moves so quickly? That\u2019s how we should think of our skills, our interests and even our job titles. After all, Steve Jobs told us that \u201cDesign is not just what it looks like and feels like. Design is how it works.\u201d Sorry skinny-jean-wearing designers \u2013 this means we\u2019re all designing something together. And it\u2019s not just about knowing the right words to use: you have to know how it feels. How it feels when you make something work, when you fix that bug, when you make it work on IE.\nLike anything in life, things run smoothly when you make the effort to share experiences, empathise and deeply understand the needs of others. How can designers do that if they\u2019ve never built their own site? I\u2019m not talking the big stuff, I\u2019m talking about your portfolio site, your mate\u2019s business website, a website for that great idea you\u2019ve had. I\u2019m talking about doing it yourself to get an unique insight into how it feels.\nWe all know that designers and developers alike love an
      , so here it is.\nTen reasons designers should be fluid with their skills and build their own sites\n1. It\u2019s never been easier\nNow here\u2019s where the definition of \u2018build\u2019 is going to get a bit loose and people are going to get angry, but when I say it\u2019s never been easier I mean because of the existence of apps and software like WordPress, Squarespace, Tumblr, et al. It\u2019s easy to make something and get it out there into the world, and these are all gateway drugs to hard coding!\n2. You\u2019ll understand how it feels\nHow it feels to be so proud that something actually works that you momentarily don\u2019t notice if the kerning is off or the padding is inconsistent. How it feels to see your site appear when you\u2019ve redirected a URL. How it feels when you just can\u2019t work out where that one extra space is in a line of PHP that has killed your whole site.\n3. It makes you a designer\nNot a better designer, it makes you a designer when you are designing how things look and how they work. \n4. You learn about movement\nPhotoshop and Sketch just don\u2019t cut it yet. Until you see your site in a browser or your app on a phone, it\u2019s hard to imagine how it moves. Building your own sites shows you that it\u2019s not just about how the content looks on the screen, but how it moves, interacts and feels.\n5. You make techie friends\nAll the tutorials and forums in the world can\u2019t beat your network of techie friends. Since I started working in web design I have worked with, sat next to, and co-created with some of the greatest developers. Developers who\u2019ve shared their knowledge, encouraged me to build things, patiently explained HTML, CSS, servers, divs, web fonts, iOS development. There has been no void, no versus, very few battles; just people who share an interest and love of making things. \n6. You will own domain names\nWhen something is paid for, online and searchable then it\u2019s real and you\u2019ve got to put the work in. Buying domains has taught me how to stop procrastinating, but also about DNS, FTP, email, and how servers work.\n7. People will ask you to do things\u2028\nLearning about code and development opens a whole new world of design. When you put your own personal websites and projects out there people ask you to do more things. OK, so sometimes those things are \u201cMake me a website for free\u201d, but more often it\u2019s cool things like \u201cCome and speak at my conference\u201d, \u201cWrite an article for my magazine\u201d and \u201cCollaborate with me.\u201d\n8. The young people are coming!\nThey love typography, they love print, they love layout, but they\u2019ve known how to put a website together since they started their first blog aged five and they show me clever apps they\u2019ve knocked together over the weekend! They\u2019re new, they\u2019re fluid, and they\u2019re better than us!\n9. Your portfolio is your portfolio\nOK, it\u2019s an obvious one, but as designers our work is our CV, our legacy! We need to show our skill, our attention to detail and our creativity in the way we showcase our work. Building your portfolio is the best way to start building your own websites. (And please be that designer who\u2019s bothered to work out how to change the Squarespace favicon!) \n10. It keeps you fluid!\nBuilding your own websites is tough. You\u2019ll never be happy with it, you\u2019ll constantly be updating it to keep up with technology and fashion, and by the time you\u2019ve finished it you\u2019ll want to start all over again. Perfect for forcing you to stay up-to-date with what\u2019s going on in the industry.\n
    ", "year": "2015", "author": "Ros Horner", "author_slug": "roshorner", "published": "2015-12-12T00:00:00+00:00", "url": "https://24ways.org/2015/be-fluid-with-your-design-skills-build-your-own-sites/", "topic": "code"} {"rowid": 71, "title": "Upping Your Web Security Game", "contents": "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.\nIf the web security game was hard to win before, it\u2019s doomed to fail now. In today\u2019s 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.\nSecurity teams, when they exist at all, cannot solve this problem. They are vastly outnumbered by developers, and cannot keep up with the application\u2019s 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.\nWhere To Start?\nEmbracing security isn\u2019t something you do overnight.\nA good place to start is by reviewing things you\u2019re already doing \u2013 and trying to make them more secure. Here are three concrete steps you can take to get going.\nHTTPS\nThreats 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\u2019re talking to, and that the information exchanged can be neither modified nor sniffed.\nHTTPS 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.\nUsing HTTPS is becoming easier and cheaper. Here are a few free tools that can help:\n\nGet free and easy HTTPS delivery from Cloudflare (be sure to use \u201cFull SSL\u201d!)\nGet a free and automation-friendly certificate from Let\u2019s Encrypt (now in open beta).\nTest how well your HTTPS is set up using SSLTest.\n\nOther vendors and platforms are rapidly simplifying and reducing the cost of their HTTPS offering, as demand and importance grows.\nTwo-Factor Authentication\nThe 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.\nAll 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.\nThe typical algorithm for 2FA is based on an IETF standard called the time-based one-time password (TOTP) algorithm, and it isn\u2019t 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\u2019t want to build 2FA support yourself, you can purchase two/multi-factor authentication services from vendors such as DuoSecurity, Auth0, Clef, Hypr and others.\nIf 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\u2019re sharing with them in the process.\nTracking Known Vulnerabilities\nMost 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.\nThis 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.\nTo find known security issues, take stock of your dependencies and match them against language-specific lists such as Snyk\u2019s vulnerability DB for Node.js, rubysec for Ruby, victims-db for Python and OWASP\u2019s 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. \nThis process is still way too painful, which means most teams don\u2019t 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\u2019s wizard will help you find and fix these issues through guided upgrades and patches, and adding Snyk\u2019s test to your continuous integration and deployment (CI/CD) will help you stay secure as your code evolves.\nNote that newly disclosed vulnerabilities usually impact old code \u2013 the one you\u2019re 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\u2019s monitor will proactively let you know about new disclosures relevant to your code, but only for Node.js for now \u2013 you can register to get updated when we expand.\nSecuring Yourself\nIn addition to making your application secure, you should make the contributors to that application secure \u2013 including you. Earlier this year we\u2019ve seen attackers target mobile app developers with a malicious Xcode. The real target, however, wasn\u2019t 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.\nThere\u2019s no single step that will make you fully secure, but here are a few steps that can make a big impact:\n\nUse 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\u2019d recommend using 2FA on all your personal services too.\nUse 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\u2019t let the attackers access your other systems too.\nSecure 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.\nBe very wary of phishing. Smart attackers use \u2018spear phishing\u2019 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.\nDon\u2019t install things through curl | sudo bash, especially if the URL is on GitHub, meaning someone else controls it. Don\u2019t do it on your machines, and definitely don\u2019t do it in your CI/CD systems. Seriously.\n\nStaying secure should be important to you personally, but it\u2019s 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.\nA Culture of Security\nUsing 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.\nThe end goal is to embrace security as an aspect of quality, and accept we all share the responsibility of keeping ourselves \u2013 and our users \u2013 safe.", "year": "2015", "author": "Guy Podjarny", "author_slug": "guypodjarny", "published": "2015-12-11T00:00:00+00:00", "url": "https://24ways.org/2015/upping-your-web-security-game/", "topic": "code"} {"rowid": 54, "title": "Putting My Patterns through Their Paces", "contents": "Over the last few years, the conversation around responsive design has shifted subtly, focusing not on designing pages, but on patterns: understanding the small, reusable elements that comprise a larger design system. And given that many of those patterns are themselves responsive, learning to manage these small layout systems has become a big part of my work.\nThe thing is, the more pattern-driven work I do, the more I realize my design process has changed in a number of subtle, important ways. I suppose you might even say that pattern-driven design has, in a few ways, redesigned me.\nMeet the Teaser\nHere\u2019s a recent example. A few months ago, some friends and I redesigned The Toast. (It was a really, really fun project, and we learned a lot.) Each page of the site is, as you might guess, stitched together from a host of tiny, reusable patterns. Some of them, like the search form and footer, are fairly unique, and used once per page; others are used more liberally, and built for reuse. The most prevalent example of these more generic patterns is the teaser, which is classed as, uh, .teaser. (Look, I never said I was especially clever.)\nIn its simplest form, a teaser contains a headline, which links to an article:\n\nFairly straightforward, sure. But it\u2019s just the foundation: from there, teasers can have a byline, a description, a thumbnail, and a comment count. In other words, we have a basic building block (.teaser) that contains a few discrete content types \u2013 some required, some not. In fact, very few of those pieces need to be present; to qualify as a teaser, all we really need is a link and a headline. But by adding more elements, we can build slight variations of our teaser, and make it much, much more versatile.\n\n Nearly every element visible on this page is built out of our generic \u201cteaser\u201d pattern.\n \nBut the teaser variation I\u2019d like to call out is the one that appears on The Toast\u2019s homepage, on search results or on section fronts. In the main content area, each teaser in the list features larger images, as well as an interesting visual treatment: the byline and comment count were the most prominent elements within each teaser, appearing above the headline.\n\n The approved visual design of our teaser, as it appears on lists on the homepage and the section fronts.\n \nAnd this is, as it happens, the teaser variation that gave me pause. Back in the old days \u2013 you know, like six months ago \u2013 I probably would\u2019ve marked this module up to match the design. In other words, I would\u2019ve looked at the module\u2019s visual hierarchy (metadata up top, headline and content below) and written the following HTML:\n
    \n \n 126 comments\n

    Article Title

    \n

    Lorem ipsum dolor sit amet, consectetur\u2026

    \n
    \nBut then I caught myself, and realized this wasn\u2019t the best approach.\nMoving Beyond Layout\nSince I\u2019ve started working responsively, there\u2019s a question I work into every step of my design process. Whether I\u2019m working in Sketch, CSSing a thing, or researching a project, I try to constantly ask myself:\n\nWhat if someone doesn\u2019t browse the web like I do?\n\n\u2026Okay, that doesn\u2019t seem especially fancy. (And maybe you came here for fancy.) But as straightforward as that question might seem, it\u2019s been invaluable to so many aspects of my practice. If I\u2019m working on a widescreen layout, that question helps me remember the constraints of the small screen; if I\u2019m working on an interface that has some enhancements for touch, it helps me consider other input modes as I work. It\u2019s also helpful as a reminder that many might not see the screen the same way I do, and that accessibility (in all its forms) should be a throughline for our work on the web.\nAnd that last point, thankfully, was what caught me here. While having the byline and comment count at the top was a lovely visual treatment, it made for a terrible content hierarchy. For example, it\u2019d be a little weird if the page was being read aloud in a speaking browser: the name of the author and the number of comments would be read aloud before the title of the article with which they\u2019re associated.\nThat\u2019s why I find it\u2019s helpful to begin designing a pattern\u2019s hierarchy before its layout: to move past the visual presentation in front of me, and focus on the underlying content I\u2019m trying to support. In other words, if someone\u2019s encountering my design without the CSS I\u2019ve written, what should their experience be?\nSo I took a step back, and came up with a different approach:\n
    \n

    Article Title

    \n \n

    \n Lorem ipsum dolor sit amet, consectetur\u2026\n 126 comments\n

    \n
    \nMuch, much better. This felt like a better match for the content I was designing: the headline \u2013 easily most important element \u2013 was at the top, followed by the author\u2019s name and an excerpt. And while the comment count is visually the most prominent element in the teaser, I decided it was hierarchically the least critical: that\u2019s why it\u2019s at the very end of the excerpt, the last element within our teaser. And with some light styling, we\u2019ve got a respectable-looking hierarchy in place:\n\nYeah, you\u2019re right \u2013 it\u2019s not our final design. But from this basic-looking foundation, we can layer on a bit more complexity. First, we\u2019ll bolster the markup with an extra element around our title and byline:\n
    \n \n \u2026\n
    \nWith that in place, we can use flexbox to tweak our layout, like so:\n.teaser-hed {\n display: flex;\n flex-direction: column-reverse;\n}\nflex-direction: column-reverse acts a bit like a change in gravity within our teaser-hed element, vertically swapping its two children.\n\nGetting closer! But as great as flexbox is, it doesn\u2019t do anything for elements outside our container, like our little comment count, which is, as you\u2019ve probably noticed, still stranded at the very bottom of our teaser.\nFlexbox is, as you might already know, wonderful! And while it enjoys incredibly broad support, there are enough implementations of old versions of Flexbox (in addition to plenty of bugs) that I tend to use a feature test to check if the browser\u2019s using a sufficiently modern version of flexbox. Here\u2019s the one we used:\nvar doc = document.body || document.documentElement;\nvar style = doc.style;\n\nif ( style.webkitFlexWrap == '' ||\n style.msFlexWrap == '' ||\n style.flexWrap == '' ) {\n doc.className += \" supports-flex\";\n}\nEagle-eyed readers will note we could have used @supports feature queries to ask browsers if they support certain CSS properties, removing the JavaScript dependency. But since we wanted to serve the layout to IE we opted to write a little question in JavaScript, asking the browser if it supports flex-wrap, a property used elsewhere in the design. If the browser passes the test, then a class of supports-flex gets applied to our html element. And with that class in place, we can safely quarantine our flexbox-enabled layout from less-capable browsers, and finish our teaser\u2019s design:\n.supports-flex .teaser-hed {\n display: flex;\n flex-direction: column-reverse;\n}\n.supports-flex .teaser .comment-count {\n position: absolute;\n right: 0;\n top: 1.1em;\n}\nIf the supports-flex class is present, we can apply our flexbox layout to the title area, sure \u2013 but we can also safely use absolute positioning to pull our comment count out of its default position, and anchor it to the top right of our teaser. In other words, the browsers that don\u2019t meet our threshold for our advanced styles are left with an attractive design that matches our HTML\u2019s content hierarchy; but the ones that pass our test receive the finished, final design.\n\nAnd with that, our teaser\u2019s complete.\nDiving Into Device-Agnostic Design\nThis is, admittedly, a pretty modest application of flexbox. (For some truly next-level work, I\u2019d recommend Heydon Pickering\u2019s \u201cFlexbox Grid Finesse\u201d, or anything Zoe Mickley Gillenwater publishes.) And for such a simple module, you might feel like this is, well, quite a bit of work. And you\u2019d be right! In fact, it\u2019s not one layout, but two: a lightly styled content hierarchy served to everyone, with the finished design served conditionally to the browsers that can successfully implement it. But I\u2019ve found that thinking about my design as existing in broad experience tiers \u2013 in layers \u2013 is one of the best ways of designing for the modern web. And what\u2019s more, it works not just for simple modules like our teaser, but for more complex or interactive patterns as well.\nOpen video\n \n Even a simple search form can be conditionally enhanced, given a little layered thinking.\n \nThis more layered approach to interface design isn\u2019t a new one, mind you: it\u2019s been championed by everyone from Filament Group to the BBC. And with all the challenges we keep uncovering, a more device-agnostic approach is one of the best ways I\u2019ve found to practice responsive design. As Trent Walton once wrote,\n\nLike cars designed to perform in extreme heat or on icy roads, websites should be built to face the reality of the web\u2019s inherent variability.\n\nWe have a weird job, working on the web. We\u2019re designing for the latest mobile devices, sure, but we\u2019re increasingly aware that our definition of \u201csmartphone\u201d is much too narrow. Browsers have started appearing on our wrists and in our cars\u2019 dashboards, but much of the world\u2019s mobile data flows over sub-3G networks. After all, the web\u2019s evolution has never been charted along a straight line: it\u2019s simultaneously getting slower and faster, with devices new and old coming online every day. With all the challenges in front of us, including many we don\u2019t yet know about, a more device-agnostic, more layered design process can better prepare our patterns \u2013 and ourselves \u2013 for the future.\n(It won\u2019t help you get enough to eat at holiday parties, though.)", "year": "2015", "author": "Ethan Marcotte", "author_slug": "ethanmarcotte", "published": "2015-12-10T00:00:00+00:00", "url": "https://24ways.org/2015/putting-my-patterns-through-their-paces/", "topic": "code"} {"rowid": 61, "title": "Animation in Responsive Design", "contents": "Animation and responsive design can sometimes feel like they\u2019re at odds with each other. Animation often needs space to do its thing, but RWD tells us that the amount of space we\u2019ll have available is going to change a lot. Balancing that can lead to some tricky animation situations. \nEmbracing the squishiness of responsive design doesn\u2019t have to mean giving up on your creative animation ideas. There are three general techniques that can help you balance your web animation creativity with your responsive design needs. One or all of these approaches might help you sneak in something just a little extra into your next project.\nFocused art direction\nSmaller viewports mean a smaller stage for your motion to play out on, and this tends to amplify any motion in your animation. Suddenly 100 pixels is really far and multiple moving parts can start looking like they\u2019re battling for space. An effect that looked great on big viewports can become muddled and confusing when it\u2019s reframed in a smaller space.\nMaking animated movements smaller will do the trick for simple motion like a basic move across the screen. But for more complex animation on smaller viewports, you\u2019ll need to simplify and reduce the number of moving parts. The key to this is determining what the vital parts of the animation are, to zone in on the parts that are most important to its message. Then remove the less necessary bits to distill the motion\u2019s message down to the essentials. \nFor example, Rally Interactive\u2019s navigation folds down into place with two triangle shapes unfolding each corner on larger viewports. If this exact motion was just scaled down for narrower spaces the two corners would overlap as they unfolded. It would look unnatural and wouldn\u2019t make much sense. \nOpen video\n\nThe main purpose of this animation is to show an unfolding action. To simplify the animation, Rally unfolds only one side for narrower viewports, with a slightly different animation. The action is still easily interpreted as unfolding and it\u2019s done in a way that is a better fit for the available space. The message the motion was meant to convey has been preserved while the amount of motion was simplified. \nOpen video\n\nSi Digital does something similar. The main concept of the design is to portray the studio as a creative lab. On large viewports, this is accomplished primarily through an animated illustration that runs the full length of the site and triggers its animations based on your scroll position. The illustration is there to support the laboratory concept visually, but it doesn\u2019t contain critical content.\nOpen video\n\nAt first, it looks like Si Digital just turned off the animation of the illustration for smaller viewports. But they\u2019ve actually been a little cleverer than that. They\u2019ve also reduced the complexity of the illustration itself. Both the amount of motion (reduced down to no motion) and the illustration were simplified to create a result that is much easier to glean the concept from.\nOpen video\n\nThe most interesting thing about these two examples is that they\u2019re solved more with thoughtful art direction than complex code. Keeping the main concept of the animations at the forefront allowed each to adapt creative design solutions to viewports of varying size without losing the integrity of their design. \nResponsive choreography\nStatic content gets moved around all the time in responsive design. A three-column layout might line up from left to right on wide viewports, then stack top to bottom on narrower viewports. The same approach can be used to arrange animated content for narrower views, but the animation\u2019s choreography also needs to be adjusted for the new layout. Even with static content, just scaling it down or zooming out to fit it into the available space is rarely an ideal solution. Rearranging your animations\u2019 choreography to change which animation starts when, or even which animations play at all, keeps your animated content readable on smaller viewports. \nIn a recent project I had three small animations that played one after the other, left to right, on wider viewports but needed to be stacked on narrower viewports to be large enough to see. On wide viewports, all three animations could play one right after the other in sequence because all three were in the viewable area at the same time. But once these were stacked for the narrower viewport layouts, that sequence had to change. \nOpen video\n\nWhat was essentially one animation on wider viewports became three separate animations when stacked on narrower viewports. The layout change meant the choreography had to change as well. Each animation starts independently when it comes into view in the stacked layout instead of playing automatically in sequence. (I\u2019ve put the animated parts in this demo if you want to peek under the hood.) \nOpen video\n\nI choose to use the GreenSock library, with the choreography defined in two different timelines for this particular project. But the same goals could be accomplished with other JavaScript options or even CSS keyframe animations and media queries. \nEven more complex responsive choreography can be pulled off with SVG. Media queries can be used to change CSS animations applied to SVG elements at specific breakpoints for starters. For even more responsive power, SVG\u2019s viewBox property, and the positioning of the objects within it, can be adjusted at JavaScript-defined breakpoints. This lets you set rules to crop the viewable area and arrange your animating elements to fit any space. \nSarah Drasner has some great examples of how to use this technique with style in this responsive infographic and this responsive interactive illustration. On the other hand, if smart scalability is what you\u2019re after, it\u2019s also possible to make all of an SVG\u2019s shapes and motion scale with the SVG canvas itself. Sarah covers both these clever responsive SVG techniques in detail. Creative and complex animation can easily become responsive thanks to the power of SVG! \nOpen video\n\nBake performance into your design decisions\nIt\u2019s hard to get very far into a responsive design discussion before performance comes up. Performance goes hand in hand with responsive design and your animation decisions can have a big impact on the overall performance of your site. \nThe translate3D \u201chack\u201d, backface-visibility:hidden, and the will-change property are the heavy hitters of animation performance. But decisions made earlier in your animation design process can have a big impact on rendering performance and your performance budget too.\nPick a technology that matches your needs\nOne of the biggest advantages of the current web animation landscape is the range of tools we have available to us. We can use CSS animations and transitions to add just a dash of interface animation to our work, go all out with webGL to create a 3D experience, or anywhere in between. All within our browsers! Having this huge range of options is amazing and wonderful but it also means you need to be cognizant of what you\u2019re using to get the job done. \nLoading in the full weight of a robust JavaScript animation library is going to be overkill if you\u2019re only animating a few small elements here and there. That extra overhead will have an impact on performance. Performance budgets will not be pleased. \nAlways match the complexity of the technology you choose to the complexity of your animation needs to avoid unnecessary performance strain. For small amounts of animation, stick to CSS solutions since it\u2019s the most lightweight option. As your animations grow in complexity, or start to require more robust logic, move to a JavaScript solution that can accomplish what you need.\nAnimate the most performant properties\nWhether you\u2019re animating in CSS or JavaScript, you\u2019re affecting specific properties of the animated element. Browsers can animate some properties more efficiently than others based on how many steps need to happen behind the scenes to visually update those properties. \nBrowsers are particularly efficient at animating opacity, scale, rotation, and position (when the latter three are done with transforms). This article from Paul Irish and Paul Lewis gives the full scoop on why. Conveniently, those are also the most common properties used in motion design. There aren\u2019t many animated effects that can\u2019t be pulled off with this list. Stick to these properties to set your animations up for the best performance results from the start. If you find yourself needing to animate a property outside of this list, check CSS Triggers\u2026 to find out how much of an additional impact it might have.\nOffset animation start times\nOffsets (the concept of having a series of similar movements execute one slightly after the other, creating a wave-like pattern) are a long-held motion graphics trick for creating more interesting and organic looking motion. Employing this trick of the trade can also be smart for performance. Animating a large number of objects all at the same time can put a strain on the browser\u2019s rendering abilities even in the best cases. Adding short delays to offset these animations in time, so they don\u2019t all start at once, can improve rendering performance. \nGo explore the responsive animation possibilities for yourself!\nWith smart art direction, responsive choreography, and an eye on performance you can create just about any creative web animation you can think up while still being responsive. Keep these in mind for your next project and you\u2019ll pull off your animations with style at any viewport size!", "year": "2015", "author": "Val Head", "author_slug": "valhead", "published": "2015-12-09T00:00:00+00:00", "url": "https://24ways.org/2015/animation-in-responsive-design/", "topic": "design"} {"rowid": 56, "title": "Helping VIPs Care About Performance", "contents": "Making a site feel super fast is the easy part of performance work. Getting people around you to care about site speed is a much bigger challenge. How do we keep the site fast beyond the initial performance work? Keeping very important people like your upper management or clients invested in performance work is critical to keeping a site fast and empowering other designers and developers to contribute.\nThe work to get others to care is so meaty that I dedicated a whole chapter to the topic in my book Designing for Performance. When I speak at conferences, the majority of questions during Q&A are on this topic. When I speak to developers and designers who care about performance, getting other people at one\u2019s organization or agency to care becomes the most pressing question.\nMy primary response to folks who raise this issue is the question: \u201cWhat metric(s) do your VIPs care about?\u201d This is often met with blank stares and raised eyebrows. But it\u2019s also our biggest clue to what we need to do to help empower others to care about performance and work on it. Every organization and executive is different. This means that three major things vary: the primary metrics VIPs care about; the language they use about measuring success; and how change is enacted. By clueing in to these nuances within your organization, you can get a huge leg up on crafting a successful pitch about performance work.\nLet\u2019s start with the metric that we should measure. Sure, (most) everybody cares about money - but is that really the metric that your VIPs are looking at each day to measure the success or efficacy of your site? More likely, dollars are the end game, but the metrics or key performance indicators (KPIs) people focus on might be:\n\nrate of new accounts created/signups\ncost of acquiring or retaining a customer\nvisitor return rate\nvisitor bounce rate\nfavoriting or another interaction rate\n\nThese are just a few examples, but they illustrate how wide-ranging the options are that people care about. I find that developers and designers haven\u2019t necessarily investigated this when trying to get others to care about performance. We often reach for the obvious \u2013 money! \u2013 but if we don\u2019t use the same kind of language our VIPs are using, we might not get too far. You need to know this before you can make the case for performance work.\nTo find out these metrics or KPIs, start reading through the emails your VIPs are sending within your company. What does it say on company wikis? Are there major dashboards internally that people are looking at where you could find some good metrics? Listen intently in team meetings or thoroughly read annual reports to see what these metrics could be.\nThe second key here is to pick up on language you can effectively copy and paste as you make the case for performance work. You need to be able to reflect back the metrics that people already find important in a way they\u2019ll be able to hear. Once you know your key metrics, it\u2019s time to figure out how to communicate with your VIPs about performance using language that will resonate with them.\nLet\u2019s start with visit traffic as an example metric that a very important person cares about. Start to dig up research that other people and companies have done that correlates performance and your KPI. For example, cite studies:\n\n\u201cWhen the home page of Google Maps was reduced from 100KB to 70\u201380KB, traffic went up 10% in the first week, and an additional 25% in the following three weeks.\u201d (source).\n\nRead through websites like WPOStats, which collects the spectrum of studies on the impact of performance optimization on user experience and business metrics. Tweet and see if others have done similar research that correlates performance and your site\u2019s main KPI.\nOnce you have collected some research that touches on the same kind of language your VIPs use about the success of your site, it\u2019s time to present it. You can start with something simple, like a qualitative description of the work you\u2019re actively doing to improve the site that translates to improved metrics that your VIPs care about. It can be helpful to append a performance budget to any proposal so you can compare the budget to your site\u2019s reality and how it might positively impact those KPIs folks care about.\nWords and graphs are often only half the battle when it comes to getting others to care about performance. Often, videos appeal to folks\u2019 emotions in a way that is missed when glancing through charts and graphs. On A List Apart I recently detailed how to create videos of how fast your site loads. Let\u2019s say that your VIPs care about how your site loads on mobile devices; it\u2019s time to show them how your site loads on mobile networks.\nOpen video\n\nYou can use these videos to make a number of different statements to your VIPs, depending on what they care about:\n\nLook at how slow our site loads versus our competitor!\nLook at how slow our site loads for users in another country!\nLook at how slow our site loads on mobile networks!\n\nAgain, you really need to know which metrics your VIPs care about and tune into the language they\u2019re using. If they don\u2019t care about the overall user experience of your site on mobile devices, then showing them how slow your site loads on 3G isn\u2019t going to work. This will be your sales pitch; you need to practice and iterate on the language and highlights that will land best with your audience. \nTo make your sales pitch as solid as possible, gut-check your ideas on how to present it with other co-workers to get their feedback. Read up on how to construct effective arguments and deliver them; do some research and see what others have done at your company when pitching to VIPs. Are slides effective? Memos or emails? Hallway conversations? Sometimes the best way to change people\u2019s minds is by mentioning it in informal chats over coffee. Emulate the other leaders in your organization who are successful at this work. \nEvery organization and very important person is different. Learn what metrics folks truly care about, study the language that they use, and apply what you\u2019ve learned in a way that\u2019ll land with those individuals. It may take time to craft your pitch for performance work over time, but it\u2019s important work to do. If you\u2019re able to figure out how to mirror back the language and metrics VIPs care about, and connect the dots to performance for them, you will have a huge leg up on keeping your site fast in the long run.", "year": "2015", "author": "Lara Hogan", "author_slug": "larahogan", "published": "2015-12-08T00:00:00+00:00", "url": "https://24ways.org/2015/helping-vips-care-about-performance/", "topic": "business"} {"rowid": 52, "title": "Git Rebasing: An Elfin Workshop Workflow", "contents": "This year Santa\u2019s helpers have been tasked with making a garland. It\u2019s a pretty simple task: string beads onto yarn in a specific order. When the garland reaches a specific length, add it to the main workshop garland. Each elf has a specific sequence they\u2019re supposed to chain, which is given to them via a work order. (This is starting to sound like one of those horrible calculus problems. I promise it isn\u2019t. It\u2019s worse; it\u2019s about Git.)\nFor the most part, the system works really well. The elves are able to quickly build up a shared chain because each elf specialises on their own bit of garland, and then links the garland together. Because of this they\u2019re able to work independently, but towards the common goal of making a beautiful garland.\nAt first the elves are really careful with each bead they put onto the garland. They check with one another before merging their work, and review each new link carefully. As time crunches on, the elves pour a little more cheer into the eggnog cooler, and the quality of work starts to degrade. Tensions rise as mistakes are made and unkind words are said. The elves quickly realise they\u2019re going to need a system to change the beads out when mistakes are made in the chain.\nThe first common mistake is not looking to see what the latest chain is that\u2019s been added to the main garland. The garland is huge, and it sits on a roll in one of the corners of the workshop. It\u2019s a big workshop, so it is incredibly impractical to walk all the way to the roll to check what the last link is on the chain. The elves, being magical, have set up a monitoring system that allows them to keep a local copy of the main garland at their workstation. It\u2019s an imperfect system though, so the elves have to request a manual refresh to see the latest copy. They can request a new copy by running the command\ngit pull --rebase=preserve\n(They found that if they ran git pull on its own, they ended up with weird loops of extra beads off the main garland, so they\u2019ve opted to use this method.) This keeps the shared garland up to date, which makes things a lot easier. A visualisation of the rebase process is available.\nThe next thing the elves noticed is that if they worked on the main workshop garland, they were always running into problems when they tried to share their work back with the rest of the workshop. It was fine if they were working late at night by themselves, but in the middle of the day, it was horrible. (I\u2019ve been asked not to talk about that time the fight broke out.) Instead of trying to share everything on their local copy of the main garland, the elves have realised it\u2019s a lot easier to work on a new string and then knot this onto the main garland when their pattern repeat is finished. They generate a new string by issuing the following commands:\ngit checkout master\ngit checkout -b 1234_pattern-name\n1234 represents the work order number and pattern-name describes the pattern they\u2019re adding. Each bead is then added to the new link (git add bead.txt) and locked into place (git commit). Each elf repeats this process until the sequence of beads described in the work order has been added to their mini garland.\nTo combine their work with the main garland, the elves need to make a few decisions. If they\u2019re making a single strand, they issue the following commands:\ngit checkout master\ngit merge --ff-only 1234_pattern-name\nTo share their work they publish the new version of the main garland to the workshop spool with the command git push origin master.\nSometimes this fails. Sharing work fails because the workshop spool has gotten new links added since the elf last updated their copy of the main workshop spool. This makes the elves both happy and sad. It makes them happy because it means the other elves have been working too, but it makes them sad because they now need to do a bit of extra work to close their work order. \nTo update the local copy of the workshop spool, the elf first unlinks the chain they just linked by running the command:\ngit reset --merge ORIG_HEAD\nThis works because the garland magic notices when the elves are doing a particularly dangerous thing and places a temporary, invisible bookmark to the last safe bead in the chain before the dangerous thing happened. The garland no longer has the elf\u2019s work, and can be updated safely. The elf runs the command git pull --rebase=preserve and the changes all the other elves have made are applied locally.\nWith these new beads in place, the elf now has to restring their own chain so that it starts at the right place. To do this, the elf turns back to their own chain (git checkout 1234_pattern-name) and runs the command git rebase master. Assuming their bead pattern is completely unique, the process will run and the elf\u2019s beads will be restrung on the tip of the main workshop garland.\nSometimes the magic fails and the elf has to deal with merge conflicts. These are kind of annoying, so the elf uses a special inspector tool to figure things out. The elf opens the inspector by running the command git mergetool to work through places where their beads have been added at the same points as another elf\u2019s beads. Once all the conflicts are resolved, the elf saves their work, and quits the inspector. They might need to do this a few times if there are a lot of new beads, so the elf has learned to follow this update process regularly instead of just waiting until they\u2019re ready to close out their work order.\nOnce their link is up to date, the elf can now reapply their chain as before, publish their work to the main workshop garland, and close their work order:\ngit checkout master\ngit merge --ff-only 1234_pattern-name\ngit push origin master\nGenerally this process works well for the elves. Sometimes, though, when they\u2019re tired or bored or a little drunk on festive cheer, they realise there\u2019s a mistake in their chain of beads. Fortunately they can fix the beads without anyone else knowing. These tools can be applied to the whole workshop chain as well, but it causes problems because the magic assumes that elves are only ever adding to the main chain, not removing or reordering beads on the fly. Depending on where the mistake is, the elf has a few different options.\nLet\u2019s pretend the elf has a sequence of five beads she\u2019s been working on. The work order says the pattern should be red-blue-red-blue-red.\n\nIf the sequence of beads is wrong (for example, blue-blue-red-red-red), the elf can remove the beads from the chain, but keep the beads in her workstation using the command git reset --soft HEAD~5.\n\nIf she\u2019s been using the wrong colours and the wrong pattern (for example, green-green-yellow-yellow-green), she can remove the beads from her chain and discard them from her workstation using the command git reset --hard HEAD~5.\n\nIf one of the beads is missing (for example, red-blue-blue-red), she can restring the beads using the first method, or she can use a bit of magic to add the missing bead into the sequence.\n\nUsing a tool that\u2019s a bit like orthoscopic surgery, she first selects a sequence of beads which contains the problem. A visualisation of this process is available.\nStart the garland surgery process with the command:\ngit rebase --interactive HEAD~4\nA new screen comes up with the following information (the oldest bead is on top):\npick c2e4877 Red bead\npick 9b5555e Blue bead\npick 7afd66b Blue bead\npick e1f2537 Red bead\nThe elf adjusts the list, changing \u201cpick\u201d to \u201cedit\u201d next to the first blue bead:\npick c2e4877 Red bead\nedit 9b5555e Blue bead\npick 7afd66b Blue bead\npick e1f2537 Red bead\nShe then saves her work and quits the editor. The garland magic has placed her back in time at the moment just after she added the first blue bead.\n\nShe needs to manually fix up her garland to add the new red bead. If the beads were files, she might run commands like vim beads.txt and edit the file to make the necessary changes.\nOnce she\u2019s finished her changes, she needs to add her new bead to the garland (git add --all) and lock it into place (git commit). This time she assigns the commit message \u201cRed bead \u2013 added\u201d so she can easily find it.\n\nThe garland magic has replaced the bead, but she still needs to verify the remaining beads on the garland. This is a mostly automatic process which is started by running the command git rebase --continue.\nThe new red bead has been assigned a position formerly held by the blue bead, and so the elf must deal with a merge conflict. She opens up a new program to help resolve the conflict by running git mergetool.\n\nShe knows she wants both of these beads in place, so the elf edits the file to include both the red and blue beads.\n\nWith the conflict resolved, the elf saves her changes and quits the mergetool.\nBack at the command line, the elf checks the status of her work using the command git status.\nrebase in progress; onto 4a9cb9d\nYou are currently rebasing branch '2_RBRBR' on '4a9cb9d'.\n (all conflicts fixed: run \"git rebase --continue\")\n\nChanges to be committed:\n (use \"git reset HEAD ...\" to unstage)\n\n modified: beads.txt\n\nUntracked files:\n (use \"git add ...\" to include in what will be committed)\n\n beads.txt.orig\nShe removes the file added by the mergetool with the command rm beads.txt.orig and commits the edits she just made to the bead file using the commands:\ngit add beads.txt\ngit commit --message \"Blue bead -- resolved conflict\"\n\nWith the conflict resolved, the elf is able to continue with the rebasing process using the command git rebase --continue. There is one final conflict the elf needs to resolve. Once again, she opens up the visualisation tool and takes a look at the two conflicting files.\n\nShe incorporates the changes from the left and right column to ensure her bead sequence is correct.\n\nOnce the merge conflict is resolved, the elf saves the file and quits the mergetool. Once again, she cleans out the backup file added by the mergetool (rm beads.txt.orig) and commits her changes to the garland:\ngit add beads.txt\ngit commit --message \"Red bead -- resolved conflict\"\nand then runs the final verification steps in the rebase process (git rebase --continue).\n\nThe verification process runs through to the end, and the elf checks her work using the command git log --oneline.\n9269914 Red bead -- resolved conflict\n4916353 Blue bead -- resolved conflict\naef0d5c Red bead -- added\n9b5555e Blue bead\nc2e4877 Red bead\nShe knows she needs to read the sequence from bottom to top (the oldest bead is on the bottom). Reviewing the list she sees that the sequence is now correct.\nSometimes, late at night, the elf makes new copies of the workshop garland so she can play around with the bead sequencer just to see what happens. It\u2019s made her more confident at restringing beads when she\u2019s found real mistakes. And she doesn\u2019t mind helping her fellow elves when they run into trouble with their beads. The sugar cookies they leave her as thanks don\u2019t hurt either. If you would also like to play with the bead sequencer, you can get a copy of the branches the elf worked.\n\nOur lessons from the workshop:\n\nBy using rebase to update your branches, you avoid merge commits and keep a clean commit history.\nIf you make a mistake on one of your local branches, you can use reset to take commits off your branch. If you want to save the work, but uncommit it, add the parameter --soft. If you want to completely discard the work, use the parameter, --hard.\nIf you have merged working branch changes to the local copy of your master branch and it is preventing you from pushing your work to a remote repository, remove these changes using the command reset with the parameter --merge ORIG_HEAD before updating your local copy of the remote master branch.\nIf you want to make a change to work that was committed a little while ago, you can use the command rebase with the parameter --interactive. You will need to include how many commits back in time you want to review.", "year": "2015", "author": "Emma Jane Westby", "author_slug": "emmajanewestby", "published": "2015-12-07T00:00:00+00:00", "url": "https://24ways.org/2015/git-rebasing/", "topic": "code"} {"rowid": 70, "title": "Bringing Your Code to the Streets", "contents": "\u2014 or How to Be a Street VJ\nOur amazing world of web code is escaping out of the browser at an alarming rate and appearing in every aspect of the environment around us. Over the past few years we\u2019ve already seen JavaScript used server-side, hardware coded with JavaScript, a rise of native style and desktop apps created with HTML, CSS and JavaScript, and even virtual reality (VR) is getting its fair share of front-end goodness.\nYou can go ahead and play with JavaScript-powered hardware such as the Tessel or the Espruino to name a couple. Just check out the Tessel project page to see JavaScript in the world of coffee roasting or sleep tracking your pet. With the rise of the internet of things, JavaScript can be seen collecting information on flooding among other things. And if that\u2019s not enough \u2018outside the browser\u2019 implementations, Node.js servers can even be found in aircraft!\nI previously mentioned VR and with three.js\u2019s extra StereoEffect.js module it\u2019s relatively simple to get browser 3D goodness to be Google Cardboard-ready, and thus set the stage for all things JavaScript and VR. It\u2019s been pretty popular in the art world too, with interactive works such as Seb Lee-Delisle\u2019s Lunar Trails installation, featuring the old arcade game Lunar Lander, which you can now play in your browser while others watch (it is the web after all). The Science Museum in London held Chrome Web Lab, an interactive exhibition featuring five experiments, showcasing the magic of the web. And it\u2019s not even the connectivity of the web that\u2019s being showcased; we can even take things offline and use web code for amazing things, such as fighting Ebola.\nOne thing is for sure, JavaScript is awesome. Hell, if you believe those telly programs (as we all do), JavaScript can even take down the stock market, purely through the witchcraft of canvas! Go JavaScript!\nNow it\u2019s our turn\nSo I wanted to create a little project influenced by this theme, and as it\u2019s Christmas, take it to the streets for a little bit of party fun! Something that could take code anywhere. Here\u2019s how I made a portable visual projection pack, a piece of video mixing software and created some web-coded street art.\nStep one: The equipment\nYou will need:\n\nOne laptop: with HDMI output and a modern browser installed, such as Google Chrome.\nOne battery-powered mini projector: I\u2019ve used a Texas Instruments DLP; for its 120 lumens it was the best cost-to-lumens ratio I could find.\nOne MIDI controller (optional): mine is an ICON iDJ as it suits mixing visuals. However, there is more affordable hardware on the market such as an Akai LPD8 or a Korg nanoPAD2. As you\u2019ll see in the article, this is optional as it can be emulated within the software.\nA case to carry it all around in.\n\n\nStep two: The software\nThe projected visuals, I imagined, could be anything you can create within a browser, whether that be simple HTML and CSS, images, videos, SVG or canvas. The only requirement I have is that they move or change with sound and that I can mix any one visual into another.\nYou may remember a couple of years ago I created a demo on this very site, allowing audio-triggered visuals from the ambient sounds your device mic was picking up. That was a great starting point \u2013 I used that exact method to pick up the audio and thus the first requirement was complete. If you want to see some more examples of visuals I\u2019ve put together for this, there\u2019s a showcase on CodePen.\nThe second requirement took a little more thought. I needed two screens, which could at any point show any of the visuals I had coded, but could be mixed from one into the other and back again. So let\u2019s start with two divs, both absolutely positioned so they\u2019re on top of each other, but at the start the second screen\u2019s opacity is set to zero.\nNow all we need is a slider, which when moved from one side to the other slowly sets the second screen\u2019s opacity to 1, thereby fading it in.\nSee the Pen Mixing Screens (Software Version) by Rumyra (@Rumyra) on CodePen.\nMixing Screens (CodePen)\n\nAs you saw above, I have a MIDI controller and although the software method works great, I\u2019d quite like to make use of this nifty piece of kit. That\u2019s easily done with the Web MIDI API. All I need to do is call it, and when I move one of the sliders on the controller (I\u2019ve allocated the big cross fader in the middle for this), pick up on the change of value and use that to control the opacity instead.\nvar midi, data;\n// start talking to MIDI controller\nif (navigator.requestMIDIAccess) {\n navigator.requestMIDIAccess({\n sysex: false\n }).then(onMIDISuccess, onMIDIFailure);\n} else {\n alert(\u201cNo MIDI support in your browser.\u201d);\n}\n\n// on success\nfunction onMIDISuccess(midiData) {\n // this is all our MIDI data\n midi = midiData;\n\n var allInputs = midi.allInputs.values();\n // loop over all available inputs and listen for any MIDI input\n for (var input = allInputs.next(); input && !input.done; input = allInputs.next()) {\n // when a MIDI value is received call the onMIDIMessage function\n input.value.onmidimessage = onMIDIMessage;\n }\n}\n\nfunction onMIDIMessage(message) {\n // data comes in the form [command/channel, note, velocity]\n data = message.data;\n\n // Opacity change for screen. The cross fader values are [176, 8, {0-127}]\n if ( (data[0] === 176) && (data[1] === 8) ) {\n // this value will change as the fader is moved\n var opacity = data[2]/127;\n screenTwo.style.opacity = opacity;\n }\n}\n\nThe final code was slightly more complicated than this, as I decided to switch the two screens based on the frequencies of the sound that was playing, and use the cross fader to depict the frequency threshold value. This meant they flickered in and out of each other, rather than just faded. There\u2019s a very rough-and-ready first version of the software on GitHub.\nPhew, Great! Now we need to get all this to the streets!\nStep three: Portable kit\nDid you notice how I mentioned a case to carry it all around in? I wanted the case to be morphable, so I could use the equipment from it too, a sort of bag-to-usherette-tray-type affair. Well, I had an unused laptop bag\u2026\n\nI strengthened it with some MDF, so when I opened the bag it would hold like a tray where the laptop and MIDI controller would sit. The projector was Velcroed to the external pocket of the bag, so when it was a tray it would project from underneath. I added two durable straps, one for my shoulders and one round my waist, both attached to the bag itself. There was a lot of cutting and trimming. As it was a laptop bag it was pretty thick to start and sewing was tricky. However, I only broke one sewing machine needle; I\u2019ve been known to break more working with leather, so I figured I was doing well. By the way, you can actually buy usherette trays, but I just couldn\u2019t resist hacking my own :)\nStep four: Take to the streets\nFirst, make sure everything is charged \u2013 everything \u2013 a lot! The laptop has to power both the MIDI controller and the projector, and although I have a mobile phone battery booster pack, that\u2019ll only charge the projector should it run out. I estimated I could get a good hour of visual artistry before I needed to worry, though.\nI had a couple of ideas about time of day and location. Here in the UK at this time of year, it gets dark around half past four, so I could easily head out in a city around 5pm and it would be dark enough for the projections to be seen pretty well. I chose Bristol, around the waterfront, as there were some interesting locations to try it out in. The best was Millennium Square: busy but not crowded and plenty of surfaces to try projecting on to.\nMy first time out with the portable audio/visual pack (PAVP as it will now be named) was brilliant. I played music and projected visuals, like a one-woman band of A/V!\n\n\nYou might be thinking what the point of this was, besides, of course, it being a bit of fun. Well, this project got me to look at canvas and SVG more closely. The Web MIDI API was really interesting; MIDI as a data format has some great practical uses. I think without our side projects we may not have all these wonderful uses for our everyday code. Not only do they remind us coding can, and should, be fun, they also help us learn and grow as makers.\nMy favourite part? When I was projecting into a water feature in Millennium Square. For those who are familiar, you\u2019ll know it\u2019s like a wall of water so it produced a superb effect. I drew quite a crowd and a kid came to stand next to me and all I could hear him say with enthusiasm was, \u2018Oh wow! That\u2019s so cool!\u2019\nYes\u2026 yes, kid, it was cool. Making things with code is cool.\nMassive thanks to the lovely Drew McLellan for his incredibly well-directed photography, and also Simon Johnson who took a great hand in perfecting the kit while it was attached.", "year": "2015", "author": "Ruth John", "author_slug": "ruthjohn", "published": "2015-12-06T00:00:00+00:00", "url": "https://24ways.org/2015/bringing-your-code-to-the-streets/", "topic": "code"} {"rowid": 49, "title": "Universal React", "contents": "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.\nMore generally we\u2019ve 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\u2019s 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.\nThe 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:\n\nThe user visits www.yoursite.com and the server executes your JavaScript to generate the HTML it needs to render the page.\nIn the background, the client-side JavaScript is executed and takes over the duty of rendering the page.\nThe next time a user clicks, rather than being sent to the server, the client-side app is in control.\nIf the user doesn\u2019t have JavaScript enabled, each click on a link goes to the server and they get the server-rendered content again.\n\nThis 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\u2019s 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.\nIt\u2019s worth noting that this tutorial assumes some familiarity with React in general, its syntax and concepts. If you\u2019d like a refresher, the ReactJS docs are a good place to start.\n\u00a0Getting started\nWe\u2019re going to create a tiny ReactJS application that will work on the server and the client. First we\u2019ll need to create a new project and install some dependencies. In a new, blank directory, run:\nnpm init -y\nnpm install --save ejs express react react-router react-dom\nThat will create a new project and install our dependencies:\n\nejs is a templating engine that we\u2019ll use to render our HTML on the server.\nexpress is a small web framework we\u2019ll run our server on.\nreact-router is a popular routing solution for React so our app can fully support and respect URLs.\nreact-dom is a small React library used for rendering React components.\n\nWe\u2019re also going to write all our code in ECMAScript 6, and therefore need to install BabelJS and configure that too.\nnpm install --save-dev babel-cli babel-preset-es2015 babel-preset-react\nThen, create a .babelrc file that contains the following:\n{\n \"presets\": [\"es2015\", \"react\"]\n}\nWhat we\u2019ve done here is install Babel\u2019s 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\u2019ll need the React transforms when we start writing JSX when working with React.\nCreating a server\nFor now, our ExpressJS server is pretty straightforward. All we\u2019ll do is render a view that says \u2018Hello World\u2019. Here\u2019s our server code:\nimport express from 'express';\nimport http from 'http';\n\nconst app = express();\n\napp.use(express.static('public'));\n\napp.set('view engine', 'ejs');\n\napp.get('*', (req, res) => {\n res.render('index');\n});\n\nconst server = http.createServer(app);\n\nserver.listen(3003);\nserver.on('listening', () => {\n console.log('Listening on 3003');\n});\nHere we\u2019re using ES6 modules, which I wrote about on 24 ways last year, if you\u2019d like a reminder. We tell the app to render the index view on any GET request (that\u2019s what app.get('*') means, the wildcard matches any route).\nWe now need to create the index view file, which Express expects to be defined in views/index.ejs:\n\n\n \n My App\n \n\n \n Hello World\n \n\nFinally, we\u2019re 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:\n./node_modules/.bin/babel-node server.js\nAnd you should now be able to visit http://localhost:3003 and see \u2018Hello World\u2019 right there:\n\nBuilding the React app\nNow we\u2019ll 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.\nFirstly, let\u2019s 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:\n\n <%- markup %>\n\nNext, we\u2019ll define the routes we want our app to have using React Router. For now we\u2019ll 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\u2019s clearer to define them as an object. Here\u2019s what we\u2019re starting with:\nconst routes = {\n path: '',\n component: AppComponent,\n childRoutes: [\n {\n path: '/',\n component: IndexComponent\n }\n ]\n}\nThese are just placed at the top of server.js, after the import statements. Later we\u2019ll move these into a separate file, but for now they are fine where they are.\nNotice 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\u2019s quickly define components/app.js and components/index.js. app.js looks like so:\nimport React from 'react';\n\nexport default class AppComponent extends React.Component {\n render() {\n return (\n
    \n

    Welcome to my App

    \n { this.props.children }\n
    \n );\n }\n}\nWhen 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:\nimport React from 'react';\n\nexport default class IndexComponent extends React.Component {\n render() {\n return (\n
    \n

    This is the index page

    \n
    \n );\n }\n}\nServer-side routing with React Router\nHead back into server.js, and firstly we\u2019ll need to add some new imports:\nimport React from 'react';\nimport { renderToString } from 'react-dom/server';\nimport { match, RoutingContext } from 'react-router';\n\nimport AppComponent from './components/app';\nimport IndexComponent from './components/index';\nThe 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\u2019s this method that we\u2019ll 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\u2019ll need to render. This wraps up our components and provides some functionality that ties React Router together with our app. Generally you don\u2019t need to concern yourself about how this component works, so don\u2019t worry too much.\nNow for the good bit: we can update our app.get('*') route with the code that matches the URL against the React routes:\napp.get('*', (req, res) => {\n // routes is our object of React routes defined above\n match({ routes, location: req.url }, (err, redirectLocation, props) => {\n if (err) {\n // something went badly wrong, so 500 with a message\n res.status(500).send(err.message);\n } else if (redirectLocation) {\n // we matched a ReactRouter redirect, so redirect from the server\n res.redirect(302, redirectLocation.pathname + redirectLocation.search);\n } else if (props) {\n // if we got props, that means we found a valid component to render\n // for the given route\n const markup = renderToString();\n\n // render `index.ejs`, but pass in the markup we want it to display\n res.render('index', { markup })\n\n } else {\n // no route match, so 404. In a real app you might render a custom\n // 404 view here\n res.sendStatus(404);\n }\n });\n});\nWe 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\u2019ve made it this far it means we found a matching component to render and we can use this code to render it:\n...\n} else if (props) {\n // if we got props, that means we found a valid component to render\n // for the given route\n const markup = renderToString();\n\n // render `index.ejs`, but pass in the markup we want it to display\n res.render('index', { markup })\n} else {\n ...\n}\nThe 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.\nNote 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:\n\n\n// OR:\n\nconst props = { a: \"foo\", b: \"bar\" };\n\nRunning the server again\nI know that felt like a lot of work, but the good news is that once you\u2019ve 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!\n\nRefactoring and one more route\nBefore we move on to getting this code running on the client, let\u2019s add one more route and do some tidying up. First, move our routes object out into routes.js:\nimport AppComponent from './components/app';\nimport IndexComponent from './components/index';\n\nconst routes = {\n path: '',\n component: AppComponent,\n childRoutes: [\n {\n path: '/',\n component: IndexComponent\n }\n ]\n}\n\nexport { routes };\nAnd then update server.js. You can remove the two component imports and replace them with:\nimport { routes } from './routes';\nFinally, let\u2019s add one more route for ./about and links between them. Create components/about.js:\nimport React from 'react';\n\nexport default class AboutComponent extends React.Component {\n render() {\n return (\n
    \n

    A little bit about me.

    \n
    \n );\n }\n}\nAnd then you can add it to routes.js too:\nimport AppComponent from './components/app';\nimport IndexComponent from './components/index';\nimport AboutComponent from './components/about';\n\nconst routes = {\n path: '',\n component: AppComponent,\n childRoutes: [\n {\n path: '/',\n component: IndexComponent\n },\n {\n path: '/about',\n component: AboutComponent\n }\n ]\n}\n\nexport { routes };\nIf you now restart the server and head to http://localhost:3003/about` you\u2019ll see the about page!\n\nFor the finishing touch we\u2019ll use the React Router link component to add some links between the pages. Edit components/app.js to look like so:\nimport React from 'react';\nimport { Link } from 'react-router';\n\nexport default class AppComponent extends React.Component {\n render() {\n return (\n
    \n

    Welcome to my App

    \n
      \n
    • Home
    • \n
    • About
    • \n
    \n { this.props.children }\n
    \n );\n }\n}\nYou can now click between the pages to navigate. However, everytime we do so the requests hit the server. Now we\u2019re 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.\nClient-side rendering\nFirst, we\u2019re going to make a small change to views/index.ejs. React doesn\u2019t like rendering directly into the body and will give a warning when you do so. To prevent this we\u2019ll wrap our app in a div:\n\n
    <%- markup %>
    \n \n\nI\u2019ve also added in a script tag to build.js, which is the file we\u2019ll generate containing all our client-side code.\nNext, create client-render.js. This is going to be the only bit of JavaScript that\u2019s exclusive to the client side. In it we need to pull in our routes and render them to the DOM.\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Router } from 'react-router';\n\nimport { routes } from './routes';\n\nimport createBrowserHistory from 'history/lib/createBrowserHistory';\n\nReactDOM.render(\n ,\n document.getElementById('app')\n)\nThe 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\u2019s 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\u2019ve 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.\nFinally 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.\nGenerating build.js\nWe\u2019re actually almost there! The final thing we need to do is generate our client side bundle. For this we\u2019re going to use webpack, a module bundler that can take our application, follow all the imports and generate one large bundle from them. We\u2019ll install it and babel-loader, a webpack plugin for transforming code through Babel.\nnpm install --save-dev webpack babel-loader\nTo 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:\nvar path = require('path');\nmodule.exports = {\n entry: path.join(process.cwd(), 'client-render.js'),\n output: {\n path: './public/',\n filename: 'build.js'\n },\n module: {\n loaders: [\n {\n test: /.js$/,\n loader: 'babel'\n }\n ]\n }\n}\nNote first that this file can\u2019t be written in ES6 as it doesn\u2019t 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 \u2013 if we just gave it the string \u2018client-render.js\u2019, webpack wouldn\u2019t be able to find it.\nNext, we tell webpack where to output our file, and here I\u2019m 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.\nNow we\u2019re ready to generate the bundle!\n./node_modules/.bin/webpack\nThis will take a fair few seconds to run (on my machine it\u2019s 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\u2019ll see that we can now navigate around our application without hitting the server, because React on the client takes over. Perfect!\nThe 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\u2019re developing.\nConclusions\nFirst, if you\u2019d 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.\nNext, I want to stress that you shouldn\u2019t 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\u2019d be right. I used it as it\u2019s 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\u2019s a suitable infrastructure for you.\nWith that, all that\u2019s left for me to do is wish you a very merry Christmas and best of luck with your React applications!", "year": "2015", "author": "Jack Franklin", "author_slug": "jackfranklin", "published": "2015-12-05T00:00:00+00:00", "url": "https://24ways.org/2015/universal-react/", "topic": "code"} {"rowid": 53, "title": "Get Expressive with Your Typography", "contents": "In 1955 Beatrice Warde, an American communicator on typography, published a series of essays entitled The Crystal Goblet in which she wrote, \u201cPeople who love ideas must have a love of words. They will take a vivid interest in the clothes that words wear.\u201d And with that proposition Warde introduced the idea that just as we judge someone based on the clothes they are wearing, so we make judgements about text based on the typefaces in which it is set.\nBeatrice Warde. \u00a91970 Monotype Imaging Inc.\nChoosing the same typeface as everyone else, especially if you\u2019re trying to make a statement, is like turning up to a party in the same dress; to a meeting in the same suit, shirt and tie; or to a craft ale dispensary in the same plaid shirt and turned-up skinny jeans.\nBut there\u2019s more to your choice of typeface than simply making an impression. In 2012 Jon Tan wrote on 24 ways about a scientific study called \u201cThe Aesthetics of Reading\u201d which concluded that \u201cgood quality typography is responsible for greater engagement during reading and thus induces a good mood.\u201d\nFurthermore, at this year\u2019s Ampersand conference Sarah Hyndman, an expert in multisensory typography, discussed how typefaces can communicate with our subconscious. Sarah showed that different fonts could have an effect on how food tasted. A rounded font placed near a bowl of jellybeans would make them taste sweeter, and a jagged angular font would make them taste more sour. \nThe quality of your typography can therefore affect the mood of your reader, and your font choice directly affect the senses. This means you can manipulate the way people feel. You can change their emotional state through type alone. Now that\u2019s a real superpower!\nThe effects of your body text design choices are measurable but subtle. If you really want to have an impact you need to think big. Literally. Display text and headings are your attention grabbers. They are your chance to interrupt, introduce and seduce.\nDisplay text and headings set the scene and draw people in. Text set large creates an image that visitors see before they read, and that\u2019s your chance to choose a typeface that immediately expresses what the text, and indeed the entire website, stands for. What expectations of the text do you want to set up? Youthful enthusiasm? Businesslike? Cutting-edge? Hipster? Sensible and secure? Fun and informal? Authoritarian?\nTypography conveys much more than just information. It imparts feeling, emotion and sentiment, and arouses preconceived ideas of trust, tone and content. Think about taking advantage of this by introducing impactful, expressive typography to your designs on the web. You can alter the way your reader feels, so what emotion do you want to provoke?\nMaybe you want them to feel inspired like this stop smoking campaign:\nhelsenorge.no\nPerhaps they should be moved and intrigued, as with Makeshift magazine:\nmkshft.org\nOr calmly reassured:\nwww.cleopatra-marina.gr\nFonts also tap into the complex library of associations that we\u2019ve been accumulating in our brains all of our lives. You build up these associations every time you see a font from the context that you see it in. All of us associate certain letterforms with topics, times and places.\nRetiro is obviously Spanish:\nRetiro by Typofonderie\nBodoni and Eurostile used in this menu couldn\u2019t be much more Italian:\nBodoni and Eurostile, both designed in Italy\nTo me, Clarendon gives a sense of the 1960s and 1970s. I\u2019m not sure if that\u2019s what Costa was going for, but that\u2019s what it means to me:\nCosta coffee flier\nAnd Knockout and Gotham really couldn\u2019t be much more American:\nKnockout and Gotham by Hoefler & Co\nWhen it comes to choosing your display typeface, the type designer Christian Schwartz says there are two kinds. First are the workhorse typefaces that will do whatever you want them to do. Helvetica, Proxima Nova and Futura are good examples. These fonts can be shaped in many different ways, but this also means they are found everywhere and take great skill and practice to work with in a unique and striking manner.\nThe second kind of typeface is one that does most of the work for you. Like finely tailored clothing, it\u2019s the detail in the design that adds interest.\nSetting headings in Bree rather than Helvetica makes a big difference to the tone of the article\nSuch typefaces carry much more inherent character, but are also less malleable and harder to adapt to different contexts. Good examples are Marr Sans, FS Clerkenwell, Strangelove and Bree.\nPush the boat out\nRemember, all type can have an effect on the reader. Take advantage of that and allow your type to have its own vernacular and impact. Be expressive with your type. Don\u2019t be too reverential, dogmatic \u2013 or ordinary. Be brave and push a few boundaries.\nAdapted from Web Typography a book in progress by Richard Rutter.", "year": "2015", "author": "Richard Rutter", "author_slug": "richardrutter", "published": "2015-12-04T00:00:00+00:00", "url": "https://24ways.org/2015/get-expressive-with-your-typography/", "topic": "design"} {"rowid": 69, "title": "How to Do a UX Review", "contents": "A UX review is where an expert goes through a website looking for usability and experience problems and makes recommendations on how to fix them. \nI\u2019ve completed a number of UX reviews over my twelve years working as a user experience consultant and I thought I\u2019d share my approach. \nI\u2019ll be talking about reviewing websites here; you can adapt the approach for web apps, or mobile or desktop apps. \nWhy conduct a review\nTypically, a client asks for a review to be undertaken by a trusted and, ideally, detached third party who either works for an agency or is a freelancer. Often they may ask a new member of the UX team to complete one, or even set it as a task for a job interview. This indicates the client is looking for an objective view, seen from the outside as a user would see the website. \nI always suggest conducting some user research rather than a review. Users know their goals and watching them make (what you might think of as) mistakes on the website is invaluable. Conducting research with six users can give you six hours\u2019 worth of review material from six viewpoints. In short, user research can identify more problems and show how common those problems might be. \nThere are three reasons, though, why a review might better suit client needs than user research: \n\nQuick results: user research and analysis takes at least three weeks.\nLimited budget: the \u00a36\u201310,000 cost to run user research is about twice the cost of a UX review. \nUsers are hard to reach: in the business-to-business world, reaching users is difficult, especially if your users hold senior positions in their organisations. Working with consumers is much easier as there are often more of them. \n\nThere is some debate about the benefits of user research over UX review. In my experience you learn far more from research, but opinions differ. \nBe objective\nThe number one mistake many UX reviewers make is reporting back the issues they identify as their opinion. This can cause credibility problems because you have to keep justifying why your opinion is correct. \nI\u2019ve had the most success when giving bad news in a UX review and then finally getting things fixed when I have been as objective as possible, offering evidence for why something may be a problem. \nTo be objective we need two sources of data: numbers from analytics to appeal to reason; and stories from users in the form of personas to speak to emotions. Highlighting issues with dispassionate numerical data helps show the extent of the problem. Making the problems more human using personas can make the problem feel more real. \nNumbers from analytics\nThe majority of clients I work with use Google Analytics, but if you use a different analytics package the same concepts apply. I use analytics to find two sets of things.\n1. Landing pages and search terms\nLanding pages are the pages users see first when they visit a website \u2013 more often than not via a Google search. Landing pages reveal user goals. If a user landed on a page called \u2018Yellow shoes\u2019 their goal may well be to find out about or buy some yellow shoes. \nIt would be great to see all the search terms bringing people to the website but in 2011 Google stopped providing search term data to (rightly!) protect users\u2019 privacy. You can get some search term data from Google Webmaster tools, but we must rely on landing pages as a clue to our users\u2019 goals. \nThe thing to look for is high-traffic landing pages with a high bounce rate. Bounce rate is the percentage of visitors to a website who navigate away from the site after viewing only one page. A high bounce rate (over 50%) isn\u2019t good; above 70% is bad.\nTo get a list of high-traffic landing pages with a high bounce rate install this bespoke report.\nGoogle Analytics showing landing pages ordered by popularity and the bounce rate for each.\nThis is the list of pages with high demand and that have real problems as the bounce rate is high. This is the main focus of the UX review. \n2. User flows\nWe have the beginnings of the user journey: search terms and initial landing pages. Now we can tap into the really useful bit of Google Analytics. Called behaviour flows, they show the most common order of pages visited. \nBehaviour flows from Google Analytics, showing the routes users took through the website.\nHere we can see the second and third (and so on) pages users visited. Importantly, we can also see the drop-outs at each step. \nIf your client has it set up, you can also set goal pages (for example, a post-checkout contact us and thank you page). You can then see a similar view that tracks back from the goal pages. If your client doesn\u2019t have this, suggest they set up goal tracking. It\u2019s easy to do. \nWe now have the remainder of the user journey. \nA user journey\nExpect the work in analytics to take up to a day. \nWe may well identify more than one user journey, starting from different landing pages and going to different second- and third-level pages. That\u2019s a good thing and shows we have different user types. Talking of user types, we need to define who our users are. \nPersonas\nWe have some user journeys and now we need to understand more about our users\u2019 motivations and goals. \nI have a love-hate relationship with personas, but used properly these portraits of users can help bring a human touch to our UX review. \nI suggest using a very cut-down view of a persona. My old friends Steve Cable and Richard Caddick at cxpartners have a great free template for personas from their book Communicating the User Experience.\nThe first thing to do is find a picture that represents that persona. Don\u2019t use crappy stock photography \u2013 it\u2019s sometimes hard to relate to perfect-looking people) \u2013 use authentic-looking people. Here\u2019s a good collection of persona photos. \nAn example persona.\nThe personas have three basic attributes:\n\nGoals: we can complete these drawing on the analytics data we have (see example).\nMusts: things we have to do to meet the persona\u2019s needs.\nMust nots: a list of things we really shouldn\u2019t do. \n\nCompleting points 2 and 3 can often be done during the writing of the report. \nLet\u2019s take an example. We know that the search term \u2018yellow shoes\u2019 takes the user to the landing page for yellow shoes. We also know this page has a high bounce rate, meaning it doesn\u2019t provide a good experience. \nWith our expert hat on we can review the page. We will find two types of problem: \n\nUsability issues: ineffective button placement or incorrect wording, links not looking like links, and so on. \nExperience issues: for example, if a product is out of stock we have to contact the business to ask them to restock. \n\nThat link is very small and hard to see.\nWe could identify that the contact button isn\u2019t easy to find (a usability issue) but that\u2019s not the real problem here. That the user has to ask the business to restock the item is a bad user experience. We add this to our personas\u2019 must nots. The big experience problems with the site form the musts and must nots for our personas. \nWe now have a story around our user journey that highlights what is going wrong. \nIf we\u2019ve identified a number of user journeys, multiple landing pages and differing second and third pages visited, we can create more personas to match. A good rule of thumb is no more than three personas. Any more and they lose impact, watering down your results. \nExpect persona creation to take up to a day to complete. \nLet\u2019s start the review\nWe take the user journeys and we follow them step by step, working through the website looking for the reasons why users drop out at each step. Using Keynote or PowerPoint, I structure the final report around the user journey with separate sections for each step.\nFor each step we\u2019ll find both usability and experience problems. Split the results into those two groups. \nUsability problems are fairly easy to fix as they\u2019re often quick design changes. As you go along, note the usability problems in one place: we\u2019ll call this \u2018quick wins\u2019. Simple quick fixes are a reassuring thing for a client to see and mean they can get started on stuff right away. You can mark the severity of usability issues. Use a scale from 1 to 3 (if you use 1 to 5 everything ends up being a 3!) where 1 is minor and 3 is serious. \nReview the website on the device you\u2019d expect your persona to use. Are they using the site on a smartphone? Review it on a smartphone. \nI allow one page or slide per problem, which allows me to explain what is going wrong. For a usability problem I\u2019ll often make a quick wireframe or sketch to explain how to address it. \nA UX review slide displaying all the elements to be addressed. These slides may be viewed from across the room on a screen so zoom into areas of discussion.\n(Quick tip: if you use Google Chrome, try Awesome Screenshot to capture screens.)\nWhen it comes to the more severe experience problems \u2013 things like an online shop not offering next day delivery, or a business that needs to promise to get back to new customers within a few hours \u2013 these will take more than a tweak to the UI to fix. \nCall these something different. I use the terms like business challenges and customer experience issues as they show that it will take changes to the organisation and its processes to address them. It\u2019s often beyond the remit of a humble UX consultant to recommend how to fix organisational issues, so don\u2019t try. \nAgain, create a page within your document to collect all of the business challenges together. \nExpect the review to take between one and three days to complete. \nThe final report should follow this structure:\n\nThe approach\nOverview of usability quick wins\nOverview of experience issues\nOverview of Google Analytics findings\nThe user journeys \nThe personas\nDetailed page-by-page review (broken down by steps on the user journey)\n\nThere are two academic theories to help with the review. \nHeuristic evaluation is a set of criteria to organise the issues you find. They\u2019re great for categorising the usability issues you identify but in practice they can be quite cumbersome to apply. \nI prefer the more scientific and much simpler cognitive walkthrough that is focused on goals and actions.\nA workshop to go through the findings\nThe most important part of the UX review process is to talk through the issues with your client and their team. \nA document can only communicate a certain amount. Conversations about the findings will help the team understand the severity of the issues you\u2019ve uncovered and give them a chance to discuss what to do about them. \nExpect the workshop to last around three hours.\nWhen presenting the report, explain the method you used to conduct the review, the data sources, personas and the reasoning behind the issues you found. Start by going through the usability issues. Often these won\u2019t be contentious and you can build trust and improve your credibility by making simple, easy to implement changes. \nThe most valuable part of the workshop is conversation around each issue, especially the experience problems. The workshop should include time to talk through each experience issue and how the team will address it. \nI collect actions on index cards throughout the workshop and make a note of who will take what action with each problem. \nIndex cards showing the problem and who is responsible.\nWhen talking through the issues, the person who designed the site is probably in the room \u2013 they may well feel threatened. So be nice.\nWhen I talk through the report I try to have strong ideas, weakly held.\nAt the end of the workshop you\u2019ll have talked through each of the issues and identified who is responsible for addressing them. To close the workshop I hand out the cards to the relevant people, giving them a physical reminder of the next steps they have to take. \nThat\u2019s my process for conducting a review. I\u2019d love to hear any tips you have in the comments.", "year": "2015", "author": "Joe Leech", "author_slug": "joeleech", "published": "2015-12-03T00:00:00+00:00", "url": "https://24ways.org/2015/how-to-do-a-ux-review/", "topic": "ux"} {"rowid": 62, "title": "Being Customer Supportive", "contents": "Every day in customer support is an inbox, a Twitter feed, or a software forum full of new questions. Each is brimming with your customers looking for advice, reassurance, or fixes for their software problems. Each one is an opportunity to take a break from wrestling with your own troublesome tasks and assist someone else in solving theirs.\nSometimes the questions are straightforward and can be answered in a few minutes with a short greeting, a link to a help page, or a prewritten bit of text you use regularly: how to print a receipt, reset a password, or even, sadly, close your account.\nMore often, a support email requires you to spend some time unpacking the question, asking for more information, and writing a detailed personal response, tailored to help that particular user on this particular day.\nHere I offer a few of my own guidelines on how to make today\u2019s email the best support experience for both me and my customer. And even if you don\u2019t consider what you do to be customer support, you might still find the suggestions useful for the next time you need to communicate with a client, to solve a software problem with teammates, or even reach out and ask for help yourself.\n(All the examples appearing in this article are fictional. Any resemblance to quotes from real, software-using persons is entirely coincidental. Except for the bit about Star Wars. That happened.)\nWho\u2019s TAHT girl\nI\u2019ll be honest: I briefly tried making these recommendations into a clever mnemonic like FAST (facial drooping, arm weakness, speech difficulties, time) or PAD (pressure, antiseptic, dressing). But instead, you get TAHT: tone, ask, help, thank. Ah, well.\nAs I work through each message in my support queue, I\n\nlisten to the tone of the email\nask clarifying questions\nbring in extra help as needed\nand thank the customer when the problem is solved.\n\nLet\u2019s open an email and get started!\nLeave your message at the sound of the tone\nWith our enthusiasm for emoji, it can be very hard to infer someone\u2019s tone from plain text. How much time have you spent pondering why your friend responded with \u201cThanks.\u201d instead of \u201cThanks!\u201d? I mean, why didn\u2019t she :grin: or :wink: too?\nOur support customers, however, are often direct about how they\u2019re feeling:\n\nI\u2019m working against a deadline. Need this fixed ASAP!!!!\nThis hasn\u2019t worked in a week and I am getting really frustrated.\nI\u2019ve done this ten times before and it\u2019s always worked. I must be missing something simple.\n\nThey want us to understand the urgency of this from their point of view, just as much as we want to help them in a timely manner. How this information is conveyed gives us an instant sense of whether they are frustrated, angry, or confused\u2014and, just as importantly, how frustrated-angry-confused they are. \nListen to this tone before you start writing your reply. Here are two ways I might open an email:\n\n\u201cI\u2019m sorry that you ran into trouble with this.\u201d\n\u201cSorry you ran into trouble with this!\u201d\n\nThe content is largely the same, but the tone is markedly different. The first version is a serious, staid reaction to the problem the customer is having; the second version is more relaxed, but no less sincere.\nMatching the tone to the sender\u2019s is an important first step. Overusing exclamation points or dropping in too-casual language may further upset someone who is already having a crummy time with your product. But to a cheerful user, a formal reply or an impersonal form response can be off-putting, and damage a good relationship.\nWhen in doubt, I err on the side of being too formal, rather than sending a reply that may be read as flip or insincere. But whichever you choose, matching your correspondent\u2019s tone will make for a more comfortable conversation.\nCatch the ball and throw it back\nOnce you\u2019ve got that tone on lock, it\u2019s time to tackle the question at hand. Let\u2019s see what our customer needs help with today:\n\nI tried everything in the troubleshooting page but I can\u2019t get it to work again. I am on a Mac. Please help.\n\nHmm, not much information here. Now, if I got this short email after helping five other people with the same problem on Mac OS X, I would be sorely tempted to send this customer that common solution in my first reply. I\u2019ve found it\u2019s important to resist the urge to assume this sixth person needs the same answer as the other five, though: there isn\u2019t enough to connect this email to the ones that came before hers. \nInstead, ask a few questions to start. Invest some time to see if there are other symptoms in common, like so:\n\nI\u2019m sorry that you ran into trouble with this! I\u2019ll need a little more information to see what\u2019s happening here.\n[questions]\nThank you for your help.\n\nThose questions are customized for the customer\u2019s issue as much as possible, and can be fairly wide-ranging. They may include asking for log files, getting some screenshots, or simply checking the browser and operating system version she\u2019s using. I\u2019ll ask anything that might make a connection to the previous cases I\u2019ve answered\u2014or, just as importantly, confirm that there isn\u2019t a connection. What\u2019s more, a few well-placed questions may save us both from pursuing the wrong path and building additional frustration. \n(A note on that closing: \u201cThank you for your help\u201d\u2013I often end an email this way when I\u2019ve asked for a significant amount of follow up information. After all, I\u2019m imposing on my customer\u2019s time to run any number of tests. It\u2019s a necessary step, but I feel that thanking them is a nice acknowledgment we\u2019re in this together.)\nHaving said that, though, let\u2019s bring tone back into the mix:\n\nI tried everything in the troubleshooting but I can\u2019t get it to work again. I am on a Mac. I\u2019m working against a deadline. Need this fixed ASAP!!!!\n\nThis customer wants answers now. I\u2019ll still ask for more details, but would consider including the solution to the previous problem in my initial reply as well. (But only if doing so can\u2019t make the situation worse!)\n\nI\u2019m sorry that you ran into trouble with this! I\u2019ll need a little more information to see what\u2019s happening here.\n[questions]\nIf you\u2019d like to try something in the meantime, delete the file named xyz.txt. (If this isn\u2019t the cause of the problem, deleting the file won\u2019t hurt anything.) Here\u2019s how to find that file on your computer:\n[steps]\nLet me know how it goes!\n\nIn the best case, the suggestion works and the customer is on her way. If it doesn\u2019t solve the problem, you will get more information in answer to your questions and can explore other options. And you\u2019ve given the customer an opportunity to be involved in fixing the issue, and some new tools which might come in handy again in the future.\nBring in help\nThe support software I use counts how many emails the customer and I have exchanged, and reports it in a summary line in my inbox. It\u2019s an easy, passive reminder of how long the customer and I have been working together on a problem, especially first thing in the morning when I\u2019m reacquainting myself with my open support cases.\nThree is the smallest number I\u2019ll see there: the customer sends the initial question (1 email); I reply with an answer (2 emails); the customer confirms the problem is solved (3 emails). But the most complicated, stickiest tickets climb into double-digit replies, and anything that stretches beyond a dozen is worthy of a cheer in Slack when we finally get to the root of the problem and get it fixed.\nWhile an extra round of questions and answers will nudge that number higher, it gives me the chance to feel out the technical comfort level of the person I\u2019m helping. If I ask the customer to send some screenshots or log files and he isn\u2019t sure how to do that, I will use that information to adjust my instructions on next steps. I may still ask him to try running a traceroute on his computer, but I\u2019ll break down the steps into a concise, numbered list, and attach screenshots of each step to illustrate it.\nIf the issue at hand is getting complicated, take note if the customer starts to feel out of their depth technically\u2014either because they tell you so directly or because you sense a shift in tone. If that happens, propose bringing some outside help into the conversation:\n\nDo you have a network firewall or do you use any antivirus software? One of those might be blocking a connection that the software needs to work properly; here\u2019s a list of the required connections [link]. If you have an IT department in-house, they should be able to help confirm that none of those are being blocked.\n\nor:\n\nThis error message means you don\u2019t have permission to install the software on your own computer. Is there a systems administrator in the office that may be able to help with this? \n\nFor email-based support cases, I\u2019ll even offer to add someone from their IT department to the thread, so we can discuss the problem together rather than have the customer relay questions and answers back and forth.\nSimilarly, there are occasionally times when my way of describing things doesn\u2019t fit how the customer understands them. Rather than bang our heads against our keyboards, I will ask one of my support colleagues to join the conversation from our side, and see if he can explain things more clearly than I\u2019ve been able to do.\nWe appreciate your business. Please call again\nAnd then, o frabjous day, you get your reward: the reply which says the problem has been solved. \n\nThat worked!! Thank you so much for saving my day!\nI wish I could send you some cookies!\nIf you were here, I would give you my tickets to Star Wars.\n[Reply is an animated gif.]\n\nSometimes the reply is a bit more understated:\n\nThat fixed it. Thanks.\n\nWhether the customer is elated, satisfied, or frankly happy to be done with emailing support, I like to close longer email threads or short, complicated issues with a final thanks and reminder that we\u2019re here to help: \n\nThank you for the update; I\u2019m glad to hear that solved the problem for you! I hope everything goes smoothly for you now, but feel free to email us again if you run into any other questions or problems. Best,\n\nThen mark that support case closed, and move on to the next question. Because even with the most thoughtfully designed software product, there will always be customers with questions for your capable support team to answer.\nTone, ask, help, thank\nSo there you have it: TAHT. Pay attention to tone; ask questions; bring in help; thank your customer.\n(Lack of) catchy mnemonics aside, good customer support is about listening, paying attention, and taking care in your replies. I think it can be summed up beautifully by this quote from Pamela Marie (as tweeted by Chris Coyier):\n\nGolden rule asking a question: imagine trying to answer it \nGolden rule in answering: imagine getting your answer \n\nYou and your teammates are applying a variation of this golden rule in every email you write. You\u2019re the software ambassadors to your customers and clients. You get the brunt of the problems and complaints, but you also get to help fix them. You write the apologies, but you also have the chance to make each person\u2019s experience with your company or product a little bit better for next time.\nI hope that your holidays are merry and bright, and may all your support inboxes be light.", "year": "2015", "author": "Elizabeth Galle", "author_slug": "elizabethgalle", "published": "2015-12-02T00:00:00+00:00", "url": "https://24ways.org/2015/being-customer-supportive/", "topic": "process"} {"rowid": 59, "title": "Animating Your Brand", "contents": "Let\u2019s talk about how we add animation to our designs, in a way that\u2019s consistent with other aspects of our brand, such as fonts, colours, layouts and everything else.\nAnimating is fun. Adding animation to our designs can bring them to life and make our designs stand out. Animations can show how the pieces of our designs fit together. They provide context and help people use our products.\nAll too often animation is something we tack on at the end. We put a transition on a modal window or sliding menu and we often don\u2019t think about whether that animation is consistent with our overall design.\nStyle guides to the rescue\nA style guide is a document that establishes and enforces style to improve communication. It can cover anything from typography and writing style to ethics and other, broader goals. It might be a static visual document showing every kind of UI, like in the Codecademy.com redesign shown below.\nUI toolkit from \u201cReimagining Codecademy.com\u201d by @mslima\nIt might be a technical reference with code examples. CodePen\u2019s new design patterns and style guide is a great example of this, showing all the components used throughout the website as live code.\nCodePen\u2019s design patterns and style guide\nA style guide gives a wide view of your project, it maintains consistency when adding new content, and we can use our style guide to present animations.\nLiving documents\nStyle guides don\u2019t need to be static. We can use them to show movement. We can share CSS keyframe animations or transitions that can then go into production. We can also explain why animation is there in the first place.\nJust as a style guide might explain why we chose a certain font or layout, we can use style guides to explain the intent behind animation. This means that if someone else wants to create a new component, they will know why animation applies.\nIf you haven\u2019t yet set up a style guide, you might want to take a look at Pattern Lab. It\u2019s a great tool for setting up your own style guide and includes loads of design patterns to get started.\nThere are many style guide articles linked from the excellent, open sourced, Website Style Guide Resources. Anna Debenham also has an excellent pocket book on the subject.\nAdding animation\nBefore you begin throwing animation at all the things, establish the character you want to convey.\nAndrex Puppy (British TV ad from 1994)\nList some words that describe the character you\u2019re aiming for. If it was the Andrex brand, they might have gone for: fun, playful, soft, comforting.\nPerhaps you\u2019re aiming for something more serious, credible and authoritative. Or maybe exciting and intense, or relaxing and meditative. For each scenario, the animations that best represent these words will be different.\nIn the example below, two animations both take the same length of time, but use different timing functions. One eases, and the other bounces around. Either might be good, depending on your needs.\nTiming functions (CodePen)\nExample: Kitman Labs\nWorking with Kitman Labs, we spent a little time working out what words best reflected the brand and came up with the following:\n\nScientific\nPrecise\nFast\nSolid\nDependable\nHelpful\nConsistent\nClear\n\nWith such a list of words in hand, we design animation that fits. We might prefer a tween that moves quickly to its destination over one that drifts slowly or bounces.\nWe can use the list when justifying our use of animation, such as when it helps our customers understand the context of data on the page. Or we may even choose not to animate, when that might make the message inconsistent.\nCreate guidelines\nIf you already have a style guide, adding animation could begin with creating an overview section.\nOne approach is to create a local website and share it within your organisation. We recently set up a local site for this purpose. \nA recent project\u2019s introduction to the topic of animation\nThis document becomes a reference when adding animation to components. Include links to related resources or examples of animation to help demonstrate the animation style you want.\nPrototyping\nYou can explain the intent of your animation style guide with live animations. This doesn\u2019t just mean waving our hands around. We can show animation through prototypes.\nThere are so many prototype tools right now. You could use Invision, Principle, Floid, or even HTML and CSS as embedded CodePens.\nA login flow prototype created in Principle\nThese tools help when trying out ideas and working through several approaches. Create videos, animated GIFs or online demos to share with others. Experiment. Find what works for you and work with whatever lets you get the most ideas out of your head fastest. Iterate and refine an animation before it gets anywhere near production.\nBuild up a collection\nBuild up your guide, one animation at a time.\nSome people prefer to loosely structure a guide with places to put things as they are discovered or invented; others might build it one page at a time \u2013 it doesn\u2019t matter. The main thing is that you collect animations like you would trading cards. Or Pokemon. Keep them ready to play and deliver that explosive result.\nYou could include animated GIFs, or link to videos or even live webpages as examples of animation. The use of animation to help user experience is also covered nicely in Val Head\u2019s UI animation and UX article on A List Apart.\nWhat matters is that you create an organised place for them to be found. Here are some ideas to get started.\nLogos and brandmarks\nMany sites include some subtle form of animation in their logos. This can draw the eye, add some character, or bring a little liveliness to an otherwise static page. Yahoo and Google have been experimenting with animation on their logos. Even a simple bouncing animation, such as the logo on Hop.ie, can add character.\nThe CSS-animated bouncer from Hop.ie\nContent transitions\nAdding content, removing content, showing and hiding messages are all opportunities to use animation. Careful and deliberate use of animation helps convey what\u2019s changing on screen.\nAnimating list items with CSS (CSSAnimation.rocks)\nFor more detail on this, I also recommend \u201cTransitional Interfaces\u201d by Pasquale D\u2019Silva.\nPage transitions\nOn a larger scale than the changes to content, full-page transitions can smooth the flow between sections of a site. Medium\u2019s article transitions are a good example of this.\nMedium-style page transition (Tympanus.net)\nPreparing a layout before the content arrives\nWe can use animation to draw a page before the content is ready, such as when a page calls a server for data before showing it.\nOptimistic loading grid (CodePen)\nSometimes it\u2019s good to show something to let the user know that everything\u2019s going well. A short animation could cover just enough time to load the initial content and make the loading transition feel seamless.\nInteractions\nHover effects, dropdown menus, slide-in menus and active states on buttons and forms are all opportunities. Look for ways you can remove the sudden changes and help make the experience of using your UI feel smoother.\nForm placeholder animation (Studio MDS)\nKeep animation visible\nIt takes continuous effort to maintain a style guide and keep it up to date, but it\u2019s worth it. Make it easy to include animation and related design decisions in your documentation and you\u2019ll be more likely to do so. If you can make it fun, and be proud of the result, better still.\nWhen updating your style guide, be sure to show the animations at the same time. This might mean animated GIFs, videos or live embedded examples of your components.\nBy doing this you can make animation integral to your design process and make sure it stays relevant.\nInspiration and resources\nThere are loads of great resources online to help you get started. One of my favourites is IBM\u2019s design language site.\nIBM\u2019s design language:\u200aanimation design guidelines\nIBM describes how animation principles apply to its UI work and components. They break down the animations into five categories of animations and explain how they apply to each example.\nThe site also includes an animation library with example videos of animations and links to source code.\nExample component from IBM\u2019s component library\nThe way IBM sets out its aims and methods is helpful not only for their existing designers and developers, but also helps new hires. Furthermore, it\u2019s a good way to show the world that IBM cares about these details.\nAnother popular animation resource is Google\u2019s material design.\nGoogle\u2019s material design documentation\nGoogle\u2019s guidelines cover everything from understanding easing through to creating engaging and useful mobile UI.\nThis approach is visible across many of Google\u2019s apps and software, and has influenced design across much of the web. The site is helpful both for learning about animation and as an showcase of how to illustrate examples.\nFrameworks\nIf you don\u2019t want to create everything from scratch, there are resources you can use to start using animation in your UI. One such resource is Salesforce\u2019s Lightning design system.\nThe system goes further than most guides. It includes a downloadable framework for adding animation to your projects. It has some interesting concepts, such as elevation settings to handle positioning on the z-axis.\nExample of elevation from Salesforce\u2019s Lightning design system\nYou should also check out Animate.css.\n\u201cJust add water\u201d\u200a\u2014\u200aAnimate.css\nAnimate.css gives you a set of predesigned animations you can apply to page elements using classes. If you use JavaScript to add or remove classes, you can then trigger complex animations. It also plays well with scroll-triggering, and tools such as WOW.js.\nLearn, evolve and make it your own\nThere\u2019s a wealth online of information and guides we can use to better understand animation. They can inspire and kick-start our own visual and animation styles. So let\u2019s think of the design of animations just as we do fonts, colours and layouts. Let\u2019s choose animation deliberately, making it part of our style guides.\nMany thanks to Val Head for taking the time to proofread and offer great suggestions for this article.", "year": "2015", "author": "Donovan Hutchinson", "author_slug": "donovanhutchinson", "published": "2015-12-01T00:00:00+00:00", "url": "https://24ways.org/2015/animating-your-brand/", "topic": "design"} {"rowid": 32, "title": "Cohesive UX", "contents": "With Yosemite, Apple users can answer iPhone calls on their MacBooks. This is weird. And yet it\u2019s representative of a greater trend toward cohesion.\n\nShortly after upgrading to Yosemite, a call came in on my iPhone and my MacBook \u201crang\u201d in parallel. And I was all, like, \u201cWut?\u201d This was a new feature in Yosemite, and honestly it was a little bizarre at first.\n\n Apple promotional image showing a phone call ringing simultaneously on multiple devices.\n\nHowever, I had just spoken at a conference on the very topic you\u2019re reading about now, and therefore I appreciated the underlying concept: the cohesion of user experience, the cohesion of screens.\n\nThis is just one of many examples I\u2019ve encountered since beginning to speak about this topic months ago. But before we get ahead of ourselves, let\u2019s look back at the past few years, specifically the role of responsive web design.\n\nRWD != cohesive experience\n\nI needn\u2019t expound on the virtues of responsive web design (RWD). You\u2019ve likely already encountered more than a career\u2019s worth on the topic. This is a good thing. Count me in as one of its biggest fans.\n\nHowever, if we are to sing the praises of RWD, we must also acknowledge its shortcomings. One of these is that RWD ends where the browser ends. For all its goodness, RWD really has no bearing on native apps or any other experiences that take place outside the browser. This makes it challenging, therefore, to create cohesion for multi-screen users if RWD is the only response to \u201clet\u2019s make it work everywhere.\u201d\n\nWe need something that incorporates the spirit of RWD while unifying all touchpoints for the entire user experience\u2014single device or several devices, in browser or sans browser, native app or otherwise.\n\nI call this cohesive UX, and I believe it\u2019s the next era of successful user experiences.\n\nToward a unified whole\n\nSimply put, the goal of cohesive UX is to deliver a consistent, unified user experience regardless of where the experience begins, continues, and ends.\n\nTwo facets are vital to cohesive UX:\n\n\n\tFunction and form\n\tData symmetry\n\n\nLet\u2019s examine each of these.\n\nFunction AND form\n\nFunction over form, of course. Right? Not so fast, kiddo.\n\nConsider Bruce Lawson\u2019s dad. After receiving an Android phone for Christmas and thumbing through his favorite sites, he was puzzled why some looked different from their counterparts on the desktop. \u201cWhen a site looked radically different,\u201d Bruce observed, \u201che\u2019d check the URL bar to ensure that he\u2019d typed in the right address. In short, he found RWD to be confusing and it meant he didn\u2019t trust the site.\u201d A lack of cohesive form led to a jarring experience for Bruce\u2019s dad.\n\nNow, if I appear to be suggesting websites must look the same in every browser\u2014you already learned they needn\u2019t\u2014know that I recognize the importance of context, especially in regards to mobile. I made a case for this more than seven years ago.\n\nRather, cohesive UX suggests that form deserves the same respect as function when crafting user experiences that span multiple screens or devices. And users are increasingly comfortable traversing media. For example, more than 40% of adults in the U.S. owning more than one device start an activity on one screen and finish it on another, according to a study commissioned by Facebook. I suspect that percentage will only increase in 2015, and I suspect the tech-affluent readers of 24 ways are among the 40%.\n\nThere are countless examples of cohesive form and function. Consider Gmail, which displays email conversations visually as a stack that can be expanded and collapsed like the bellows of an accordion. This visual metaphor has been consistent in virtually any instance of Gmail\u2014website or app\u2014since at least 2007 when I captured this screenshot on my Nokia 6680:\n\n Screenshot captured while authoring Mobile Web Design (2007). Back then we didn\u2019t call this an app, but rather a \u2018smart client\u2019.\n\nWhen the holistic experience is cohesive as it is with Gmail, users\u2019 mental models and even muscle memory are preserved.1 Functionality and aesthetics align with the expectations users have for how things should function and what they should look like. In other words, the experience is roughly the same across screens.\n\nBut don\u2019t be ridiculous, peoples. Note that I said \u201croughly.\u201d It\u2019s important to avoid mindless replication of aesthetics and functionality for the sake of cohesion. Again, the goal is a unified whole, not a carbon copy. Affordances and concessions should be made as context and intuition require. For example, while Facebook users are accustomed to top-aligned navigation in the browser, they encounter bottom-aligned navigation in the iOS app as justified by user testing:\n\nThe iOS app model has held up despite many attempts to better it: http://t.co/rSMSAqeh9m pic.twitter.com/mBp36lAEgc\u2014 Luke Wroblewski (@lukew) December 10, 2014\n\n\nDespite the (rather minor) lack of consistency in navigation placement, other elements such as icons, labels, and color theme work in tandem to produce a unified, holistic whole.\n\nData symmetry\n\nData symmetry involves the repetition, continuity, or synchronicity of data across screens, devices, and platforms. As regards cohesive UX, data includes not just the material (such as an article you\u2019re writing on Medium) but also the actions that can be performed on or with that material (such as Medium\u2019s authoring tools). That is to say, \u201csync verbs, not just nouns\u201d (Josh Clark).\n\nIn my estimation, Amazon is an archetype of data symmetry, as is Rdio. When logged in, data is shared across virtually any device of any kind, irrespective of using a browser or native app. Add a product to your Amazon cart from your phone during the morning commute, and finish the transaction at work on your laptop. Easy peasy.\n\nAmazon\u2019s aesthetics are crazy cohesive, to boot:\n\n Amazon web (left) and native app (right).\n\nWith Rdio, not only are playlists and listening history synced across screens as you would expect, but the cohesion goes even further. Rdio\u2019s remote control feature allows you to control music playing on one device using another device, all in real time.\n\n Rdio\u2019s remote control feature, as viewed on my MacBook while music plays on my iMac.\n\nAt my office I often work from my couch using my MacBook, but my speakers are connected to my iMac. When signed in to Rdio on both devices, my MacBook serves as proxy for controlling Rdio on my iMac, much the same as any Yosemite-enabled device can serve as proxy for an incoming iPhone call.\n\n Me, in my office. Note the iMac and speakers at far right.\n\nThis is a brilliant example of cohesive design, and it\u2019s executed entirely via the cloud.\n\nThings to consider\n\nConsider the following when crafting cohesive experiences:\n\n\n\tInventory the elements that comprise your product experience, and cohesify them.2\nConsider things such as copy, tone, typography, iconography, imagery, flow, placement, brand identification, account data, session data, user preferences, and so on. Then, create cohesion among these elements to the greatest extent possible, while adapting to context as needed.\n\tStore session data in the cloud rather than locally.\nFor example, avoid using browser cookies to store shopping cart data, as cookies are specific to a single browser on a single device. Instead, store this data in the cloud so it can be accessed from other devices, as well as beyond the browser.\n\tConsider using web views when developing your native app.\n\u201cYou\u2019re already using web apps in native wrappers without even noticing it,\u201d Lukas Mathis contends. \u201cThe fact that nobody even notices, the fact that this isn\u2019t a story, shows that, when it comes to user experience, web vs. native doesn\u2019t matter anymore.\u201d Web views essentially allow you to display HTML content inside a native wrapper. This can reduce the time and effort needed to make the overall experience cohesive. So whereas the navigation bar may be rendered by the app, for example, the remaining page display may be rendered via the web. There\u2019s readily accessible documentation for using web views in C++, iOS, Android, and so forth.\n\n\nNature is calling\n\nReturning to the example of Yosemite and sychronized phone calls, is it really that bizarre in light of cohesive UX? Perhaps at first. But I suspect that, over time, Yosemite\u2019s cohesiveness \u2014 and the cohesiveness of other examples like the ones we\u2019ve discussed here \u2014 will become not only more natural but more commonplace, too.\n\n\n\n1 I browse Flipboard on my iPad nearly every morning as part of my breakfast routine. Swiping horizontally advances to the next page. Countless times I\u2019ve done the same gesture in Flipboard for iPhone only to have it do nothing. This is because the gesture for advancing is vertical on phones. I\u2019m so conditioned to the horizontal swipe that I often fail to make the switch to vertical swipe, and apparently others suffer from the same muscle memory, too.\n\n2 Cohesify isn\u2019t a thing. But chances are you understood what I meant. Yay neologism!", "year": "2014", "author": "Cameron Moll", "author_slug": "cameronmoll", "published": "2014-12-24T00:00:00+00:00", "url": "https://24ways.org/2014/cohesive-ux/", "topic": "ux"} {"rowid": 44, "title": "Taglines and Truisms", "contents": "To bring her good luck, \u201cwhite rabbits\u201d was the first thing that my grandmother said out loud on the first day of every month. We all need a little luck, but we shouldn\u2019t rely on it, especially when it comes to attracting new clients.\n\nThe first thing we say to a prospective client when they visit our website for the first time helps them to understand not only what we do but why we do it. We can also help them understand why they should choose to work with us over one of our competitors.\n\nTake a minute or two to look at your competitors\u2019 websites. What\u2019s the first thing that they say about themselves? Do they say that they \u201cdesign delightful digital experiences,\u201d \u201ccraft beautiful experiences\u201d or \u201ccreate remarkable digital experiences?\u201d\n\nIt\u2019s easy to find companies who introduce themselves with what they do, their proposition, but what a company does is only part of their story. Their beliefs and values, what they stand for why they do what they do are also important. \n\nWhen someone visits our websites for the first time, we have only a brief moment to help them understand us. To help us we can learn from the advertising industry, where the job of a tagline is to communicate a concept, deliver a message and sell a product, often using only a few words.\n\nWhen an advertising campaign is effective, its tagline stays with you, sometimes long after that campaign is over. For example, can you remember which company or brand these taglines help to sell? (Answers at the bottom of the article:)\n\n\nThe Ultimate Driving Machine\nJust Do It\nDon\u2019t Leave Home Without It\n\n\nA clever tagline isn\u2019t just a play on words, although it can include one. A tagline does far more than help make your company memorable. Used well, it brings together notions of what makes your company and what you offer special. Then it expresses those notions in a few words or possibly a short sentence. \n\nI\u2019m sure that everyone can find examples of company slogans written in the type of language that should stay within the walls of a marketing department. We can also find taglines where the meaning is buried so deep that the tag itself becomes effectively meaningless.\n\nA meaningful tagline supports our ideas about who we are and what we offer, and provides a platform for different executions of them, sometimes over a period of time. For a tagline to work well, it must allow for current and future ideas about a brand.\n\nIt must also be meaningful to our brand and describe a truism, a truth that need not be a fact or statistic, but something that\u2019s true about us, who we are, what we do and why that\u2019s distinctive. It can be obvious, funny, serious or specific but above all it must be true. It should also be difficult to argue with, making your messages difficult to argue with too.\n\nI doubt that I need remind you who this tagline belongs to:\n\n\n\tThere are some things money can\u2019t buy. For everything else there\u2019s MasterCard.\n\n\nThat tagline was launched in 1997 by McCann-Erickson along with the \u201cPriceless\u201d campaign and it helped establish MasterCard as a friendlier credit card company, one with a sense of humour. \n\nMasterCard\u2019s truism is that the things which really matter in life can\u2019t be bought. They are worth more than anything that a monetary value can be applied to. In expressing that truism through the tagline, MasterCard\u2019s advertising tells people to use not just any credit card, but their MasterCard, to pay for everything they buy.\n\n\u201cGuinness is good for you\u201d may have been a stretch, but \u201cGood things come to those who wait\u201d builds on the truism that patience is a virtue and therefore a good pint of Guinness takes time to pour (119.5 seconds. I know you were wondering.)\n\nThe fact that British Airways flies to more destinations than any other airline is their truism, and led their advertisers to the now famous tagline, \u201cThe world\u2019s favourite airline.\u201d\n\n\n\nAt my company, Stuff & Nonsense, we\u2019ve been thinking about taglines as we think about our position within an industry that seems full of companies who \u201cdesign\u201d, \u201ccraft\u201d, and \u201ccreate\u201d \u201cdelightful\u201d, \u201cbeautiful\u201d, \u201cremarkable digital experiences\u201d.\n\nMuch of what made us different has changed along with the type of work we\u2019re interested in doing. Our work\u2019s expanded beyond websites and now includes design for mobile and other media. It\u2019s true we can\u2019t know how or where it will be seen. The ways that we make it are flexible too as we\u2019re careful not to become tied to particular tools or approaches. \n\nIt\u2019s also true that we\u2019re a small team. One that\u2019s flexible enough to travel around the world to work alongside our clients. We join their in-house teams and we collaborate with them in ways that other agencies often find more difficult. We know that our clients appreciate our flexibility and have derived enormous value from it. We know that we\u2019ve won business because of it and that it\u2019s now a big part of our proposition.\n\nOur truism is that we\u2019re flexible, \u201cFabulously flexible\u201d as our tagline now expresses. And although we know that there may be other agencies who can be similarly flexible \u2013 after all, being flexible is not a unique selling proposition \u2013 only we do it so fabulously.\n\n\n\nAs the old year rolls into the new, how will your company describe what you do in 2015? More importantly, how will you tell prospective clients why you do it, what matters to you and why they should work with you?\n\nStart by writing a list of truisms about your company. Write as many as you can, but then whittle that list down to just one, the most important truth. Work on that truism to create a tagline that\u2019s meaningful, difficult to be argue with and, above all, uniquely yours.\n\nAnswers\n\n\nThe Ultimate Driving Machine (BMW)\nJust Do It (Nike)\nDon\u2019t Leave Home Without It (American Express)", "year": "2014", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2014-12-23T00:00:00+00:00", "url": "https://24ways.org/2014/taglines-and-truisms/", "topic": "business"} {"rowid": 26, "title": "Integrating Contrast Checks in Your Web Workflow", "contents": "It\u2019s nearly Christmas, which means you\u2019ll be sure to find an overload of festive red and green decorating everything in sight\u2014often in the ugliest ways possible. \n\nWhile I\u2019m not here to battle holiday tackiness in today\u2019s 24 ways, it might just be the perfect reminder to step back and consider how we can implement colour schemes in our websites and apps that are not only attractive, but also legible and accessible for folks with various types of visual disabilities.\n\n This simulated photo demonstrates how red and green Christmas baubles could appear to a person affected by protanopia-type colour blindness\u2014not as festive as you might think. Source: Derek Bruff\n\nI\u2019ve been fortunate to work with Simply Accessible to redesign not just their website, but their entire brand. Although the new site won\u2019t be launching until the new year, we\u2019re excited to let you peek under the tree and share a few treats as a case study into how we tackled colour accessibility in our project workflow. Don\u2019t worry\u2014we won\u2019t tell Santa!\n\nCreate a colour game plan\n\nA common misconception about accessibility is that meeting compliance requirements hinders creativity and beautiful design\u2014but we beg to differ. Unfortunately, like many company websites and internal projects, Simply Accessible has spent so much time helping others that they had not spent enough time helping themselves to show the world who they really are. This was the perfect opportunity for them to practise what they preached.\n\nAfter plenty of research and brainstorming, we decided to evolve the existing Simply Accessible brand. Or, rather, salvage what we could. There was no established logo to carry into the new design (it was a stretch to even call it a wordmark), and the Helvetica typography across the site lacked any character. The only recognizable feature left to work with was colour. It was a challenge, for sure: the oranges looked murky and brown, and the blues looked way too corporate for a company like Simply Accessible. We knew we needed to inject a lot of personality.\n\nThe old Simply Accessible website and colour palette.\n\nAfter an audit to round up every colour used throughout the site, we dug in deep and played around with some ideas to bring some new life to this palette. \n\nChoose effective colours\n\nWhether you\u2019re starting from scratch or evolving an existing brand, the first step to having an effective and legible palette begins with your colour choices. While we aren\u2019t going to cover colour message and meaning in this article, it\u2019s important to understand how to choose colours that can be used to create strong contrast\u2014one of the most important ways to create hierarchy, focus, and legibility in your design.\n\nThere are a few methods of creating effective contrast.\n\nLight and dark colours\n\nThe contrast that exists between light and dark colours is the most important attribute when creating effective contrast.\n\nTry not to use colours that have a similar lightness next to each other in a design.\n\n\n\nThe red and green colours on the left share a similar lightness and don\u2019t provide enough contrast on their own without making some adjustments. Removing colour and showing the relationship in greyscale reveals that the version on the right is much more effective. \n\nIt\u2019s important to remember that red and green colour pairs cause difficulty for the majority of colour-blind people, so they should be avoided wherever possible, especially when placed next to each other. \n\nComplementary contrast\n\n\n\nEffective contrast can also be achieved by choosing complementary colours (other than red and green), that are opposite each other on a colour wheel.\n\nThese colour pairs generally work better than choosing adjacent hues on the wheel.\n\nCool and warm contrast\n\nContrast also exists between cool and warm colours on the colour wheel.\n\nImagine a colour wheel divided into cool colours like blues, purples, and greens, and compare them to warm colours like reds, oranges and yellows.\n\n\n\nChoosing a dark shade of a cool colour, paired with a light tint of a warm colour will provide better contrast than two warm colours or two cool colours. \n\nDevelop colour concepts\n\nAfter much experimentation, we settled on a simple, two-colour palette of blue and orange, a cool-warm contrast colour scheme. We added swatches for call-to-action messaging in green, error messaging in red, and body copy and form fields in black and grey. Shades and tints of blue and orange were added to illustrations and other design elements for extra detail and interest.\n\nFirst stab at a new palette.\n\nWe introduced the new palette for the first time on an internal project to test the waters before going full steam ahead with the website. It gave us plenty of time to get a feel for the new design before sharing it with the public.\n\nPutting the test palette into practice with an internal report\n\nIt\u2019s important to be open to changes in your palette as it might need to evolve throughout the design process. Don\u2019t tell your client up front that this palette is set in stone. If you need to tweak the colour of a button later because of legibility issues, the last thing you want is your client pushing back because it\u2019s different from what you promised.\n\nAs it happened, we did tweak the colours after the test run, and we even adjusted the logo\u2014what looked great printed on paper looked a little too light on screens.\n\nConsider how colours might be used\n\nDon\u2019t worry if you haven\u2019t had the opportunity to test your palette in advance. As long as you have some well-considered options, you\u2019ll be ready to think about how the colour might be used on the site or app. \n\nObviously, in such early stages it\u2019s unlikely that you\u2019re going to know every element or feature that will appear on the site at launch time, or even which design elements could be introduced to the site later down the road. There are, of course, plenty of safe places to start.\n\nFor Simply Accessible, I quickly mocked up these examples in Illustrator to get a handle on the elements of a website where contrast and legibility matter the most: text colours and background colours. While it\u2019s less important to consider the contrast of decorative elements that don\u2019t convey essential information, it\u2019s important for a reader to be able to discern elements like button shapes and empty form fields.\n\nA basic list of possible colour combinations that I had in mind for the Simply Accessible website\n\nRun initial tests\n\nOnce these elements were laid out, I manually plugged in the HTML colour code of each foreground colour and background colour on Lea Verou\u2019s Contrast Checker. I added the results from each colour pair test to my document so we could see at a glance which colours needed adjustment or which colours wouldn\u2019t work at all.\n\nNote: Read more about colour accessibility and contrast requirements\n\n\n\n\n\nAs you can see, a few problems were revealed in this test. To meet the minimum AA compliance, we needed to slightly darken the green, blue, and orange background colours for text\u2014an easy fix. A more complicated problem was apparent with the button colours. I had envisioned some buttons appearing over a blue background, but the contrast ratios were well under 3:1. Although there isn\u2019t a guide in WCAG for contrast requirements of two non-text elements, the ISO and ANSI standard for visible contrast is 3:1, which is what we decided to aim for.\n\nWe also checked our colour combinations in Color Oracle, an app that simulates the most extreme forms of colour blindness. It confirmed that coloured buttons over blue backgrounds was simply not going to work. The contrast was much too low, especially for the more common deuteranopia and protanopia-type deficiencies.\n\nHow our proposed colour pairs could look to people with three types of colour blindness\n\nMake adjustments if necessary\n\n\n\nAs a solution, we opted to change all buttons to white when used over dark coloured backgrounds. In addition to increasing contrast, it also gave more consistency to the button design across the site instead of introducing a lot of unnecessary colour variants.\n\nPutting more work into getting compliant contrast ratios at this stage will make the rest of implementation and testing a breeze. When you\u2019ve got those ratios looking good, it\u2019s time to move on to implementation.\n\nImplement colours in style guide and prototype\n\nOnce I was happy with my contrast checks, I created a basic style guide and added all the colour values from my colour exploration files, introduced more tints and shades, and added patterned backgrounds. I created examples of every panel style we were planning to use on the site, with sample text, links, and buttons\u2014all with working hover states. Not only does this make it easier for the developer, it allows you to check in the browser for any further contrast issues.\n\n\n\n\n\nRun a final contrast check\n\nDuring the final stages of testing and before launch, it\u2019s a good idea to do one more check for colour accessibility to ensure nothing\u2019s been lost in translation from design to code. Unless you\u2019ve introduced massive changes to the design in the prototype, it should be fairly easy to fix any issues that arise, particularly if you\u2019ve stayed on top of updating any revisions in the style guide.\n\nOne of the more well-known evaluation tools, WAVE, is web-based and will work in any browser, but I love using Chrome\u2019s Accessibility Tools. Not only are they built right in to the Inspector, but they\u2019ll work if your site is password-protected or private, too.\n\nChrome\u2019s Accessibility Tools audit feature shows that there are no immediate issues with colour contrast in our prototype \n\nThe human touch\n\nFinally, nothing beats a good round of user testing. Even evaluation tools have their flaws. Although they\u2019re great at catching contrast errors for text and backgrounds, they aren\u2019t going to be able to find errors in non-text elements, infographics, or objects placed next to each other where discernible contrast is important. \n\n\n\nOur final palette, compared with our initial ideas, was quite different, but we\u2019re proud to say it\u2019s not just compliant, but shows Simply Accessible\u2019s true personality. Who knows, it may not be final at all\u2014there are so many opportunities down the road to explore and expand it further.\n\n\n\nAccessibility should never be an afterthought in a project. It\u2019s not as simple as adding alt text to images, or running your site through a compliance checker at the last minute and assuming that a pass means everything is okay. Considering how colour will be used during every stage of your project will help avoid massive problems before launch, or worse, launching with serious issues. \n\nIf you find yourself working on a personal project over the Christmas break, try integrating these checks into your workflow and make colour accessibility a part of your New Year\u2019s resolutions.", "year": "2014", "author": "Geri Coady", "author_slug": "gericoady", "published": "2014-12-22T00:00:00+00:00", "url": "https://24ways.org/2014/integrating-contrast-checks-in-your-web-workflow/", "topic": "design"} {"rowid": 36, "title": "Naming Things", "contents": "There are only two hard things in computer science: cache invalidation and naming things.\nPhil Karlton\n\n\nBeing a professional web developer means taking responsibility for the code you write and ensuring it is comprehensible to others. Having a documented code style is one means of achieving this, although the size and type of project you\u2019re working on will dictate the conventions used and how rigorously they are enforced.\n\nWorking in-house may mean working with multiple developers, perhaps in distributed teams, who are all committing changes \u2013 possibly to a significant codebase \u2013 at the same time. Left unchecked, this codebase can become unwieldy. Coding conventions ensure everyone can contribute, and help build a product that works as a coherent whole.\n\nEven on smaller projects, perhaps working within an agency or by yourself, at some point the resulting product will need to be handed over to a third party. It\u2019s sensible, therefore, to ensure that your code can be understood by those who\u2019ll eventually take ownership of it.\n\nPut simply, code is read more often than it is written or changed. A consistent and predictable naming scheme can make code easier for other developers to understand, improve and maintain, presumably leaving them free to worry about cache invalidation.\n\nLet\u2019s talk about semantics\n\nNames not only allow us to identify objects, but they can also help us describe the objects being identified.\n\nSemantics (the meaning or interpretation of words) is the cornerstone of standards-based web development. Using appropriate HTML elements allows us to create documents and applications that have implicit structural meaning. Thanks to HTML5, the vocabulary we can choose from has grown even larger.\n\nHTML elements provide one level of meaning: a widely accepted description of a document\u2019s underlying structure. It\u2019s only with the mutual agreement of browser vendors and developers that

    indicates a paragraph.\n\nYet (with the exception of widely accepted microdata and microformat schemas) only HTML elements convey any meaning that can be parsed consistently by user agents. While using semantic values for class names is a noble endeavour, they provide no additional information to the visitor of a website; take them away and a document will have exactly the same semantic value.\n\nI didn\u2019t always think this was the case, but the real world has a habit of changing your opinion. Much of my thinking around semantics has been informed by the writing of my peers. In \u201cAbout HTML semantics and front-end architecture\u201d, Nicholas Gallagher wrote:\n\n\n\tThe important thing for class name semantics in non-trivial applications is that they be driven by pragmatism and best serve their primary purpose \u2013 providing meaningful, flexible, and reusable presentational/behavioural hooks for developers to use.\n\n\nThese thoughts are echoed by Harry Roberts in his CSS Guidelines:\n\n\n\tThe debate surrounding semantics has raged for years, but it is important that we adopt a more pragmatic, sensible approach to naming things in order to work more efficiently and effectively. Instead of focussing on \u2018semantics\u2019, look more closely at sensibility and longevity \u2013 choose names based on ease of maintenance, not for their perceived meaning.\n\n\nNaming methodologies\n\nFront-end development has undergone a revolution in recent years. As the projects we\u2019ve worked on have grown larger and more important, our development practices have matured. The pros and cons of object-orientated approaches to CSS can be endlessly debated, yet their introduction has highlighted the usefulness of having documented naming schemes.\n\nJonathan Snook\u2019s SMACSS (Scalable and Modular Architecture for CSS) collects style rules into five categories: base, layout, module, state and theme. This grouping makes it clear what each rule does, and is aided by a naming convention:\n\n\n\tBy separating rules into the five categories, naming convention is beneficial for immediately understanding which category a particular style belongs to and its role within the overall scope of the page. On large projects, it is more likely to have styles broken up across multiple files. In these cases, naming convention also makes it easier to find which file a style belongs to.\n\n\tI like to use a prefix to differentiate between layout, state and module rules. For layout, I use l- but layout- would work just as well. Using prefixes like grid- also provide enough clarity to separate layout styles from other styles. For state rules, I like is- as in is-hidden or is-collapsed. This helps describe things in a very readable way.\n\n\nSMACSS is more a set of suggestions than a rigid framework, so its ideas can be incorporated into your own practice. Nicholas Gallagher\u2019s SUIT CSS project is far more strict in its naming conventions:\n\n\n\tSUIT CSS relies on structured class names and meaningful hyphens (i.e., not using hyphens merely to separate words). This helps to work around the current limits of applying CSS to the DOM (i.e., the lack of style encapsulation), and to better communicate the relationships between classes.\n\n\nOver the last year, I\u2019ve favoured a BEM-inspired approach to CSS. BEM stands for block, element, modifier, which describes the three types of rule that contribute to the style of a single component. This means that, given the following markup:\n\n

      \n
    • Rudolph
    • \n
    • Dasher
    • \n
    • Dancer
    • \n
    • Prancer
    • \n
    • Vixen
    • \n
    • Comet
    • \n
    • Cupid
    • \n
    • Dunder
    • \n
    • Blixem
    • \n
    \n\nI know that:\n\n\n\t.sleigh is a containing block or component.\n\t.sleigh__reindeer is used only as a descendent element of .sleigh.\n\t.sleigh__reindeer\u2013\u2013famous is used only as a modifier of .sleigh__reindeer.\n\n\nWith this naming scheme in place, I know which styles relate to a particular component, and which are shared. Beyond reducing specificity-related head-scratching, this approach has given me a framework within which I can consistently label items, and has sped up my workflow considerably.\n\nEach of these methodologies shows that any robust CSS naming convention will have clear rules around case (lowercase, camelCase, PascalCase) and the use of special (allowed) characters like hyphens and underscores.\n\nWhat makes for a good name?\n\nRegardless of higher-level conventions, there\u2019s no getting away from the fact that, at some point, we\u2019re still going to have to name things. Recognising that classes should be named with other developers in mind, what makes for a good name?\n\nUnderstandable\n\nThe most important aspect is for a name to be understandable. Words used in your project may come from a variety of sources: some may be widely understood, and others only be recognised by people working within a particular environment.\n\n\n\tCulture\nMost words you\u2019ll choose will have common currency outside the world of web development, although they may have a particular interpretation among developers (think menu, list, input). However, words may have a narrower cultural significance; for example, in Germany and other German-speaking countries, impressum is the term used for legally mandated statements of ownership.\n\tIndustry\nIndustries often use specific terms to describe common business practices and concepts. Publishing has a number of these (headline, standfirst, masthead, colophon\u2026) all have well understood meanings \u2013 and not all of them are relevant to online usage.\n\tOrganisation\nCompanies may have internal names (or nicknames) for their products and services. The Guardian is rife with such names: bisons (and buffalos), pixies (and super-pixies), bentos (and mini-bentos)\u2026 all of which mean something very different outside the organisation. Although such names can be useful inside smaller teams, in larger organisations they can become a barrier to entry, a sort of secret code used among employees who have been around long enough to know what they mean.\n\tProduct\nYour team will undoubtedly have created names for specific features or interface components used in your product. For example, at Clearleft we coined the term gravigation for a navigation bar that was pinned to the bottom of the viewport. Elements of a visual design language may have names, too. Transport for London\u2019s bar and circle logo is known internally as the roundel, while Nike\u2019s logo is called the swoosh. Branding agencies often christen colours within a brand palette, too, either to evoke aspects of the identity or to indicate intended usage.\n\n\nOnce you recognise the origin of the words you use, you\u2019ll be better able to judge their appropriateness. Using Latin words for class names may satisfy a need to use semantic-sounding terms but, unless you work in a company whose employees have a basic grasp of Latin, a degree of translation will be required. Military ranks might be a clever way of declaring sizes without implying actual values, but I\u2019d venture most people outside the armed forces don\u2019t know how they\u2019re ordered.\n\nObvious\n\nQuite often, the first name that comes into your head will be the best option. Names that obliquely reference the function of a class (e.g. receptacle instead of container, kevlar instead of no-bullets) only serve to add an additional layer of abstraction. Don\u2019t overthink it!\n\nOne way of knowing if the names you use are well understood is to look at what similar concepts are called in existing vocabularies. schema.org, Dublin Core and the BBC\u2019s ontologies are all useful sources for object names.\n\nFunctional\n\nWhile we\u2019ve learned to avoid using presentational classes, there remains a tension between naming things based on their content, and naming them for their intended presentation or behaviour (which may change at different breakpoints). Rather than think about a component\u2019s appearance or behaviour, instead look to its function, its purpose. To clarify, ask what a component\u2019s function is, and not how the component functions.\n\nFor example, the Guardian\u2019s internal content system uses the following names for different types of image placement: supporting, showcase and thumbnail, with inline being the default. These options make no promise of the resulting position on a webpage (or smartphone app, or television screen\u2026), but do suggest intended use, and therefore imply the likely presentation.\n\nConsistent\n\nBeing consistent in your approach to names will allow for easier naming of successive components, and extending the vocabulary when necessary. For example, a predictably named hierarchy might use names like primary and secondary. Should another level need to be added, tertiary is clearly be preferred over third.\n\nAppropriate\n\nYour project will feature a mix of style rules. Some will perform utility functions (clearing floats, removing bullets from a list, reseting margins), while others will perform specific functions used only once or twice in a project. Names should reflect this. For commonly used classes, be generic; for unique components be more specific.\n\nIt\u2019s also worth remembering that you can use multiple classes on an element, so combining both generic and specific can give you a powerful modular design system:\n\n\n\tGeneric: list\n\tSpecific: naughty-children\n\tCombined: naughty-children list\n\n\nIf following the BEM methodology, you might use the following classes:\n\n\n\tGeneric: list\n\tSpecific: list\u2013\u2013nice-children\n\tCombined: list list\u2013\u2013nice-children\n\n\nExtensible\n\nGood naming schemes can be extended. One way of achieving this is to use namespaces, which are basically a way of grouping related names under a higher-level term.\n\nMicroformats are a good example of a well-designed naming scheme, with many of its vocabularies taking property names from existing and related specifications (e.g. hCard is a 1:1 representation of vCard). Microformats 2 goes one step further by grouping properties under several namespaces:\n\n\n\th-* for root class names (e.g. h-card)\n\tp-* for simple (text) properties (e.g. p-name)\n\tu-* for URL properties (e.g. u-photo)\n\tdt-* for date/time properties (e.g. dt-bday)\n\te-* for embedded markup properties (e.g. e-note)\n\n\nThe inclusion of namespaces is a massive improvement over the earlier specification, but the downside is that microformats now occupy five separate namespaces. This might be problematic if you are using u-* for your utility classes. While nothing will break, your naming system won\u2019t be as robust, so plan accordingly.\n\n(Note: Microformats perform a very specific function, separate from any presentational concerns. It\u2019s therefore considered best practice to not use microformat classes as styling hooks, but instead use additional classes that relate to the function of the component and adhere to your own naming conventions.)\n\nShort\n\nNames should be as long as required, but no longer. When looking for words to describe a particular function, I try to look for single words where possible. Avoid abbreviations unless they are understood within the contexts described above. rrp is fine if labelling a recommended retail price in an online shop, but not very helpful if used to mean ragged-right paragraph, for example.\n\nFun!\n\nFinally, names can be an opportunity to have some fun! Names can give character to a project, be it by providing an outlet for in-jokes or adding little easter eggs for those inclined to look.\n\nThe copyright statement on Apple\u2019s website has long been named sosumi, a word that has a nice little history inside Apple. Until recently, the hamburger menu icon on the Guardian website was labelled honest-burger, after the developer\u2019s favourite burger restaurant.\n\nA few thoughts on preprocessors\n\nCSS preprocessors have solved a lot of problems, but they have an unfortunate downside: they require you to name yet more things! Whereas we needed to worry only about style rules, now we need names for variables, mixins, functions\u2026 oh my!\n\nA second article could be written about naming these, so for now I\u2019ll offer just a few thoughts. The first is to note that preprocessors make it easier to change things, as they allow for DRYer code. So while the names of variables are important (and the advice in this article still very much applies), you can afford to relax a little.\n\nLooking to name colour variables? If possible, find out if colours have been assigned names in a brand palette. If not, use obvious names (based on appearance or function, depending on your preference) and adapt as the palette grows. If it becomes difficult to name colours that are too similar, I\u2019d venture that the problem lies with the design rather than the naming scheme.\n\nThe same is true for responsive breakpoints. Preprocessors allow you to move awkward naming conventions out of the markup and into the CSS. Although terms like mobile, tablet and desktop are not desirable given the need to think about device-agnostic design, if these terms are widely understood within a product team and among stakeholders, using them will ensure everyone is using the same language (they can always be changed later).\n\nIt still feels like we\u2019re at the very beginning of understanding how preprocessors fit into a development workflow, if at all! I suspect over the next few years, best practices will emerge for all of these considerations. In the meantime, use your brain!\n\n\n\nEven with sensible rules and conventions in place, naming things can remain difficult, but hopefully I\u2019ve made this exercise a little less painful. Christmas is a time of giving, so to the developer reading your code in a year\u2019s time, why not make your gift one of clearer class names.", "year": "2014", "author": "Paul Lloyd", "author_slug": "paulrobertlloyd", "published": "2014-12-21T00:00:00+00:00", "url": "https://24ways.org/2014/naming-things/", "topic": "code"}