{"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": 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": 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": 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": 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": 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": 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": 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": 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": 68, "title": "Grid, Flexbox, Box Alignment: Our New System for Layout", "contents": "Three years ago for 24 ways 2012, I wrote an article about a new CSS layout method I was excited about. A specification had emerged, developed by people from the Internet Explorer team, bringing us a proper grid system for the web. In 2015, that Internet Explorer implementation is still the only public implementation of CSS grid layout. However, in 2016 we should be seeing it in a new improved form ready for our use in browsers.\nGrid layout has developed hidden behind a flag in Blink, and in nightly builds of WebKit and, latterly, Firefox. By being developed in this way, breaking changes could be safely made to the specification as no one was relying on the experimental implementations in production work.\nAnother new layout method has emerged over the past few years in a more public and perhaps more painful way. Shipped prefixed in browsers, The flexible box layout module (flexbox) was far too tempting for developers not to use on production sites. Therefore, as changes were made to the specification, we found ourselves with three different flexboxes, and browser implementations that did not match one another in completeness or in the version of specified features they supported. \nOwing to the different ways these modules have come into being, when I present on grid layout it is often the very first time someone has heard of the specification. A question I keep being asked is whether CSS grid layout and flexbox are competing layout systems, as though it might be possible to back the loser in a CSS layout competition. The reality, however, is that these two methods will sit together as one system for doing layout on the web, each method playing to certain strengths and serving particular layout tasks. \nIf there is to be a loser in the battle of the layouts, my hope is that it will be the layout frameworks that tie our design to our markup. They have been a necessary placeholder while we waited for a true web layout system, but I believe that in a few years time we\u2019ll be easily able to date a website to circa 2015 by seeing
    or
    in the markup.\nIn this article, I\u2019m going to take a look at the common features of our new layout systems, along with a couple of examples which serve to highlight the differences between them.\nTo see the grid layout examples you will need to enable grid in your browser. The easiest thing to do is to enable the experimental web platform features flag in Chrome. Details of current browser support can be found here. \nRelationship\nItems only become flex or grid items if they are a direct child of the element that has display:flex, display:grid or display:inline-grid applied. Those direct children then understand themselves in the context of the complete layout. This makes many things possible. It\u2019s the lack of relationship between elements that makes our existing layout methods difficult to use. If we float two columns, left and right, we have no way to tell the shorter column to extend to the height of the taller one. We have expended a lot of effort trying to figure out the best way to make full-height columns work, using techniques that were never really designed for page layout.\nAt a very simple level, the relationship between elements means that we can easily achieve full-height columns. In flexbox:\nSee the Pen Flexbox equal height columns by rachelandrew (@rachelandrew) on CodePen.\n\nAnd in grid layout (requires a CSS grid-supporting browser):\nSee the Pen Grid equal height columns by rachelandrew (@rachelandrew) on CodePen.\n\nAlignment\nFull-height columns rely on our flex and grid items understanding themselves as part of an overall layout. They also draw on a third new specification: the box alignment module. If vertical centring is a gift you\u2019d like to have under your tree this Christmas, then this is the box you\u2019ll want to unwrap first.\nThe box alignment module takes the alignment and space distribution properties from flexbox and applies them to other layout methods. That includes grid layout, but also other layout methods. Once implemented in browsers, this specification will give us true vertical centring of all the things.\nOur examples above achieved full-height columns because the default value of align-items is stretch. The value ensured our columns stretched to the height of the tallest. If we want to use our new vertical centring abilities on all items, we would set align-items:center on the container. To align one flex or grid item, apply the align-self property.\nThe examples below demonstrate these alignment properties in both grid layout and flexbox. The portrait image of Widget the cat is aligned with the default stretch. The other three images are aligned using different values of align-self.\nTake a look at an example in flexbox:\nSee the Pen Flexbox alignment by rachelandrew (@rachelandrew) on CodePen.\n\nAnd also in grid layout (requires a CSS grid-supporting browser):\nSee the Pen Grid alignment by rachelandrew (@rachelandrew) on CodePen.\n\nThe alignment properties used with CSS grid layout.\nFluid grids\nA cornerstone of responsive design is the concept of fluid grids.\n\n\u201c[\u2026]every aspect of the grid\u2014and the elements laid upon it\u2014can be expressed as a proportion relative to its container.\u201d\n\u2014Ethan Marcotte, \u201cFluid Grids\u201d\n\nThe method outlined by Marcotte is to divide the target width by the context, then use that value as a percentage value for the width property on our element.\nh1 {\n margin-left: 14.575%; /*\u00a0144px / 988px = 0.14575\u00a0*/\n width: 70.85%; /*\u00a0700px / 988px = 0.7085\u00a0*/\n}\nIn more recent years, we\u2019ve been able to use calc() to simplify this (at least, for those of us able to drop support for Internet Explorer 8). However, flexbox and grid layout make fluid grids simple.\nThe most basic of flexbox demos shows this fluidity in action. The justify-content property \u2013 another property defined in the box alignment module \u2013 can be used to create an equal amount of space between or around items. As the available width increases, more space is assigned in proportion.\nIn this demo, the list items are flex items due to display:flex being added to the ul. I have given them a maximum width of 250 pixels. Any remaining space is distributed equally between the items as the justify-content property has a value of space-between.\nSee the Pen Flexbox: justify-content by rachelandrew (@rachelandrew) on CodePen.\n\nFor true fluid grid-like behaviour, your new flexible friends are flex-grow and flex-shrink. These properties give us the ability to assign space in proportion.\nThe flexbox flex property is a shorthand for:\n\nflex-grow\nflex-shrink\nflex-basis\n\nThe flex-basis property sets the default width for an item. If flex-grow is set to 0, then the item will not grow larger than the flex-basis value; if flex-shrink is 0, the item will not shrink smaller than the flex-basis value.\n\nflex: 1 1 200px: a flexible box that can grow and shrink from a 200px basis.\nflex: 0 0 200px: a box that will be 200px and cannot grow or shrink.\nflex: 1 0 200px: a box that can grow bigger than 200px, but not shrink smaller.\n\nIn this example, I have a set of boxes that can all grow and shrink equally from a 100 pixel basis.\nSee the Pen Flexbox: flex-grow by rachelandrew (@rachelandrew) on CodePen.\n\nWhat I would like to happen is for the first element, containing a portrait image, to take up less width than the landscape images, thus keeping it more in proportion. I can do this by changing the flex-grow value. By giving all the items a value of 1, they all gain an equal amount of the available space after the 100 pixel basis has been worked out.\nIf I give them all a value of 3 and the first box a value of 1, the other boxes will be assigned three parts of the available space while box 1 is assigned only one part. You can see what happens in this demo:\nSee the Pen Flexbox: flex-grow by rachelandrew (@rachelandrew) on CodePen.\n\nOnce you understand flex-grow, you should easily be able to grasp how the new fraction unit (fr, defined in the CSS grid layout specification) works. Like flex-grow, this unit allows us to assign available space in proportion. In this case, we assign the space when defining our track sizes.\nIn this demo (which requires a CSS grid-supporting browser), I create a four-column grid using the fraction unit to define my track sizes. The first track is 1fr in width, and the others 2fr.\ngrid-template-columns: 1fr 2fr 2fr 2fr;\nSee the Pen Grid fraction units by rachelandrew (@rachelandrew) on CodePen.\n\nThe four-track grid.\nSeparation of concerns\nMy younger self petitioned my peers to stop using tables for layout and to move to CSS. One of the rallying cries of that movement was the concept of separating our source and content from how they were displayed. It was something of a failed promise given the tools we had available: the display leaked into the markup with the need for redundant elements to cope with browser bugs, or visual techniques that just could not be achieved without supporting markup.\nBrowsers have improved, but even now we can find ourselves compromising the ideal document structure so we can get the layout we want at various breakpoints. In some ways, the situation has returned to tables-for-layout days. Many of the current grid frameworks rely on describing our layout directly in the markup. We add divs for rows, and classes to describe the number of desired columns. We nest these constructions of divs inside one another.\nHere is a snippet from the Bootstrap grid examples \u2013 two columns with two nested columns:\n
    \n
    \n .col-md-8\n
    \n
    \n .col-md-6\n
    \n
    \n .col-md-6\n
    \n
    \n
    \n
    \n .col-md-4\n
    \n
    \nNot a million miles away from something I might have written in 1999.\n

    \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": 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": 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": 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"} {"rowid": 42, "title": "An Overview of SVG Sprite Creation Techniques", "contents": "SVG can be used as an icon system to replace icon fonts. The reasons why SVG makes for a superior icon system are numerous, but we won\u2019t be going over them in this article. If you don\u2019t use SVG icons and are interested in knowing why you may want to use them, I recommend you check out \u201cInline SVG vs Icon Fonts\u201d by Chris Coyier \u2013 it covers the most important aspects of both systems and compares them with each other to help you make a better decision about which system to choose.\n\nOnce you\u2019ve made the decision to use SVG instead of icon fonts, you\u2019ll need to think of the best way to optimise the delivery of your icons, and ways to make the creation and use of icons faster.\n\nJust like bitmaps, we can create image sprites with SVG \u2013 they don\u2019t look or work exactly alike, but the basic concept is pretty much the same.\n\nThere are several ways to create SVG sprites, and this article will give you an overview of three of them. While we\u2019re at it, we\u2019re going to take a look at some of the available tools used to automate sprite creation and fallback for us.\n\nPrerequisites\n\nThe content of this article assumes you are familiar with SVG. If you\u2019ve never worked with SVG before, you may want to look at some of the introductory tutorials covering SVG syntax, structure and embedding techniques. I recommend the following:\n\n\n\tSVG basics: Using SVG.\n\tStructure: Structuring, Grouping, and Referencing in SVG \u2014 The , , and Elements. We\u2019ll mention and quite a bit in this article.\n\tEmbedding techniques: Styling and Animating SVGs with CSS. The article covers several topics, but the section linked focuses on embedding techniques.\n\tA compendium of SVG resources compiled by Chris Coyier \u2014 contains resources to almost every aspect of SVG you might be interested in.\n\n\nAnd if you\u2019re completely new to the concept of spriting, Chris Coyier\u2019s CSS Sprites explains all about them.\n\nAnother important SVG feature is the viewBox attribute. For some of the techniques, knowing your way around this attribute is not required, but it\u2019s definitely more useful if you understand \u2013 even if just vaguely \u2013 how it works. The last technique mentioned in the article requires that you do know the attribute\u2019s syntax and how to use it. To learn all about viewBox, you can refer to my blog post about SVG coordinate systems.\n\nWith the prerequisites in place, let\u2019s move on to spriting SVGs!\n\nBefore you sprite\u2026\n\nIn order to create an SVG sprite with your icons, you\u2019ll of course need to have these icons ready for use.\n\nSome spriting tools require that you place your icons in a folder to which a certain spriting process is to be applied. As such, for all of the upcoming sections we\u2019ll work on the assumption that our SVG icons are placed in a folder named SVG.\n\nEach icon is an individual .svg file.\n\nYou\u2019ll need to make sure each icon is well-prepared and optimised for use \u2013 make sure you\u2019ve cleaned up the code by running it through one of the optimisation tools or processes available (or doing it manually if it\u2019s not tedious).\n\nAfter prepping the icon files and placing them in a folder, we\u2019re ready to create our SVG sprite.\n\nHTML inline SVG sprites\n\nSince SVG is XML code, it can be embedded inline in an HTML document as a code island using the element. Chris Coyier wrote about this technique first on CSS-Tricks.\n\nThe embedded SVG will serve as a container for our icons and is going to be the actual sprite we\u2019re going to use. So we\u2019ll start by including the SVG in our document.\n\n\n\n\n\n \n\n\n\n\n\nNext, we\u2019re going to place the icons inside the . Each icon will be wrapped in a element we can then reference and use elsewhere in the page using the SVG element. The element has many benefits, and we\u2019re using it because it allows us to define a symbol (which is a convenient markup for an icon) without rendering that symbol on the screen. The elements defined inside will only be rendered when they are referenced \u2013 or called \u2013 by the element.\n\nMoreover, can have its own viewBox attribute, which makes it possible to control the positioning of its content inside its container at any time.\n\nBefore we move on, I\u2019d like to shed some light on the style=\"display:none;\" part of the snippet above. Without setting the display of the SVG to none, and even though its contents are not rendered on the page, the SVG will still take up space in the page, resulting in a big empty area. In order to avoid that, we\u2019re hiding the SVG entirely with CSS.\n\nNow, suppose we have a Twitter icon in the icons folder. twitter.svg might look something like this:\n\n\n\n\n\n\n\n\nWe don\u2019t need the root svg element, so we\u2019ll strip the code and only keep the parts that make up the Twitter icon\u2019s shape, which in this example is just the element.Let\u2019s drop that into the sprite container like so:\n\n\n \n \n \n\n \n \n \n \n\n \n\n\nRepeat for the other icons.\n\nThe value of the element\u2019s viewBox attribute depends on the size of the SVG. You don\u2019t need to know how the viewBox works to use it in this case. Its value is made up of four parts: the first two will almost always be \u201c0 0\u201d; the second two will be equal to the size of the icon. For example, our Twitter icon is 32px by 32px (see twitter.svg above), so the viewBox value is \u201c0 0 32 32\u201d.\n\nThat said, it is certainly useful to understand how the viewBox works \u2013 it can help you troubleshoot SVG sometimes and gives you better control over it, allowing you to scale, position and even crop SVGs manually without having to resort to an editor. My blog post explains all about the viewBox attribute and its related attributes.\n\nOnce you have your SVG sprite ready, you can display the icons anywhere on the page by referencing them using the SVG element:\n\n\n \n\n\nAnd that\u2019s all there is to it!\n\nHTML-inline SVG sprites are simple to create and use, but when you have a lot of icons (and the more icon sets you create) it can easily become daunting if you have to manually transfer the icons into the . Fortunately, you don\u2019t have to do that. Fabrice Weinberg created a Grunt plugin called grunt-svgstore which takes the icons in your SVG folder and generates the SVG sprites for you; all you have to do is just drop the sprites into your page and use the icons like we did earlier.\n\nThis technique works in all browsers supporting SVG. There seems to be a bug in Safari on iOS which causes the icons not to show up when the SVG sprite is defined at the bottom of the document after the references to the icons, so it\u2019s safest to include the sprite before you use the icons until this bug is fixed.\n\nThis technique has one disadvantage: the SVG sprite cannot be cached. We\u2019re saving an extra HTTP request here but the browser cannot cache the image, so we aren\u2019t speeding up any subsequent page loads by inlining the SVG. There must be a better way \u2013 and there is.\n\nStyling the icons is possible, but getting deep into the styles becomes a bit harder owing to the nature of the contents of the element \u2013 these contents are cloned into a shadow DOM, and hence selecting elements in CSS the traditional way is not possible. However, some techniques to work around that do exist, and give us slightly more styling flexibility. Animations work as expected.\n\nReferencing an external SVG sprite in HTML\n\nInstead of including the SVG inline in the document, you can reference the sprite and the icons inside it externally, taking advantage of fragment identifiers to select individual icons in the sprite.\n\nFor example, the above reference to the Twitter icon would look something like this instead:\n\n\n \n\n\n\nicons.svg is the name of the SVG file that contains all of our icons as symbols, and the fragment identifier #twitter-icon is the reference to the wrapping the Twitter icon\u2019s contents. Very convenient, isn\u2019t it? The browser will request the sprite and then cache it, speeding up subsequent page loads. Win!\n\nThis technique also works in all browsers supporting SVG except Internet Explorer \u2013 not even IE9+ with SVG support permits this technique. No version of IE supports referencing an external SVG in .\n\nFortunately (again), Jonathan Neil has created a plugin called svg4everybody which fills this gap in IE; you can reference an external sprite in and also provide fallback for browsers that do not support SVG. However, it requires you to have the fallback images (PNG or JPEG, for example) available to do so. For details, refer to the plugin\u2019s Github repository\u2019s readme file.\n\nCSS inline SVG sprites\n\nAnother way to create an SVG sprite is by inlining the SVG icons in a style sheet using data URIs, and providing fallback for non-supporting browsers \u2013 also within the CSS.\n\nUsing this approach, we\u2019re turning the style sheet into the sprite that includes our icons. The style sheet is normally cached by the browser, so we have that concern out of the way.\n\nThis technique is put into practice in Filament Group\u2019s icon system approach, which uses their Grunticon plugin \u2013 or its sister Grumpicon web app \u2013 for generating the necessary CSS for the sprite. As such, we\u2019re going to cover this technique by following a workflow that uses one of these tools.\n\nAgain, we start with our icon SVG files. To focus on the actual spriting method and not on the tooling, I\u2019ll go over the process of sprite creation using the Grumpicon web app, instead of the Grunticon plugin. Both tools generate the same resources that we\u2019re going to use for the icon system. Whether you choose the web app or the Grunt set-up, after processing your SVG folder you\u2019re going to end up with the same set of resources that we\u2019ll be using throughout this section.\n\nThe first step is to drop your icons into the Grumpicon web app.\n\n Grumpicon homepage screenshot.\n\nThe application will then show you a preview of your icons, and a download button will allow you to download the generated files. These files will contain everything you need for your icon system \u2013 all that\u2019s left is for you to drop the generated files and code into your project as recommended and you\u2019ll have your sprite and icons ready to use anywhere you want in your page.\n\nGrumpicon generates five files and one folder in the downloaded package: a png folder containing PNG versions of your icons; three style sheets (that we\u2019ll go over briefly); a loader script file; and preview.html which is a live example showing you the other files in action.\n\nThe script in the loader goes into the of your page. This script handles browser and feature detection, and requests the necessary style sheet depending on browser support for SVG and base64 data URIs. If you view the source code of the preview page, you can see exactly how the script is added.\n\nicons.data.svg.css is the style sheet that contains your icons \u2013 the sprite. The icons are embedded inline inside the style sheet using data URIs, and applied to elements of your choice as background images, using class names. For example:\n\n.twitter-icon{\n background-image: url('data:image/svg+xml;\u2026'); /* the ellipsis is where the icon\u2019s data would go */\n background-repeat: no-repeat;\n background-position: 50% 50%;\n height: 2em;\n width: 2em;\n /* etc. */\n}\n\nThen, you only have to apply the twitter-icon class name to an element in your HTML to apply the icon as a background to it:\n\n\n\nAnd that\u2019s all you need to do to get an icon on the page.\n\nicons.data.svg.css, along with the other two style sheets and the png folder should be added to your CSS folder.\n\nicons.data.png.css is the style sheet the script will load in browsers that don\u2019t support SVG, such as IE8. Fallback for the inline SVG is provided as a base64-encoded PNG. For instance, the fallback for the Twitter icon from our example would look like so:\n\n.twitter-icon{\n background-image: url('data:image/png;base64;\u2026\u2019);\n /* etc. */\n}\n\nicons.fallback.css is the style sheet required for browsers that don\u2019t support base64-encoded PNGs \u2013 the PNG images are loaded as usual using the image\u2019s URL. The script will load this style sheet for IE6 and IE7, for example.\n\n.twitter-icon{\n background-image: url(png/twitter-icon.png);\n /* etc. */\n}\n\nThis technique is very different from the previous one. The sprite in this case is literally the style sheet, not an SVG container, and the icon usage is very similar to that of a CSS sprite \u2013 the icons are provided as background images.\n\nThis technique has advantages and disadvantages. For the sake of brevity, I won\u2019t go into further details, but the main limitations worth mentioning are that SVGs embedded as background images cannot be styled with CSS; and animations are restricted to those defined inside the for each icon. CSS interactions (such as hover effects) don\u2019t work either. Thus, to apply an effect for an icon that changes its color on hover, for example, you\u2019ll need to export a set of SVGs for each colour in order for Grumpicon to create matching fallback PNG images that can then be used for the animation.\n\nFor more details about the Grumpicon workflow, I recommend you check out \u201cA Designer\u2019s Guide to Grumpicon\u201d on Filament Group\u2019s website.\n\nUsing SVG fragment identifiers and views\n\nThis spriting technique is, again, different from the previous ones, and it is my personal favourite.\n\nSVG comes with a standard way of cropping to a specific area in a particular SVG image. If you\u2019ve ever worked with CSS sprites before then this definitely sounds familiar: it\u2019s almost exactly what we do with CSS sprites \u2013 the image containing all of the icons is cropped, so to speak, to show only the one icon that we want in the background positioning area of the element, using background size and positioning properties.\n\nInstead of using background properties, we\u2019ll be using SVG\u2019s viewBox attribute to crop our SVG to the specific icon we want.\n\nWhat I like about this technique is that it is more visual than the previous ones. Using this technique, the SVG sprite is treated like an actual image containing other images (the icons), instead of treating it as a piece of code containing other code.\n\nAgain, our SVG icons are placed inside a main SVG container that is going to be our SVG sprite. If you\u2019re working in a graphics editor, position or arrange your icons inside the canvas any way you want them to be, and then export the graphic as is. Of course, the less empty space there is in your SVG, the better.\n\nIn our example, the sprite contains three icons as shown in the following image. The sprite is open in Sketch. Notice how the SVG is just big enough to fit the icons inside it. It doesn\u2019t have to be like this, but it\u2019s cleaner this way.\n\n Screenshot showing the SVG sprite containing our icons.\n\nNow, suppose you want to display only the Instagram icon. Using the SVG viewBox attribute, we can crop the SVG to the icon. The Instagram icon is positioned at 64px along the positive x-axis, and zero pixels along the y-axis. It is also 32px by 32px in size.\n\n Screenshot showing the position (offset) of the Instagram icon inside the SVG sprite, and its size.\n\nUsing this information, we can specify the value of the viewBox as: 64 0 32 32. This area of the view box contains only the Instagram icon. 64 0 specifies the top-left corner of the view box area, and 32 32 specify its dimensions.\n\nNow, if we were to change the viewBox value on the SVG sprite to this value, only the Instagram icon will be visible inside the SVG viewport. Great. But how do we use this information to display the icon in our page using our sprite?\n\nSVG comes with a native way to link to portions or areas of an image using fragment identifiers. Fragment identifiers are used to link into a particular view area of an SVG document. Thus, using a fragment identifier and the boundaries of the area that we want (from the viewBox), we can link to that area and display it.\n\nFor example, if you want to display the icon from the sprite using an tag, you can reference the icon in the sprite like so:\n\n\"Settings\n\nThe fragment identifier in the snippet above (#svgView(viewBox(64, 0, 32, 32))) is the important part. This will result in only the Instagram icon\u2019s area of the sprite being displayed.\n\nThere is also another way to do this, using the SVG element. The element can be used to define a view area and then reference that area somewhere else. For example, to define the view box containing the Instagram icon, we can do the following:\n\n\n\nThen, we can reference this view in our element like this:\n\n\"Instagram\n\nThe best part about this technique \u2013 besides the ability to reference an external SVG and hence make use of browser caching \u2013 is that it allows us to use practically any SVG embedding technique and does not restrict us to specific tags.\n\nIt goes without saying that this feature can be used for more than just icon systems, owing to viewBox\u2019s power in controlling an SVG\u2019s viewable area.\n\nSVG fragment identifiers have decent browser support, but the technique is buggy in Safari: there is a bug that causes problems when loading a server SVG file and then using fragment identifiers with it. Bear Travis has documented the issue and a workaround.\n\nWhere to go from here\n\nPick the technique that works best for your project. Each technique has its own pros and cons, relating to convenience and maintainability, performance, and styling and scripting. Each technique also requires its own fallback mechanism.\n\nThe spriting techniques mentioned here are not the only techniques available. Other methods exist, such as SVG stacks, and others may surface in future, but these are the three main ones today.\n\nThe third technique using SVG\u2019s built-in viewBox features is my favourite, and with better browser support and fewer (ideally, no) bugs, I believe it is more likely to become the standard way to create and use SVG sprites. Fallback techniques can be created, of course, in one of many possible ways.\n\nDo you use SVG for your icon system? If so, which is your favourite technique? Do you know or have worked with other ways for creating SVG sprites?", "year": "2014", "author": "Sara Soueidan", "author_slug": "sarasoueidan", "published": "2014-12-16T00:00:00+00:00", "url": "https://24ways.org/2014/an-overview-of-svg-sprite-creation-techniques/", "topic": "code"} {"rowid": 30, "title": "Making Sites More Responsive, Responsibly", "contents": "With digital projects we\u2019re used to shifting our thinking to align with our target audience. We may undertake research, create personas, identify key tasks, or observe usage patterns, with our findings helping to refine our ongoing creations.\u00a0A product\u2019s overall experience can make or break its success, and when it comes to defining these experiences our development choices play a huge role alongside more traditional user-focused activities.\n\nThe popularisation of responsive web design is a great example of how we are able to shape the web\u2019s direction through using technology to provide better experiences. If we think back to the move from table-based layouts to CSS, initially our clients often didn\u2019t know or care about the difference in these approaches, but\u00a0we\u00a0did. Responsive design was similar in this respect \u2013 momentum grew through the web industry choosing to use an approach that we felt would give a better experience, and which was more future-friendly.\u00a0\n\nWe tend to think of responsive design as a means of displaying content appropriately across a range of devices, but the technology and our implementation of it can facilitate much more. A responsive layout not only helps your content work when the newest smartphone comes out, but it also ensures your layout suitably adapts if a visually impaired user drastically changes the size of the text.\n\n The 24 ways site at 400% on a Retina MacBook Pro displays a layout more typically used for small screens.\n\nWhen we think more broadly, we realise that our technical choices and approaches to implementation can have knock-on effects for the greater good, and beyond our initial target audiences. We can make our experiences more\u00a0responsive to people\u2019s needs, enhancing their usability and accessibility along the way.\n\nBeing responsibly responsive\n\nOf course, when we think about being more responsive, there\u2019s a fine line between creating useful functionality and becoming intrusive and overly complex. In the excellent Responsible Responsive Design, Scott Jehl states that:\n\n\nA responsible responsive design equally considers the following throughout a project:\n\nUsability: The way a website\u2019s user interface is presented to the user, and how that UI responds to browsing conditions and user interactions.\nAccess: The ability for users of all devices, browsers, and assistive technologies to access and understand a site\u2019s features and content.\nSustainability: The ability for the technology driving a site or application to work for devices that exist today and to continue to be usable and accessible to users, devices, and browsers in the future.\nPerformance: The speed at which a site\u2019s features and content are perceived to be delivered to the user and the efficiency with which they operate within the user interface.\n\n\n\nScott\u2019s book covers these ideas in a lot more detail than I\u2019ll be able to here (put it on your Christmas list if it\u2019s not there already), but for now let\u2019s think a bit more about our roles as digital creators\u00a0and the power this gives us.\n\nOur choices around technology and the decisions we have to make can be extremely wide-ranging. Solutions will vary hugely depending on the needs of each project, though we can further explore the concept of making our creations more responsive through the use of humble web technologies.\n\nThe power of the web\n\nWe all know that under the HTML5 umbrella are some great new capabilities, including a number of JavaScript APIs such as geolocation, web audio, the file API and many more. We often use these to enhance the functionality of our sites and apps, to add in new features, or to facilitate device-specific interactions.\n\nYou\u2019ll have seen articles with flashy titles such as \u201cTop 5 JavaScript APIs You\u2019ve Never Heard Of!\u201d, which you\u2019ll probably read, think \u201cThat\u2019s quite cool\u201d, yet never use in any real work.\n\nThere is great potential for technologies like these\u00a0to be misused, but there are also great prospects for them to be used well to enhance experiences. Let\u2019s have a look at a few\u00a0examples you may not have considered.\n\nOffline first\n\nWhen we make websites, many of us follow a process which involves user stories \u2013 standardised snippets of context explaining who needs what, and why.\n\n\u201cAs a student I want to pay online for my course so I don\u2019t have to visit the college in person.\u201d\n\n\u201cAs a retailer I want to generate unique product codes so I can manage my stock.\u201d\n\nWe very often focus heavily on what\u00a0needs doing, but may not consider carefully how it will be done. As in Scott\u2019s list, accessibility is extremely important, not only in terms of providing a great experience to users of assistive technologies, but also to make your creation more accessible in the general sense \u2013 including under different conditions.\n\nOffline first is yet another \u2018first\u2019 methodology (my personal favourite being \u2018tea first\u2019), which encourages us to develop so that connectivity\u00a0itself is an enhancement \u2013 letting\u00a0users continue with tasks even when they\u2019re offline. Despite the rapid growth in public Wi-Fi, if we consider data costs and connectivity in developing countries, our travel habits with planes, underground trains and roaming (or simply if you live in the UK\u2019s signal-barren East Anglian wilderness as I do), then you\u2019ll realise that connectivity isn\u2019t as ubiquitous as our internet-addled brains would make us believe. Take a scenario that I\u2019m sure we\u2019re all familiar with \u2013 the digital conference. Your venue may be in a city served by high-speed networks, but after overloading capacity with a full house of hashtag-hungry attendees, each carrying several devices, then everyone\u2019s likely to be offline after all. Wouldn\u2019t it be better if we could do something like this instead?\n\n\n\tSomeone visits our conference website.\n\tOn this initial run, some assets may be cached for future use: the conference schedule, the site\u2019s CSS, photos of the speakers.\n\tWhen the attendee revisits the site on the day, the page shell loads up from the cache.\n\tIf we have cached content (our session timetable, speaker photos or anything else), we can load it directly from the cache. We might then try to update this, or get some new content from the internet, but the conference attendee already has a base experience to use.\n\tIf we don\u2019t have something cached already, then we can try\u00a0grabbing it online.\n\tIf for any reason our requests for new content fail (we\u2019re offline), then we can display a pre-cached error message from the initial load, perhaps providing our users with alternative suggestions from what is\u00a0cached.\n\n\nThere are a number of ways we can make something like this, including using the application cache (AppCache) if you\u2019re that way inclined. However, you may want to look into service workers\u00a0instead. There are also some great resources on Offline First!\u00a0if you\u2019d like to find out more about this.\n\nBuilding in offline functionality isn\u2019t necessarily about starting offline first, and it\u2019s also perfectly possible to retrofit sites and apps to catch offline scenarios, but this kind of graceful degradation can end up being more complex than if we\u2019d considered it from the start. By treating connectivity as an enhancement, we can improve the experience and provide better performance than we can when waiting to counter failures. Our websites can respond to connectivity and usage scenarios, on top of adapting how we present our content. Thinking in this way can enhance each point in Scott\u2019s criteria.\n\nAs I mentioned, this isn\u2019t necessarily the kind of development choice that our clients will ask us for, but it\u2019s one we may decide is simply the right way to build based on our project, enhancing the experience we provide to people, and making it more responsive to their situation.\n\nEven more accessible\n\nWe\u2019ve looked at accessibility in terms of broadening when we can interact with a website, but what about how? Our user stories and personas are often of limited use. We refer in very general terms to students, retailers, and sometimes just users. What if we have a student whose needs are very different from another student? Can we make our sites even more usable and accessible through our development choices?\n\nAgain using JavaScript to illustrate this concept, we can do a lot more with the ways people interact with our websites, and with the feedback we provide, than simply accepting keyboard, mouse and touch inputs and displaying output on a screen.\n\nInput\n\nAmbient light detection is one of those features that looks great in simple demos, but which we struggle to put to practical use. It\u2019s not new \u2013 many satnav systems automatically change the contrast for driving at night or in tunnels, and our laptops may alter the screen brightness or keyboard backlighting to better adapt to our surroundings. Using web technologies we can adapt our presentation to be better suited to ambient light levels.\n\nIf our device has an appropriate light sensor and runs a browser that supports the API, we can grab the ambient light in units using ambient light events, in JavaScript. We may then change our presentation based on different bandings, perhaps like this:\n\nwindow.addEventListener('devicelight', function(e) {\n var lux = e.value;\n\n if (lux < 50) {\n //Change things for dim light\n }\n if (lux >= 50 && lux <= 10000) {\n //Change things for normal light\n }\n if (lux > 10000) {\n //Change things for bright light\n }\n});\n\nLive demo\u00a0(requires light sensor and supported browser).\n\nSoon we may also be able to do such detection through CSS, with light-level being cited in the Media Queries Level 4 specification. If that becomes the case, it\u2019ll probably look something like this:\n\n@media (light-level: dim) {\n /*Change things for dim light*/\n}\n\n@media (light-level: normal) {\n /*Change things for normal light*/\n}\n\n@media (light-level: washed) {\n /*Change things for bright light*/\n}\n\nWhile we may be quick to dismiss this kind of detection as being a gimmick, it\u2019s important to consider that apps such as Light Detector, listed on Apple\u2019s accessibility page, provide important context around exactly this functionality.\n\n\n\t\u201cIf you are blind, Light Detector helps you to be more independent in many daily activities. At home, point your iPhone towards the ceiling to understand where the light fixtures are and whether they are switched on. In a room, move the device along the wall to check if there is a window and where it is. You can find out whether the shades are drawn by moving the device up and down.\u201d\n\n\teverywaretechnologies.com/apps/lightdetector\n\n\nInput can be about so much more than what we enter through keyboards. Both an ever increasing amount of available sensors and more APIs being supported by the major browsers will allow us to cater for more scenarios and respond to them accordingly. This can be as complex or simple as you need; for instance, while x-webkit-speech has been deprecated, the web speech API is available for a number of browsers, and research into sign language detection is also being performed by organisations such as Microsoft.\n\nOutput\n\nWeb technologies give us some great enhancements around input, allowing us to adapt our experiences accordingly. They also provide us with some nice ways to provide feedback to users.\n\nWhen we play video games, many of our modern consoles come with the ability to have rumble effects on our controller pads. These are a great example of an enhancement, as they provide a level of feedback that is entirely optional, but which can give a great deal of extra information to the player in the right circumstances, and broaden the scope of our comprehension beyond what we\u2019re seeing and hearing.\n\nHaptic feedback is possible on the web as well. We could use this in any number of responsible applications, such as alerting a user to changes or using different patterns as a communication mechanism. If you find yourself in a pickle, here\u2019s how to print out SOS in Morse code through the vibration API. The following code indicates the length of vibration in milliseconds, interspersed by pauses in milliseconds.\n\nnavigator.vibrate([100, 300, 100, 300, 100, 300, 600, 300, 600, 300, 600, 300, 100, 300, 100, 300, 100]);\n\nLive demo\u00a0(requires supported browser)\n\nWith great power\u2026\n\nWhat you\u2019ve no doubt come to realise by now is that these are just more examples of progressive enhancement, whose inclusion will provide a better experience if the capabilities are available, but which we should not rely on. This idea isn\u2019t new, but the most important thing to remember, and what I would like you to take away from this article, is that it is up to us to decide to include these kind of approaches within our projects \u2013 if we don\u2019t root for them, they probably won\u2019t happen. This is where our professional responsibility comes in.\n\nWe won\u2019t necessarily be asked to implement solutions for the scenarios above, but they illustrate how we can help to push the boundaries of experiences. Maybe we\u2019ll have to switch our thinking about how we build, but we can create more usable products for a diverse range of people and usage scenarios through the choices we make around technology. Let\u2019s stop thinking simply in terms of features inside a narrow view of our target users, and work out how we can extend these to cater for a wider set of situations.\n\nWhen you plan your next digital project, consider the power of the web and the enhancements we can use, and try to make your projects even more responsive and responsible.", "year": "2014", "author": "Sally Jenkinson", "author_slug": "sallyjenkinson", "published": "2014-12-10T00:00:00+00:00", "url": "https://24ways.org/2014/making-sites-more-responsive-responsibly/", "topic": "code"} {"rowid": 46, "title": "Responsive Enhancement", "contents": "24 ways has been going strong for ten years. That\u2019s an aeon in internet timescales. Just think of all the changes we\u2019ve seen in that time: the rise of Ajax, the explosion of mobile devices, the unrecognisably changed landscape of front-end tooling.\n\nTools and technologies come and go, but one thing has remained constant for me over the past decade: progressive enhancement.\n\nProgressive enhancement isn\u2019t a technology. It\u2019s more like a way of thinking. Instead of thinking about the specifics of how a finished website might look, progressive enhancement encourages you to think about the fundamental meaning of what the website is providing. So instead of thinking of a website in terms of its ideal state in a modern browser on a nice widescreen device, progressive enhancement allows you to think about the core functionality in a more abstract way.\n\nOnce you\u2019ve figured out what the core functionality is \u2013 adding an item to a shopping cart, posting a message, sharing a photo \u2013 then you can enable that functionality in the simplest possible way. That usually means starting with good old-fashioned HTML. Links and forms are often all you need. Then, once you have the core functionality working in a basic way, you can start to enhance to make a progressively better experience for more modern browsers.\n\nThe advantage of working this way isn\u2019t just that your site will work in older browsers (albeit in a rudimentary way). It also ensures that if anything goes wrong in a modern browser, it won\u2019t be catastrophic.\n\nThere\u2019s a common misconception that progressive enhancement means that you\u2019ll spend your time dealing with older browsers, but in fact the opposite is true. Putting the basic functionality into place doesn\u2019t take very long at all. And once you\u2019ve done that, you\u2019re free to spend all your time experimenting with the latest and greatest browser technologies, secure in the knowledge that even if they aren\u2019t universally supported yet, that\u2019s OK: you\u2019ve already got your fallback in place.\n\nThe key to thinking about web development this way is realising that there isn\u2019t one final interface \u2013 there could be many, slightly different interfaces depending on the properties and capabilities of any particular user agent at any particular moment. And that\u2019s OK. Websites do not need to look the same in every browser.\n\nOnce you truly accept that, it\u2019s an immensely liberating idea. Instead of spending your time trying to make websites look the same in wildly varying browsers, you can spend your time making sure that the core functionality of what you build works everywhere, while providing the best possible experience for more capable browsers.\n\nAllow me to demonstrate with a simple example: navigation.\n\nStep one: core functionality\n\nLet\u2019s say we have a straightforward website about the twelve days of Christmas, with a page for each day. The core functionality is pretty clear:\n\n\n\tTo read about any particular day.\n\tTo browse from day to day.\n\n\nThe first is easily satisfied by marking up the text with headings, paragraphs and all the usual structural HTML elements. The second is satisfied by providing a list of good ol\u2019 hyperlinks.\n\nNow where\u2019s the best place to position this navigation list? Personally, I\u2019m a big fan of the jump-to-footer pattern. This puts the content first and the navigation second. At the top of the page there\u2019s a link with an href attribute pointing to the fragment identifier for the navigation.\n\n\n
    \n Menu\n ...\n
    \n \n\n\nSee the footer-anchor pattern in action.\n\nBecause it\u2019s nothing more than a hyperlink, this works in just about every browser since the dawn of the web. Following hyperlinks is what web browsers were made to do (hence the name).\n\nStep two: layout as an enhancement\n\nThe footer-anchor pattern is a particularly neat solution on small-screen devices, like mobile phones. Once more screen real estate is available, I can use the magic of CSS to reposition the navigation above the content. I could use position: absolute, flexbox or, in this case, display: table.\n\n@media all and (min-width: 35em) {\n .control {\n display: none;\n }\n body {\n display: table;\n }\n [role=\"navigation\"] {\n display: table-caption;\n columns: 6 15em;\n }\n}\n\nSee the styles for wider screens in action\n\nStep three: enhance!\n\nRight. At this point I\u2019m providing core functionality to everyone, and I\u2019ve got nice responsive styles for wider screens. I could stop here, but the real advantage of progressive enhancement is that I don\u2019t have to. From here on, I can go crazy adding all sorts of fancy enhancements for modern browsers, without having to worry about providing a fallback for older browsers \u2013 the fallback is already in place.\n\nWhat I\u2019d really like is to provide a swish off-canvas pattern for small-screen devices. Here\u2019s my plan:\n\n\n\tPosition the navigation under the main content.\n\tListen out for the .control links being activated and intercept that action.\n\tWhen those links are activated, toggle a class of .active on the body.\n\tIf the .active class exists, slide the content out to reveal the navigation.\n\n\nHere\u2019s the CSS for positioning the content and navigation:\n\n@media all and (max-width: 35em) {\n [role=\"main\"] {\n transition: all .25s;\n width: 100%;\n position: absolute;\n z-index: 2;\n top: 0;\n right: 0;\n }\n [role=\"navigation\"] {\n width: 75%;\n position: absolute;\n z-index: 1;\n top: 0;\n right: 0;\n }\n .active [role=\"main\"] {\n transform: translateX(-75%);\n }\n}\n\nIn my JavaScript, I\u2019m going to listen out for any clicks on the .control links and toggle the .active class on the body accordingly:\n\n(function (win, doc) {\n 'use strict';\n var linkclass = 'control',\n activeclass = 'active',\n toggleClassName = function (element, toggleClass) {\n var reg = new RegExp('(s|^)' + toggleClass + '(s|$)');\n if (!element.className.match(reg)) {\n element.className += ' ' + toggleClass;\n } else {\n element.className = element.className.replace(reg, '');\n }\n },\n navListener = function (ev) {\n ev = ev || win.event;\n var target = ev.target || ev.srcElement;\n if (target.className.indexOf(linkclass) !== -1) {\n ev.preventDefault();\n toggleClassName(doc.body, activeclass);\n }\n };\n doc.addEventListener('click', navListener, false);\n}(this, this.document));\n\nI\u2019m all set, right? Not so fast!\n\nCutting the mustard\n\nI\u2019ve made the assumption that addEventListener will be available in my JavaScript. That isn\u2019t a safe assumption. That\u2019s because JavaScript \u2013 unlike HTML or CSS \u2013 isn\u2019t fault-tolerant. If you use an HTML element or attribute that a browser doesn\u2019t understand, or if you use a CSS selector, property or value that a browser doesn\u2019t understand, it\u2019s no big deal. The browser will just ignore what it doesn\u2019t understand: it won\u2019t throw an error, and it won\u2019t stop parsing the file.\n\nJavaScript is different. If you make an error in your JavaScript, or use a JavaScript method or property that a browser doesn\u2019t recognise, that browser will throw an error, and it will stop parsing the file. That\u2019s why it\u2019s important to test for features before using them in JavaScript. That\u2019s also why it isn\u2019t safe to rely on JavaScript for core functionality.\n\nIn my case, I need to test for the existence of addEventListener:\n\n(function (win, doc) {\n if (!win.addEventListener) {\n return;\n }\n ...\n}(this, this.document));\n\nThe good folk over at the BBC call this kind of feature test cutting the mustard. If a browser passes the test, it cuts the mustard, and so it gets the enhancements. If a browser doesn\u2019t cut the mustard, it doesn\u2019t get the enhancements. And that\u2019s fine because, remember, websites don\u2019t need to look the same in every browser.\n\nI want to make sure that my off-canvas styles are only going to apply to mustard-cutting browsers. I\u2019m going to use JavaScript to add a class of .cutsthemustard to the document:\n\n(function (win, doc) {\n if (!win.addEventListener) {\n return;\n }\n ...\n var enhanceclass = 'cutsthemustard';\n doc.documentElement.className += ' ' + enhanceclass;\n}(this, this.document));\n\nNow I can use the existence of that class name to adjust my CSS:\n\n@media all and (max-width: 35em) {\n .cutsthemustard [role=\"main\"] {\n transition: all .25s;\n width: 100%;\n position: absolute;\n z-index: 2;\n top: 0;\n right: 0;\n }\n .cutsthemustard [role=\"navigation\"] {\n width: 75%;\n position: absolute;\n z-index: 1;\n top: 0;\n right: 0;\n }\n .cutsthemustard .active [role=\"main\"] {\n transform: translateX(-75%);\n }\n}\n\nSee the enhanced mustard-cutting off-canvas navigation. Remember, this only applies to small screens so you might have to squish your browser window.\n\nEnhance all the things!\n\nThis was a relatively simple example, but it illustrates the thinking behind progressive enhancement: once you\u2019re providing the core functionality to everyone, you\u2019re free to go crazy with all the latest enhancements for modern browsers.\n\nProgressive enhancement doesn\u2019t mean you have to provide all the same functionality to everyone \u2013 quite the opposite. That\u2019s why it\u2019s key to figure out early on what the core functionality is, and make sure that it can be provided with the most basic technology. But from that point on, you\u2019re free to add many more features that aren\u2019t mission-critical. You should reward more capable browsers by giving them more of those features, such as animation in CSS, geolocation in JavaScript, and new input types in HTML.\n\nLike I said, progressive enhancement isn\u2019t a technology. It\u2019s a way of thinking. Once you start thinking this way, you\u2019ll be prepared for whatever the next ten years throws at us.", "year": "2014", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2014-12-09T00:00:00+00:00", "url": "https://24ways.org/2014/responsive-enhancement/", "topic": "code"} {"rowid": 38, "title": "Websites of Christmas Past, Present and Future", "contents": "The websites of Christmas past\n\nThe first website was created at CERN. It was launched on 20 December 1990 (just in time for Christmas!), and it still works today, after twenty-four years. Isn\u2019t that incredible?!\n\nWhy does this website still work after all this time? I can think of a few reasons.\n\nFirst, the authors of this document chose HTML. Of course they couldn\u2019t have known back then the extent to which we would be creating documents in HTML, but HTML always had a lot going for it. It\u2019s built on top of plain text, which means it can be opened in any text editor, and it\u2019s pretty readable, even without any parsing.\n\nDespite the fact that HTML has changed quite a lot over the past twenty-four years, extensions to the specification have always been implemented in a backwards-compatible manner. Reading through the 1992 W3C document HTML Tags, you\u2019ll see just how it has evolved. We still have h1 \u2013 h6 elements, but I\u2019d not heard of the element before. Despite being deprecated since HTML2, it still works in several browsers. You can see it in action on my website.\n\nAs well as being written in HTML, there is no run-time compilation of code; the first website simply consists of HTML files transmitted over the web. Due to its lack of complexity, it stood a good chance of surviving in the turbulent World Wide Web.\n\nThat\u2019s all well and good for a simple, static website. But websites created today are increasingly interactive. Many require a login and provide experiences that are tailored to the individual user. This type of dynamic website requires code to be executed somewhere.\n\nTraditionally, dynamic websites would execute such code on the server, and transmit a simple HTML file to the user. As far as the browser was concerned, this wasn\u2019t much different from the first website, as the additional complexity all happened before the document was sent to the browser.\n\nDoing it all in the browser\n\nIn 2003, the first single page interface was created at slashdotslash.com. A single page interface or single page app is a website where the page is created in the browser via JavaScript. The benefit of this technique is that, after the initial page load, subsequent interactions can happen instantly, or very quickly, as they all happen in the browser.\n\nWhen software runs on the client rather than the server, it is often referred to as a fat client. This means that the bulk of the processing happens on the client rather than the server (which can now be thin).\n\nA fat client is preferred over a thin client because:\n\n\n\tIt takes some processing requirements away from the server, thereby reducing the cost of servers (a thin server requires cheaper, or fewer servers).\n\tThey can often continue working offline, provided no server communication is required to complete tasks after initial load.\n\tThe latency of internet communications is bypassed after initial load, as interactions can appear near instantaneous when compared to waiting for a response from the server.\n\n\nBut there are also some big downsides, and these are often overlooked:\n\n\n\tThey can\u2019t work without JavaScript. Obviously JavaScript is a requirement for any client-side code execution. And as the UK Government Digital Service discovered, 1.1% of their visitors did not receive JavaScript enhancements. Of that 1.1%, 81% had JavaScript enabled, but their browsers failed to execute it (possibly due to dropping the internet connection). If you care about 1.1% of your visitors, you should care about the non-JavaScript experience for your website.\n\tThe browser needs to do all the processing. This means that the hardware it runs on needs to be fast. It also means that we require all clients to have largely the same capabilities and browser APIs.\n\tThe initial payload is often much larger, and nothing will be rendered for the user until this payload has been fully downloaded and executed. If the connection drops at any point, or the code fails to execute owing to a bug, we\u2019re left with the non-JavaScript experience.\n\tThey are not easily indexed as every crawler now needs to run JavaScript just to receive the content of the website.\n\n\nThese are not merely edge case issues to shirk off. The first three issues will affect some of your visitors; the fourth affects everyone, including you.\n\nWhat problem are we trying to solve?\n\nSo what can be done to address these issues? Whereas fat clients solve some inherent issues with the web, they seem to create as many problems. When attempting to resolve any issue, it\u2019s always good to try to uncover the original problem and work forwards from there. One of the best ways to frame a problem is as a user story. A user story considers the who, what and why of a need. Here\u2019s a template:\n\n\n\tAs a {who} I want {what} so that {why}\n\n\nI haven\u2019t got a specific project in mind, so let\u2019s refer to the who as user. Here\u2019s one that could explain the use of thick clients.\n\n\n\tAs a user I want the site to respond to my actions quickly so that I get immediate feedback when I do something.\n\n\nThis user story could probably apply to a great number of websites, but so could this:\n\n\n\tAs a user I want to get to the content quickly, so that I don\u2019t have to wait too long to find out what the site is all about or get the content I need.\n\n\nA better solution\n\nHow can we balance both these user needs? How can we have a website that loads fast, and also reacts fast? The solution is to have a thick server, that serves the complete document, and then a thick client, that manages subsequent actions and replaces parts of the page. What we\u2019re talking about here is simply progressive enhancement, but from the user\u2019s perspective.\n\nThe initial payload contains the entire document. At this point, all interactions would happen in a traditional way using links or form elements. Then, once we\u2019ve downloaded the JavaScript (asynchronously, after load) we can enhance the experience with JavaScript interactions. If for whatever reason our JavaScript fails to download or execute, it\u2019s no biggie \u2013 we\u2019ve already got a fully functioning website. If an API that we need isn\u2019t available in this browser, it\u2019s not a problem. We just fall back to the basic experience.\n\nThis second point, of having some minimum requirement for an enhanced experience, is often referred to as cutting the mustard, first used in this sense by the BBC News team. Essentially it\u2019s an if statement like this:\n\nif('querySelector' in document\n && 'localStorage' in window\n && 'addEventListener' in window) {\n // bootstrap the JavaScript application\n }\n\nThis code states that the browser must support the following methods before downloading and executing the JavaScript:\n\n\n\tdocument.querySelector (can it find elements by CSS selectors)\n\twindow.localStorage (can it store strings)\n\twindow.addEventListener (can it bind to events in a standards-compliant way)\n\n\nThese three properties are what the BBC News team decided to test for, as they are present in their website\u2019s JavaScript. Each website will have its own requirements. The last method, window.addEventListener is in interesting one. Although it\u2019s simple to bind to events on IE8 and earlier, these browsers have very inconsistent support for standards. Making any JavaScript-heavy website work on IE8 and earlier is a painful exercise, and comes at a cost to all users on other browsers, as they\u2019ll download unnecessary code to patch support for IE.\n\n JavaScript API support by browser.\n\nI discovered that IE8 supports 12% of the current JavaScript APIs, while IE9 supports 16%, and IE10 51%. It seems, then, that IE10 could be the earliest version of IE that I\u2019d like to develop JavaScript for. That doesn\u2019t mean that users on browsers earlier than 10 can\u2019t use the website. On the contrary, they get the core experience, and because it\u2019s just HTML and CSS, it\u2019s much more likely to be bug-free, and could even provide a better experience than trying to run JavaScript in their browser. They receive the thin client experience.\n\nBy reducing the number of platforms that our enhanced JavaScript version supports, we can better focus our efforts on those platforms and offer an even greater experience to those users. But we can only do that if we use progressive enhancement. Otherwise our website would be completely broken for all other users.\n\nSo what we have is a thick server, capable of serving the entire website to our users, complete with all core functionality needed for our users to complete their tasks; and we have a thick client on supported browsers, which can bring an even greater experience to those users.\n\nThis is all transparent to users. They may notice that the website seems snappier on the new iPhone they received for Christmas than on the Windows 7 machine they got five years ago, but then they probably expected it to be faster on their iPhone anyway.\n\nIsn\u2019t this just more work?\n\nIt\u2019s true that making a thick server and a thick client is more work than just making one or the other. But there are some big advantages:\n\n\n\tThe website works for everyone.\n\tYou can decide when users get the enhanced experience.\n\tYou can enhance features in an iterative (or agile) manner.\n\tWhen the website breaks, it doesn\u2019t break down.\n\tThe more you practise this approach, the quicker you will become.\n\n\nThe websites of Christmas present\n\nThe best way to discover websites using this technique of progressive enhancement is to disable JavaScript and see if the website breaks. I use the Web Developer extension, which is available for Chrome and Firefox. It lets me quickly disable JavaScript.\n\n Web Developer extension.\n\n24 ways works with and without JavaScript. Try using the menu icon to view the navigation. Without JavaScript, it\u2019s a jump link to the bottom of the page, but with JavaScript, the menu slides in from the right.\n\n 24 ways navigation with JavaScript disabled.\n\n 24 ways navigation with working JavaScript.\n\nGoogle search will also work without JavaScript. You won\u2019t get instant search results or any prerendering, because those are enhancements.\n\nFor a more app-like example, try using Twitter. Without JavaScript, it still works, and looks nearly identical. But when you load JavaScript, links open in modal windows and all pages are navigated much quicker, as only the content that has changed is loaded. You can read about how they achieved this in Twitter\u2019s blog posts Improving performance on twitter.com and Implementing pushState for twitter.com.\n\nUnfortunately Facebook doesn\u2019t use progressive enhancement, which not only means that the website doesn\u2019t work without JavaScript, but it takes longer to load. I tested it on WebPagetest and if you compare the load times of Twitter and Facebook, you\u2019ll notice that, despite putting similar content on the page, Facebook takes two and a half times longer to render the core content on the page.\n\n Facebook takes two and a half times longer to load than Twitter.\n\nWebsites of Christmas yet to come\n\nEvery project is different, and making a website that enjoys a long life, or serves a larger number of users may or may not be a high priority. But I hope I\u2019ve convinced you that it certainly is possible to look to the past and future simultaneously, and that there can be significant advantages to doing so.", "year": "2014", "author": "Josh Emerson", "author_slug": "joshemerson", "published": "2014-12-08T00:00:00+00:00", "url": "https://24ways.org/2014/websites-of-christmas-past-present-and-future/", "topic": "code"} {"rowid": 37, "title": "JavaScript Modules the ES6 Way", "contents": "JavaScript admittedly has plenty of flaws, but one of the largest and most prominent is the lack of a module system: a way to split up your application into a series of smaller files that can depend on each other to function correctly. \n\nThis is something nearly all other languages come with out of the box, whether it be Ruby\u2019s require, Python\u2019s import, or any other language you\u2019re familiar with. Even CSS has @import! JavaScript has nothing of that sort, and this has caused problems for application developers as they go from working with small websites to full client-side applications. Let\u2019s be clear: it doesn\u2019t mean the new module system in the upcoming version of JavaScript won\u2019t be useful to you if you\u2019re building smaller websites rather than the next Instagram.\n\nThankfully, the lack of a module system will soon be a problem of the past. The next version of JavaScript, ECMAScript 6, will bring with it a full-featured module and dependency management solution for JavaScript. The bad news is that it won\u2019t be landing in browsers for a while yet \u2013 but the good news is that the specification for the module system and how it will look has been finalised. The even better news is that there are tools available to get it all working in browsers today without too much hassle. In this post I\u2019d like to give you the gift of JS modules and show you the syntax, and how to use them in browsers today. It\u2019s much simpler than you might think.\n\nWhat is ES6?\n\nECMAScript is a scripting language that is standardised by a company called Ecma International. JavaScript is an implementation of ECMAScript. ECMAScript 6 is simply the next version of the ECMAScript standard and, hence, the next version of JavaScript. The spec aims to be fully comfirmed and complete by the end of 2014, with a target initial release date of June 2015. It\u2019s impossible to know when we will have full feature support across the most popular browsers, but already some ES6 features are landing in the latest builds of Chrome and Firefox. You shouldn\u2019t expect to be able to use the new features across browsers without some form of additional tooling or library for a while yet.\n\nThe ES6 module spec\n\nThe ES6 module spec was fully confirmed in July 2014, so all the syntax I will show you in this article is not expected to change. I\u2019ll first show you the syntax and the new APIs being added to the language, and then look at how to use them today. There are two parts to the new module system. The first is the syntax for declaring modules and dependencies in your JS files, and the second is a programmatic API for loading in modules manually. The first is what most people are expected to use most of the time, so it\u2019s what I\u2019ll focus on more.\n\nModule syntax\n\nThe key thing to understand here is that modules have two key components. First, they have dependencies. These are things that the module you are writing depends on to function correctly. For example, if you were building a carousel module that used jQuery, you would say that jQuery is a dependency of your carousel. You import these dependencies into your module, and we\u2019ll see how to do that in a minute. Second, modules have exports. These are the functions or variables that your module exposes publicly to anything that imports it. Using jQuery as the example again, you could say that jQuery exports the $ function. Modules that depend on and hence import jQuery get access to the $ function, because jQuery exports it.\n\nAnother important thing to note is that when I discuss a module, all I really mean is a JavaScript file. There\u2019s no extra syntax to use other than the new ES6 syntax. Once ES6 lands, modules and files will be analogous.\n\nNamed exports\n\nModules can export multiple objects, which can be either plain old variables or JavaScript functions. You denote something to be exported with the export keyword:\n\nexport function double(x) {\n return x + x;\n};\n\n\nYou can also store something in a variable then export it. If you do that, you have to wrap the variable in a set of curly braces.\n\nvar double = function(x) {\n return x + x;\n}\n\nexport { double };\n\nA module can then import the double function like so:\n\nimport { double } from 'mymodule';\ndouble(2); // 4\n\nAgain, curly braces are required around the variable you would like to import. It\u2019s also important to note that from 'mymodule' will look for a file called mymodule.js in the same directory as the file you are requesting the import from. There is no need to add the .js extension.\n\nThe reason for those extra braces is that this syntax lets you export multiple variables:\n\nvar double = function(x) {\n return x + x;\n}\n\nvar square = function(x) {\n return x * x;\n}\n\nexport { double, square }\n\nI personally prefer this syntax over the export function \u2026, but only because it makes it much clearer to me what the module exports. Typically I will have my export {\u2026} line at the bottom of the file, which means I can quickly look in one place to determine what the module is exporting.\n\nA file importing both double and square can do so in just the way you\u2019d expect:\n\nimport { double, square } from 'mymodule';\ndouble(2); // 4\nsquare(3); // 9\n\nWith this approach you can\u2019t easily import an entire module and all its methods. This is by design \u2013 it\u2019s much better and you\u2019re encouraged to import just the functions you need to use.\n\nDefault exports\n\nAlong with named exports, the system also lets a module have a default export. This is useful when you are working with a large library such as jQuery, Underscore, Backbone and others, and just want to import the entire library. A module can define its default export (it can only ever have one default export) like so:\n\nexport default function(x) {\n return x + x;\n}\n\nAnd that can be imported:\n\nimport double from 'mymodule';\ndouble(2); // 4\n\n\nThis time you do not use the curly braces around the name of the object you are importing. Also notice how you can name the import whatever you\u2019d like. Default exports are not named, so you can import them as anything you like:\n\nimport christmas from 'mymodule';\nchristmas(2); // 4\n\nThe above is entirely valid.\n\nAlthough it\u2019s not something that is used too often, a module can have both named exports and a default export, if you wish.\n\nOne of the design goals of the ES6 modules spec was to favour default exports. There are many reasons behind this, and there is a very detailed discussion on the ES Discuss site about it. That said, if you find yourself preferring named exports, that\u2019s fine, and you shouldn\u2019t change that to meet the preferences of those designing the spec.\n\nProgrammatic API\n\nAlong with the syntax above, there is also a new API being added to the language so you can programmatically import modules. It\u2019s pretty rare you would use this, but one obvious example is loading a module conditionally based on some variable or property. You could easily import a polyfill, for example, if the user\u2019s browser didn\u2019t support a feature your app relied on. An example of doing this is:\n\nif(someFeatureNotSupported) {\n System.import('my-polyfill').then(function(myPolyFill) {\n // use the module from here\n });\n}\n\nSystem.import will return a promise, which, if you\u2019re not familiar, you can read about in this excellent article on HTMl5 Rocks by Jake Archibald. A promise basically lets you attach callback functions that are run when the asynchronous operation (in this case, System.import), is complete.\n\nThis programmatic API opens up a lot of possibilities and will also provide hooks to allow you to register callbacks that will run at certain points in the lifetime of a module. Those hooks and that syntax are slightly less set in stone, but when they are confirmed they will provide really useful functionality. For example, you could write code that would run every module that you import through something like JSHint before importing it. In development that would provide you with an easy way to keep your code quality high without having to run a command line watch task.\n\nHow to use it today\n\nIt\u2019s all well and good having this new syntax, but right now it won\u2019t work in any browser \u2013 and it\u2019s not likely to for a long time. Maybe in next year\u2019s 24 ways there will be an article on how you can use ES6 modules with no extra work in the browser, but for now we\u2019re stuck with a bit of extra work.\n\nES6 module transpiler\n\nOne solution is to use the ES6 module transpiler, a compiler that lets you write your JavaScript using the ES6 module syntax (actually a subset of it \u2013 not quite everything is supported, but the main features are) and have it compiled into either CommonJS-style code (CommonJS is the module specification that NodeJS and Browserify use), or into AMD-style code (the spec RequireJS uses). There are also plugins for all the popular build tools, including Grunt and Gulp.\n\nThe advantage of using this transpiler is that if you are already using a tool like RequireJS or Browserify, you can drop the transpiler in, start writing in ES6 and not worry about any additional work to make the code work in the browser, because you should already have that set up already. If you don\u2019t have any system in place for handling modules in the browser, using the transpiler doesn\u2019t really make sense. Remember, all this does is convert ES6 module code into CommonJS- or AMD-compliant JavaScript. It doesn\u2019t do anything to help you get that code running in the browser, but if you have that part sorted it\u2019s a really nice addition to your workflow. If you would like a tutorial on how to do this, I wrote a post back in June 2014 on using ES6 with the ES6 module transpiler.\n\nSystemJS\n\nAnother solution is SystemJS. It\u2019s the best solution in my opinion, particularly if you are starting a new project from scratch, or want to use ES6 modules on a project where you have no current module system in place. SystemJS is a spec-compliant universal module loader: it loads ES6 modules, AMD modules, CommonJS modules, as well as modules that just add a variable to the global scope (window, in the browser).\n\nTo load in ES6 files, SystemJS also depends on two other libraries: the ES6 module loader polyfill; and Traceur. Traceur is best accessed through the bower-traceur package, as the main repository doesn\u2019t have an easy to find downloadable version. The ES6 module load polyfill implements System.import, and lets you load in files using it. Traceur is an ES6-to-ES5 module loader. It takes code written in ES6, the newest version of JavaScript, and transpiles it into ES5, the version of JavaScript widely implemented in browsers. The advantage of this is that you can play with the new features of the language today, even though they are not supported in browsers. The drawback is that you have to run all your files through Traceur every time you save them, but this is easily automated. Additionally, if you use SystemJS, the Traceur compilation is done automatically for you.\n\nAll you need to do to get SystemJS running is to add a <script> element to load SystemJS into your webpage. It will then automatically load the ES6 module loader and Traceur files when it needs them. In your HTML you then need to use System.import to load in your module:\n\n<script>\n System.import('./app');\n</script>\n\nWhen you load the page, app.js will be asynchronously loaded. Within app.js, you can now use ES6 modules. SystemJS will detect that the file is an ES6 file, automatically load Traceur, and compile the file into ES5 so that it works in the browser. It does all this dynamically in the browser, but there are tools to bundle your application in production, so it doesn\u2019t make a lot of requests on the live site. In development though, it makes for a really nice workflow.\n\nWhen working with SystemJS and modules in general, the best approach is to have a main module (in our case app.js) that is the main entry point for your application. app.js should then be responsible for loading all your application\u2019s modules. This forces you to keep your application organised by only loading one file initially, and having the rest dealt with by that file.\n\nSystemJS also provides a workflow for bundling your application together into one file.\n\nConclusion\n\nES6 modules may be at least six months to a year away (if not more) but that doesn\u2019t mean they can\u2019t be used today. Although there is an overhead to using them now \u2013 with the work required to set up SystemJS, the module transpiler, or another solution \u2013 that doesn\u2019t mean it\u2019s not worthwhile. Using any module system in the browser, whether that be RequireJS, Browserify or another alternative, requires extra tooling and libraries to support it, and I would argue that the effort to set up SystemJS is no greater than that required to configure any other tool. It also comes with the extra benefit that when the syntax is supported in browsers, you get a free upgrade. You\u2019ll be able to remove SystemJS and have everything continue to work, backed by the native browser solution.\n\nIf you are starting a new project, I would strongly advocate using ES6 modules. It is a syntax and specification that is not going away at all, and will soon be supported in browsers. Investing time in learning it now will pay off hugely further down the road.\n\nFurther reading\n\nIf you\u2019d like to delve further into ES6 modules (or ES6 generally) and using them today, I recommend the following resources:\n\n\n\tECMAScript 6 modules: the final syntax by Axel Rauschmayer\n\tPractical Workflows for ES6 Modules by Guy Bedford\n\tECMAScript 6 resources for the curious JavaScripter by Addy Osmani\n\tTracking ES6 support by Addy Osmani\n\tES6 Tools List by Addy Osmani\n\tUsing Grunt and the ES6 Module Transpiler by Thomas Boyt\n\tJavaScript Modules and Dependencies with jspm by myself\n\tUsing ES6 Modules Today by Guy Bedford", "year": "2014", "author": "Jack Franklin", "author_slug": "jackfranklin", "published": "2014-12-03T00:00:00+00:00", "url": "https://24ways.org/2014/javascript-modules-the-es6-way/", "topic": "code"} {"rowid": 31, "title": "Dealing with Emergencies in Git", "contents": "The stockings were hung by the chimney with care,\nIn hopes that version control soon would be there.\n\nThis summer I moved to the UK with my partner, and the onslaught of the Christmas holiday season began around the end of October (October!). It does mean that I\u2019ve had more than a fair amount of time to come up with horrible Git analogies for this article. Analogies, metaphors, and comparisons help the learner hook into existing mental models about how a system works. They only help, however, if the learner has enough familiarity with the topic at hand to make the connection between the old and new information.\n\nLet\u2019s start by painting an updated version of Clement Clarke Moore\u2019s Christmas living room. Empty stockings are hung up next to the fireplace, waiting for Saint Nicholas to come down the chimney and fill them with small treats. Holiday treats are scattered about. A bowl of mixed nuts, the holiday nutcracker, and a few clementines. A string of coloured lights winds its way up an evergreen.\n\nPerhaps a few of these images are familiar, or maybe they\u2019re just settings you\u2019ve seen in a movie. It doesn\u2019t really matter what the living room looks like though. The important thing is to ground yourself in your own experiences before tackling a new subject. Instead of trying to brute-force your way into new information, as an adult learner constantly ask yourself: \u2018What is this like? What does this remind me of? What do I already know that I can use to map out this new territory?\u2019 It\u2019s okay if the map isn\u2019t perfect. As you refine your understanding of a new topic, you\u2019ll outgrow the initial metaphors, analogies, and comparisons.\n\nWith apologies to Mr. Moore, let\u2019s give it a try.\n\nGetting Interrupted in Git\n\nWhen on the roof there arose such a clatter!\n\nYou\u2019re happily working on your software project when all of a sudden there are freaking reindeer on the roof! Whatever you\u2019ve been working on is going to need to wait while you investigate the commotion.\n\nIf you\u2019ve got even a little bit of experience working with Git, you know that you cannot simply change what you\u2019re working on in times of emergency. If you\u2019ve been doing work, you have a dirty working directory and you cannot change branches, or push your work to a remote repository while in this state.\n\nUp to this point, you\u2019ve probably dealt with emergencies by making a somewhat useless commit with a message something to the effect of \u2018switching branches for a sec\u2019. This isn\u2019t exactly helpful to future you, as commits should really contain whole ideas of completed work. If you get interrupted, especially if there are reindeer on the roof, the chances are very high that you weren\u2019t finished with what you were working on.\n\nYou don\u2019t need to make useless commits though. Instead, you can use the stash command. This command allows you to temporarily set aside all of your changes so that you can come back to them later. In this sense, stash is like setting your book down on the side table (or pushing the cat off your lap) so you can go investigate the noise on the roof. You aren\u2019t putting your book away though, you\u2019re just putting it down for a moment so you can come back and find it exactly the way it was when you put it down.\n\nLet\u2019s say you\u2019ve been working in the branch waiting-for-st-nicholas, and now you need to temporarily set aside your changes to see what the noise was on the roof:\n\n$ git stash\n\nAfter running this command, all uncommitted work will be temporarily removed from your working directory, and you will be returned to whatever state you were in the last time you committed your work.\n\nWith the book safely on the side table, and the cat safely off your lap, you are now free to investigate the noise on the roof. It turns out it\u2019s not reindeer after all, but just your boss who thought they\u2019d help out by writing some code on the project you\u2019ve been working on. Bless. Rolling your eyes, you agree to take a look and see what kind of mischief your boss has gotten themselves into this time.\n\nYou fetch an updated list of branches from the remote repository, locate the branch your boss had been working on, and checkout a local copy:\n\n$ git fetch\n$ git branch -r\n$ git checkout -b helpful-boss-branch origin/helpful-boss-branch\n\nYou are now in a local copy of the branch where you are free to look around, and figure out exactly what\u2019s going on.\n\nYou sigh audibly and say, \u2018Okay. Tell me what was happening when you first realised you\u2019d gotten into a mess\u2019 as you look through the log messages for the branch.\n\n$ git log --oneline\n$ git log\n\nBy using the log command you will be able to review the history of the branch and find out the moment right before your boss ended up stuck on your roof.\n\nYou may also want to compare the work your boss has done to the main branch for your project. For this article, we\u2019ll assume the main branch is named master.\n\n$ git diff master\n\nLooking through the commits, you may be able to see that things started out okay but then took a turn for the worse.\n\nChecking out a single commit\n\nUsing commands you\u2019re already familiar with, you can rewind through history and take a look at the state of the code at any moment in time by checking out a single commit, just like you would a branch.\n\nUsing the log command, locate the unique identifier (commit hash) of the commit you want to investigate. For example, let\u2019s say the unique identifier you want to checkout is 25f6d7f.\n\n$ git checkout 25f6d7f\n\nNote: checking out '25f6d7f'.\n\nYou are in 'detached HEAD' state. You can look around,\nmake experimental changes and commit them, and you can\ndiscard any commits you make in this state without\nimpacting any branches by performing another checkout.\n\nIf you want to create a new branch to retain commits you create, you may do so (now or later) by using @-b@ with the checkout command again. Example:\n\n$ git checkout -b new_branch_name\n\nHEAD is now at 25f6d7f... Removed first paragraph.\n\nThis is usually where people start to panic. Your boss screwed something up, and now your HEAD is detached. Under normal circumstances, these words would be a very good reason to panic.\n\nTake a deep breath. Nothing bad is going to happen. Being in a detached HEAD state just means you\u2019ve temporarily disconnected from a known chain of events. In other words, you\u2019re currently looking at the middle of a story (or branch) about what happened \u2013 and you\u2019re not at the endpoint for this particular story.\n\nGit allows you to view the history of your repository as a timeline (technically it\u2019s a directed acyclic graph). When you make commits which are not associated with a branch, they are essentially inaccessible once you return to a known branch. If you make commits while you\u2019re in a detached HEAD state, and then try to return to a known branch, Git will give you a warning and tell you how to save your work.\n\n$ git checkout master\n\nWarning: you are leaving 1 commit behind, not connected to\nany of your branches:\n\n 7a85788 Your witty holiday commit message.\n\nIf you want to keep them by creating a new branch, this may be a good time to do so with:\n\n$ git branch new_branch_name 7a85788\n\nSwitched to branch 'master'\nYour branch is up-to-date with 'origin/master'.\n\nSo, if you want to save the commits you\u2019ve made while in a detached HEAD state, you simply need to put them on a new branch.\n\n$ git branch saved-headless-commits 7a85788\n\nWith this trick under your belt, you can jingle around in history as much as you\u2019d like. It\u2019s not like sliding around on a timeline though. When you checkout a specific commit, you will only have access to the history from that point backwards in time. If you want to move forward in history, you\u2019ll need to move back to the branch tip by checking out the branch again.\n\n$ git checkout helpful-boss-branch\n\nYou\u2019re now back to the present. Your HEAD is now pointing to the endpoint of a known branch, and so it is no longer detached. Any changes you made while on your adventure are safely stored in a new branch, assuming you\u2019ve followed the instructions Git gave you. That wasn\u2019t so scary after all, now, was it?\n\nBack to our reindeer problem.\n\nIf your boss is anything like the bosses I\u2019ve worked with, chances are very good that at least some of their work is worth salvaging. Depending on how your repository is structured, you\u2019ll want to capture the good work using one of several different methods.\n\nBack in the living room, we\u2019ll use our bowl of nuts to illustrate how you can rescue a tiny bit of work.\n\nSaving just one commit\n\nAbout that bowl of nuts. If you\u2019re like me, you probably had some favourite kinds of nuts from an assorted collection. Walnuts were generally the most satisfying to crack open. So, instead of taking the entire bowl of nuts and dumping it into a stocking (merging the stocking and the bowl of nuts), we\u2019re just going to pick out one nut from the bowl. In Git terms, we\u2019re going to cherry-pick a commit and save it to another branch.\n\nFirst, checkout the main branch for your development work. From this branch, create a new branch where you can copy the changes into.\n\n$ git checkout master\n$ git checkout -b rescue-the-boss\n\nFrom your boss\u2019s branch, helpful-boss-branch locate the commit you want to keep.\n\n$ git log --oneline helpful-boss-branch\n\nLet\u2019s say the commit ID you want to keep is e08740b. From your rescue branch, use the command cherry-pick to copy the changes into your current branch.\n\n$ git cherry-pick e08740b\n\nIf you review the history of your current branch again, you will see you now also have the changes made in the commit in your boss\u2019s branch.\n\nAt this point you might need to make a few additional fixes to help your boss out. (You\u2019re angling for a bonus out of all this. Go the extra mile.) Once you\u2019ve made your additional changes, you\u2019ll need to add that work to the branch as well.\n\n$ git add [filename(s)]\n$ git commit -m \"Building on boss's work to improve feature X.\"\n\nGo ahead and test everything, and make sure it\u2019s perfect. You don\u2019t want to introduce your own mistakes during the rescue mission!\n\nUploading the fixed branch\n\nThe next step is to upload the new branch to the remote repository so that your boss can download it and give you a huge bonus for helping you fix their branch.\n\n$ git push -u origin rescue-the-boss\n\nCleaning up and getting back to work\n\nWith your boss rescued, and your bonus secured, you can now delete the local temporary branches.\n\n$ git branch --delete rescue-the-boss\n$ git branch --delete helpful-boss-branch\n\nAnd settle back into your chair to wait for Saint Nicholas with your book, your branch, and possibly your cat.\n\n$ git checkout waiting-for-st-nicholas\n$ git stash pop\n\nYour working directory has been returned to exactly the same state you were in at the beginning of the article.\n\nHaving fun with analogies\n\nI\u2019ve had a bit of fun with analogies in this article. But sometimes those little twists on ideas can really help someone pick up a new idea (git stash: it\u2019s like when Christmas comes around and everyone throws their fashion sense out the window and puts on a reindeer sweater for the holiday party; or git bisect: it\u2019s like trying to find that one broken light on the string of Christmas lights). It doesn\u2019t matter if the analogy isn\u2019t perfect. It\u2019s just a way to give someone a temporary hook into a concept in a way that makes the concept accessible while the learner becomes comfortable with it. As the learner\u2019s comfort increases, the analogies can drop away, making room for the technically correct definition of how something works.\n\nOr, if you\u2019re like me, you can choose to never grow old and just keep mucking about in the analogies. I\u2019d argue it\u2019s a lot more fun to play with a string of Christmas lights and some holiday cheer than a directed acyclic graph anyway.", "year": "2014", "author": "Emma Jane Westby", "author_slug": "emmajanewestby", "published": "2014-12-02T00:00:00+00:00", "url": "https://24ways.org/2014/dealing-with-emergencies-in-git/", "topic": "code"} {"rowid": 18, "title": "Grunt for People Who Think Things Like Grunt are Weird and Hard", "contents": "Front-end developers are often told to do certain things:\n\n\n\tWork in as small chunks of CSS and JavaScript as makes sense to you, then concatenate them together for the production website.\n\tCompress your CSS and minify your JavaScript to make their file sizes as small as possible for your production website.\n\tOptimize your images to reduce their file size without affecting quality.\n\tUse Sass for CSS authoring because of all the useful abstraction it allows.\n\n\nThat\u2019s not a comprehensive list of course, but those are the kind of things we need to do. You might call them tasks.\n\nI bet you\u2019ve heard of Grunt. Well, Grunt is a task runner. Grunt can do all of those things for you. Once you\u2019ve got it set up, which isn\u2019t particularly difficult, those things can happen automatically without you having to think about them again.\n\nBut let\u2019s face it: Grunt is one of those fancy newfangled things that all the cool kids seem to be using but at first glance feels strange and intimidating. I hear you. This article is for you.\n\nLet\u2019s nip some misconceptions in the bud right away\n\nPerhaps you\u2019ve heard of Grunt, but haven\u2019t done anything with it. I\u2019m sure that applies to many of you. Maybe one of the following hang-ups applies to you.\n\nI don\u2019t need the things Grunt does\n\nYou probably do, actually. Check out that list up top. Those things aren\u2019t nice-to-haves. They are pretty vital parts of website development these days. If you already do all of them, that\u2019s awesome. Perhaps you use a variety of different tools to accomplish them. Grunt can help bring them under one roof, so to speak. If you don\u2019t already do all of them, you probably should and Grunt can help. Then, once you are doing those, you can keep using Grunt to do more for you, which will basically make you better at doing your job.\n\nGrunt runs on Node.js \u2014 I don\u2019t know Node\n\nYou don\u2019t have to know Node. Just like you don\u2019t have to know Ruby to use Sass. Or PHP to use WordPress. Or C++ to use Microsoft Word.\n\nI have other ways to do the things Grunt could do for me\n\nAre they all organized in one place, configured to run automatically when needed, and shared among every single person working on that project? Unlikely, I\u2019d venture.\n\nGrunt is a command line tool \u2014 I\u2019m just a designer\n\nI\u2019m a designer too. I prefer native apps with graphical interfaces when I can get them. But I don\u2019t think that\u2019s going to happen with Grunt1.\n\nThe extent to which you need to use the command line is:\n\n\n\tNavigate to your project\u2019s directory.\n\tType grunt and press Return.\n\n\nAfter set-up, that is, which again isn\u2019t particularly difficult.\n\nOK. Let\u2019s get Grunt installed\n\nNode is indeed a prerequisite for Grunt. If you don\u2019t have Node installed, don\u2019t worry, it\u2019s very easy. You literally download an installer and run it. Click the big Install button on the Node website.\n\nYou install Grunt on a per-project basis. Go to your project\u2019s folder. It needs a file there named package.json at the root level. You can just create one and put it there.\n\n package.json at root\n\nThe contents of that file should be this:\n\n{\n \"name\": \"example-project\",\n \"version\": \"0.1.0\",\n \"devDependencies\": {\n \"grunt\": \"~0.4.1\"\n }\n}\n\nFeel free to change the name of the project and the version, but the devDependencies thing needs to be in there just like that.\n\nThis is how Node does dependencies. Node has a package manager called NPM (Node packaged modules) for managing Node dependencies (like a gem for Ruby if you\u2019re familiar with that). You could even think of it a bit like a plug-in for WordPress.\n\nOnce that package.json file is in place, go to the terminal and navigate to your folder. Terminal rubes like me do it like this:\n\n Terminal rube changing directories\n\nThen run the command:\n\nnpm install\n\nAfter you\u2019ve run that command, a new folder called node_modules will show up in your project.\n\n Example of node_modules folder\n\nThe other files you see there, README.md and LICENSE are there because I\u2019m going to put this project on GitHub and that\u2019s just standard fare there.\n\nThe last installation step is to install the Grunt CLI (command line interface). That\u2019s what makes the grunt command in the terminal work. Without it, typing grunt will net you a \u201cCommand Not Found\u201d-style error. It is a separate installation for efficiency reasons. Otherwise, if you had ten projects you\u2019d have ten copies of Grunt CLI.\n\nThis is a one-liner again. Just run this command in the terminal:\n\nnpm install -g grunt-cli\n\nYou should close and reopen the terminal as well. That\u2019s a generic good practice to make sure things are working right. Kinda like restarting your computer after you install a new application was in the olden days.\n\nLet\u2019s make Grunt concatenate some files\n\nPerhaps in our project there are three separate JavaScript files:\n\n\n\tjquery.js \u2013 The library we are using.\n\tcarousel.js \u2013 A jQuery plug-in we are using.\n\tglobal.js \u2013 Our authored JavaScript file where we configure and call the plug-in.\n\n\nIn production, we would concatenate all those files together for performance reasons (one request is better than three). We need to tell Grunt to do this for us.\n\nBut wait. Grunt actually doesn\u2019t do anything all by itself. Remember Grunt is a task runner. The tasks themselves we will need to add. We actually haven\u2019t set up Grunt to do anything yet, so let\u2019s do that.\n\nThe official Grunt plug-in for concatenating files is grunt-contrib-concat. You can read about it on GitHub if you want, but all you have to do to use it on your project is to run this command from the terminal (it will henceforth go without saying that you need to run the given commands from your project\u2019s root folder):\n\nnpm install grunt-contrib-concat --save-dev\n\nA neat thing about doing it this way: your package.json file will automatically be updated to include this new dependency. Open it up and check it out. You\u2019ll see a new line:\n\n\"grunt-contrib-concat\": \"~0.3.0\"\n\nNow we\u2019re ready to use it. To use it we need to start configuring Grunt and telling it what to do.\n\nYou tell Grunt what to do via a configuration file named Gruntfile.js2\n\nJust like our package.json file, our Gruntfile.js has a very special format that must be just right. I wouldn\u2019t worry about what every word of this means. Just check out the format:\n\nmodule.exports = function(grunt) {\n\n // 1. All configuration goes here \n grunt.initConfig({\n pkg: grunt.file.readJSON('package.json'),\n\n concat: {\n // 2. Configuration for concatinating files goes here.\n }\n\n });\n\n // 3. Where we tell Grunt we plan to use this plug-in.\n grunt.loadNpmTasks('grunt-contrib-concat');\n\n // 4. Where we tell Grunt what to do when we type \"grunt\" into the terminal.\n grunt.registerTask('default', ['concat']);\n\n};\n\nNow we need to create that configuration. The documentation can be overwhelming. Let\u2019s focus just on the very simple usage example.\n\nRemember, we have three JavaScript files we\u2019re trying to concatenate. We\u2019ll list file paths to them under src in an array of file paths (as quoted strings) and then we\u2019ll list a destination file as dest. The destination file doesn\u2019t have to exist yet. It will be created when this task runs and squishes all the files together.\n\nBoth our jquery.js and carousel.js files are libraries. We most likely won\u2019t be touching them. So, for organization, we\u2019ll keep them in a /js/libs/ folder. Our global.js file is where we write our own code, so that will be right in the /js/ folder. Now let\u2019s tell Grunt to find all those files and squish them together into a single file named production.js, named that way to indicate it is for use on our real live website.\n\nconcat: { \n dist: {\n src: [\n 'js/libs/*.js', // All JS in the libs folder\n 'js/global.js' // This specific file\n ],\n dest: 'js/build/production.js',\n }\n}\n\nNote: throughout this article there will be little chunks of configuration code like above. The intention is to focus in on the important bits, but it can be confusing at first to see how a particular chunk fits into the larger file. If you ever get confused and need more context, refer to the complete file.\n\nWith that concat configuration in place, head over to the terminal, run the command:\n\ngrunt\n\nand watch it happen! production.js will be created and will be a perfect concatenation of our three files. This was a big aha! moment for me. Feel the power course through your veins. Let\u2019s do more things!\n\nLet\u2019s make Grunt minify that JavaScript\n\nWe have so much prep work done now, adding new tasks for Grunt to run is relatively easy. We just need to:\n\n\n\tFind a Grunt plug-in to do what we want\n\tLearn the configuration style of that plug-in\n\tWrite that configuration to work with our project\n\n\nThe official plug-in for minifying code is grunt-contrib-uglify. Just like we did last time, we just run an NPM command to install it:\n\nnpm install grunt-contrib-uglify --save-dev\n\nThen we alter our Gruntfile.js to load the plug-in:\n\ngrunt.loadNpmTasks('grunt-contrib-uglify');\n\nThen we configure it:\n\nuglify: {\n build: {\n src: 'js/build/production.js',\n dest: 'js/build/production.min.js'\n }\n}\n\nLet\u2019s update that default task to also run minification:\n\ngrunt.registerTask('default', ['concat', 'uglify']);\n\nSuper-similar to the concatenation set-up, right?\n\nRun grunt at the terminal and you\u2019ll get some deliciously minified JavaScript:\n\n Minified JavaScript\n\nThat production.min.js file is what we would load up for use in our index.html file.\n\nLet\u2019s make Grunt optimize our images\n\nWe\u2019ve got this down pat now. Let\u2019s just go through the motions. The official image minification plug-in for Grunt is grunt-contrib-imagemin. Install it:\n\nnpm install grunt-contrib-imagemin --save-dev\n\nRegister it in the Gruntfile.js:\n\ngrunt.loadNpmTasks('grunt-contrib-imagemin');\n\nConfigure it:\n\nimagemin: {\n dynamic: {\n files: [{\n expand: true,\n cwd: 'images/',\n src: ['**/*.{png,jpg,gif}'],\n dest: 'images/build/'\n }]\n }\n}\n\nMake sure it runs:\n\ngrunt.registerTask('default', ['concat', 'uglify', 'imagemin']);\n\nRun grunt and watch that gorgeous squishification happen:\n\n Squished images\n\nGotta love performance increases for nearly zero effort.\n\nLet\u2019s get a little bit smarter and automate\n\nWhat we\u2019ve done so far is awesome and incredibly useful. But there are a couple of things we can get smarter on and make things easier on ourselves, as well as Grunt:\n\n\n\tRun these tasks automatically when they should\n\tRun only the tasks needed at the time\n\n\nFor instance:\n\n\n\tConcatenate and minify JavaScript when JavaScript changes\n\tOptimize images when a new image is added or an existing one changes\n\n\nWe can do this by watching files. We can tell Grunt to keep an eye out for changes to specific places and, when changes happen in those places, run specific tasks. Watching happens through the official grunt-contrib-watch plugin.\n\nI\u2019ll let you install it. It is exactly the same process as the last few plug-ins we installed. We configure it by giving watch specific files (or folders, or both) to watch. By watch, I mean monitor for file changes, file deletions or file additions. Then we tell it what tasks we want to run when it detects a change.\n\nWe want to run our concatenation and minification when anything in the /js/ folder changes. When it does, we should run the JavaScript-related tasks. And when things happen elsewhere, we should not run the JavaScript-related tasks, because that would be irrelevant. So:\n\nwatch: {\n scripts: {\n files: ['js/*.js'],\n tasks: ['concat', 'uglify'],\n options: {\n spawn: false,\n },\n } \n}\n\nFeels pretty comfortable at this point, hey? The only weird bit there is the spawn thing. And you know what? I don\u2019t even really know what that does. From what I understand from the documentation it is the smart default. That\u2019s real-world development. Just leave it alone if it\u2019s working and if it\u2019s not, learn more.\n\nNote: Isn\u2019t it frustrating when something that looks so easy in a tutorial doesn\u2019t seem to work for you? If you can\u2019t get Grunt to run after making a change, it\u2019s very likely to be a syntax error in your Gruntfile.js. That might look like this in the terminal:\n\n Errors running Grunt\n\nUsually Grunt is pretty good about letting you know what happened, so be sure to read the error message. In this case, a syntax error in the form of a missing comma foiled me. Adding the comma allowed it to run.\n\nLet\u2019s make Grunt do our preprocessing\n\nThe last thing on our list from the top of the article is using Sass \u2014 yet another task Grunt is well-suited to run for us. But wait? Isn\u2019t Sass technically in Ruby? Indeed it is. There is a version of Sass that will run in Node and thus not add an additional dependency to our project, but it\u2019s not quite up-to-snuff with the main Ruby project. So, we\u2019ll use the official grunt-contrib-sass plug-in which just assumes you have Sass installed on your machine. If you don\u2019t, follow the command line instructions.\n\nWhat\u2019s neat about Sass is that it can do concatenation and minification all by itself. So for our little project we can just have it compile our main global.scss file:\n\nsass: {\n dist: {\n options: {\n style: 'compressed'\n },\n files: {\n 'css/build/global.css': 'css/global.scss'\n }\n } \n}\n\nWe wouldn\u2019t want to manually run this task. We already have the watch plug-in installed, so let\u2019s use it! Within the watch configuration, we\u2019ll add another subtask:\n\ncss: {\n files: ['css/*.scss'],\n tasks: ['sass'],\n options: {\n spawn: false,\n }\n}\n\nThat\u2019ll do it. Now, every time we change any of our Sass files, the CSS will automaticaly be updated.\n\nLet\u2019s take this one step further (it\u2019s absolutely worth it) and add LiveReload. With LiveReload, you won\u2019t have to go back to your browser and refresh the page. Page refreshes happen automatically and in the case of CSS, new styles are injected without a page refresh (handy for heavily state-based websites).\n\nIt\u2019s very easy to set up, since the LiveReload ability is built into the watch plug-in. We just need to:\n\n\nInstall the browser plug-in\nAdd to the top of the watch configuration:\n. watch: {\n options: {\n livereload: true,\n },\n scripts: { \n /* etc */\n\nRestart the browser and click the LiveReload icon to activate it.\nUpdate some Sass and watch it change the page automatically.\n\n\n Live reloading browser\n\nYum.\n\nPrefer a video?\n\nIf you\u2019re the type that likes to learn by watching, I\u2019ve made a screencast to accompany this article that I\u2019ve published over on CSS-Tricks: First Moments with Grunt\n\nLeveling up\n\nAs you might imagine, there is a lot of leveling up you can do with your build process. It surely could be a full time job in some organizations.\n\nSome hardcore devops nerds might scoff at the simplistic setup we have going here. But I\u2019d advise them to slow their roll. Even what we have done so far is tremendously valuable. And don\u2019t forget this is all free and open source, which is amazing.\n\nYou might level up by adding more useful tasks:\n\n\n\tRunning your CSS through Autoprefixer (A+ Would recommend) instead of a preprocessor add-ons.\n\tWriting and running JavaScript unit tests (example: Jasmine).\n\tBuild your image sprites and SVG icons automatically (example: Grunticon).\n\tStart a server, so you can link to assets with proper file paths and use services that require a real URL like TypeKit and such, as well as remove the need for other tools that do this, like MAMP.\n\tCheck for code problems with HTML-Inspector, CSS Lint, or JS Hint.\n\tHave new CSS be automatically injected into the browser when it ever changes.\n\tHelp you commit or push to a version control repository like GitHub.\n\tAdd version numbers to your assets (cache busting).\n\tHelp you deploy to a staging or production environment (example: DPLOY).\n\n\nYou might level up by simply understanding more about Grunt itself:\n\n\n\tRead Grunt Boilerplate by Mark McDonnell.\n\tRead Grunt Tips and Tricks by Nicolas Bevacqua.\n\tOrganize your Gruntfile.js by splitting it up into smaller files.\n\tCheck out other people\u2019s and projects\u2019 Gruntfile.js.\n\tLearn more about Grunt by digging into its source and learning about its API.\n\n\nLet\u2019s share\n\nI think some group sharing would be a nice way to wrap this up. If you are installing Grunt for the first time (or remember doing that), be especially mindful of little frustrating things you experience(d) but work(ed) through. Those are the things we should share in the comments here. That way we have this safe place and useful resource for working through those confusing moments without the embarrassment. We\u2019re all in this thing together!\n\n \n\n1 Maybe someday someone will make a beautiful Grunt app for your operating system of choice. But I\u2019m not sure that day will come. The configuration of the plug-ins is the important part of using Grunt. Each plug-in is a bit different, depending on what it does. That means a uniquely considered UI for every single plug-in, which is a long shot.\n\nPerhaps a decent middleground is this Grunt DevTools Chrome add-on.\n\n2 Gruntfile.js is often referred to as Gruntfile in documentation and examples. Don\u2019t literally name it Gruntfile \u2014 it won\u2019t work.", "year": "2013", "author": "Chris Coyier", "author_slug": "chriscoyier", "published": "2013-12-11T00:00:00+00:00", "url": "https://24ways.org/2013/grunt-is-not-weird-and-hard/", "topic": "code"} {"rowid": 21, "title": "Keeping Parts of Your Codebase Private on GitHub", "contents": "Open source is brilliant, there\u2019s no denying that, and GitHub has been instrumental in open source\u2019s recent success. I\u2019m a keen open-sourcerer myself, and I have a number of projects on GitHub. However, as great as sharing code is, we often want to keep some projects to ourselves. To this end, GitHub created private repositories which act like any other Git repository, only, well, private!\n\nA slightly less common issue, and one I\u2019ve come up against myself, is the desire to only keep certain parts of a codebase private. A great example would be my site, CSS Wizardry; I want the code to be open source so that people can poke through and learn from it, but I want to keep any draft blog posts private until they are ready to go live. Thankfully, there is a very simple solution to this particular problem: using multiple remotes.\n\nBefore we begin, it\u2019s worth noting that you can actually build a GitHub Pages site from a private repo. You can keep the entire source private, but still have GitHub build and display a full Pages/Jekyll site. I do this with csswizardry.net. This post will deal with the more specific problem of keeping only certain parts of the codebase (branches) private, and expose parts of it as either an open source project, or a built GitHub Pages site.\n\nN.B. This post requires some basic Git knowledge.\n\nAdding your public remote\n\nLet\u2019s assume you\u2019re starting from scratch and you currently have no repos set up for your project. (If you do already have your public repo set up, skip to the \u201cAdding your private remote\u201d section.)\n\nSo, we have a clean slate: nothing has been set up yet, we\u2019re doing all of that now. On GitHub, create two repositories. For the sake of this article we shall call them site.com and private.site.com. Make the site.com repo public, and the private.site.com repo private (you will need a paid GitHub account).\n\nOn your machine, create the site.com directory, in which your project will live. Do your initial work in there, commit some stuff \u2014 whatever you need to do. Now we need to link this local Git repo on your machine with the public repo (remote) on GitHub. We should all be used to this:\n\n$ git remote add origin git@github.com:[user]/site.com.git\n\nHere we are simply telling Git to add a remote called origin which lives at git@github.com:[user]/site.com.git. Simple stuff. Now we need to push our current branch (which will be master, unless you\u2019ve explicitly changed it) to that remote:\n\n$ git push -u origin master\n\nHere we are telling Git to push our master branch to a corresponding master branch on the remote called origin, which we just added. The -u sets upstream tracking, which basically tells Git to always shuttle code on this branch between the local master branch and the master branch on the origin remote. Without upstream tracking, you would have to tell Git where to push code to (and pull it from) every time you ran the push or pull commands. This sets up a permanent bond, if you like.\n\nThis is really simple stuff, stuff that you will probably have done a hundred times before as a Git user. Now to set up our private remote.\n\nAdding your private remote\n\nWe\u2019ve set up our public, open source repository on GitHub, and linked that to the repository on our machine. All of this code will be publicly viewable on GitHub.com. (Remember, GitHub is just a host of regular Git repositories, which also puts a nice GUI around it all.) We want to add the ability to keep certain parts of the codebase private. What we do now is add another remote repository to the same local repository. We have two repos on GitHub (site.com and private.site.com), but only one repository (and, therefore, one directory) on our machine. Two GitHub repos, and one local one.\n\nIn your local repo, check out a new branch. For the sake of this article we shall call the branch dev. This branch might contain work in progress, or draft blog posts, or anything you don\u2019t want to be made publicly viewable on GitHub.com. The contents of this branch will, in a moment, live in our private repository.\n\n$ git checkout -b dev\n\nWe have now made a new branch called dev off the branch we were on last (master, unless you renamed it).\n\nNow we need to add our private remote (private.site.com) so that, in a second, we can send this branch to that remote:\n\n$ git remote add private git@github.com:[user]/private.site.com.git\n\nLike before, we are just telling Git to add a new remote to this repo, only this time we\u2019ve called it private and it lives at git@github.com:[user]/private.site.com.git. We now have one local repo on our machine which has two remote repositories associated with it.\n\nNow we need to tell our dev branch to push to our private remote:\n\n$ git push -u private dev\n\nHere, as before, we are pushing some code to a repo. We are saying that we want to push the dev branch to the private remote, and, once again, we\u2019ve set up upstream tracking. This means that, by default, the dev branch will only push and pull to and from the private remote (unless you ever explicitly state otherwise).\n\nNow you have two branches (master and dev respectively) that push to two remotes (origin and private respectively) which are public and private respectively.\n\nAny work we do on the master branch will push and pull to and from our publicly viewable remote, and any code on the dev branch will push and pull from our private, hidden remote.\n\nAdding more branches\n\nSo far we\u2019ve only looked at two branches pushing to two remotes, but this workflow can grow as much or as little as you\u2019d like. Of course, you\u2019d never do all your work in only two branches, so you might want to push any number of them to either your public or private remotes. Let\u2019s imagine we want to create a branch to try something out real quickly:\n\n$ git checkout -b test\n\nNow, when we come to push this branch, we can choose which remote we send it to:\n\n$ git push -u private test\n\nThis pushes the new test branch to our private remote (again, setting the persistent tracking with -u).\n\nYou can have as many or as few remotes or branches as you like.\n\nCombining the two\n\nLet\u2019s say you\u2019ve been working on a new feature in private for a few days, and you\u2019ve kept that on the private remote. You\u2019ve now finalised the addition and want to move it into your public repo. This is just a simple merge. Check out your master branch:\n\n$ git checkout master\n\nThen merge in the branch that contained the feature:\n\n$ git merge dev\n\nNow master contains the commits that were made on dev and, once you\u2019ve pushed master to its remote, those commits will be viewable publicly on GitHub:\n\n$ git push\n\nNote that we can just run $ git push on the master branch as we\u2019d previously set up our upstream tracking (-u).\n\nMultiple machines\n\nSo far this has covered working on just one machine; we had two GitHub remotes and one local repository. Let\u2019s say you\u2019ve got yourself a new Mac (yay!) and you want to clone an existing project:\n\n$ git clone git@github.com:[user]/site.com.git\n\nThis will not clone any information about the remotes you had set up on the previous machine. Here you have a fresh clone of the public project and you will need to add the private remote to it again, as above.\n\nDone!\n\nIf you\u2019d like to see me blitz through all that in one go, check the showterm recording.\n\nThe beauty of this is that we can still share our code, but we don\u2019t have to develop quite so openly all of the time. Building a framework with a killer new feature? Keep it in a private branch until it\u2019s ready for merge. Have a blog post in a Jekyll site that you\u2019re not ready to make live? Keep it in a private drafts branch. Working on a new feature for your personal site? Tuck it away until it\u2019s finished. Need a staging area for a Pages-powered site? Make a staging remote with its own custom domain.\n\nAll this boils down to, really, is the fact that you can bring multiple remotes together into one local codebase on your machine. What you do with them is entirely up to you!", "year": "2013", "author": "Harry Roberts", "author_slug": "harryroberts", "published": "2013-12-09T00:00:00+00:00", "url": "https://24ways.org/2013/keeping-parts-of-your-codebase-private-on-github/", "topic": "code"} {"rowid": 11, "title": "JavaScript: Taking Off the Training Wheels", "contents": "JavaScript is the third pillar of front-end web development. Of those pillars, it is both the most powerful and the most complex, so it\u2019s understandable that when 24 ways asked, \u201cWhat one thing do you wish you had more time to learn about?\u201d, a number of you answered \u201cJavaScript!\u201d\n\nThis article aims to help you feel happy writing JavaScript, and maybe even without libraries like jQuery. I can\u2019t comprehensively explain JavaScript itself without writing a book, but I hope this serves as a springboard from which you can jump to other great resources.\n\nWhy learn JavaScript?\n\nSo what\u2019s in it for you? Why take the next step and learn the fundamentals?\n\nConfidence with jQuery\n\nIf nothing else, learning JavaScript will improve your jQuery code; you\u2019ll be comfortable writing jQuery from scratch and feel happy bending others\u2019 code to your own purposes. Writing efficient, fast and bug-free jQuery is also made much easier when you have a good appreciation of JavaScript, because you can look at what jQuery is really doing. Understanding how JavaScript works lets you write better jQuery because you know what it\u2019s doing behind the scenes. When you need to leave the beaten track, you can do so with confidence.\n\nIn fact, you could say that jQuery\u2019s ultimate goal is not to exist: it was invented at a time when web APIs were very inconsistent and hard to work with. That\u2019s slowly changing as new APIs are introduced, and hopefully there will come a time when jQuery isn\u2019t needed.\n\nAn example of one such change is the introduction of the very useful document.querySelectorAll. Like jQuery, it converts a CSS selector into a list of matching elements. Here\u2019s a comparison of some jQuery code and the equivalent without.\n\n$('.counter').each(function (index) {\n $(this).text(index + 1);\n});\n\nvar counters = document.querySelectorAll('.counter');\n[].slice.call(counters).forEach(function (elem, index) {\n elem.textContent = index + 1;\n});\n\nSolving problems no one else has!\n\nWhen you have to go to the internet to solve a problem, you\u2019re forever stuck reusing code other people wrote to solve a slightly different problem to your own. Learning JavaScript will allow you to solve problems in your own way, and begin to do things nobody else ever has.\n\nNode.js\n\nNode.js is a non-browser environment for running JavaScript, and it can do just about anything! But if that sounds daunting, don\u2019t worry: the Node community is thriving, very friendly and willing to help.\n\nI think Node is incredibly exciting. It enables you, with one language, to build complete websites with complex and feature-filled front- and back-ends. Projects that let users log in or need a database are within your grasp, and Node has a great ecosystem of library authors to help you build incredible things. Exciting!\n\nHere\u2019s an example web server written with Node. http is a module that allows you to create servers and, like jQuery\u2019s $.ajax, make requests. It\u2019s a small amount of code to do something complex and, while working with Node is different from writing front-end code, it\u2019s certainly not out of your reach.\n\nvar http = require('http');\nhttp.createServer(function (req, res) {\n res.writeHead(200, {'Content-Type': 'text/plain'});\n res.end('Hello World');\n}).listen(1337);\nconsole.log('Server running at http://localhost:1337/');\n\nGrunt and other website tools\n\nNode has brought in something of a renaissance in tools that run in the command line, like Yeoman and Grunt. Both of these rely heavily on Node, and I\u2019ll talk a little bit about Grunt here.\n\nGrunt is a task runner, and many people use it for compiling Sass or compressing their site\u2019s JavaScript and images. It\u2019s pretty cool. You configure Grunt via the gruntfile.js, so JavaScript skills will come in handy, and since Grunt supports plug-ins built with JavaScript, knowing it unlocks the bucketloads of power Grunt has to offer.\n\nWays to improve your skills\n\nSo you know you want to learn JavaScript, but what are some good ways to learn and improve? I think the answer to that is different for different people, but here are some ideas.\n\nRebuild a jQuery app\n\nConverting a jQuery project to non-jQuery code is a great way to explore how you modify elements on the page and make requests to the server for data. My advice is to focus on making it work in one modern browser initially, and then go cross-browser if you\u2019re feeling adventurous. There are many resources for directly comparing jQuery and non-jQuery code, like Jeffrey Way\u2019s jQuery to JavaScript article.\n\nFind a mentor\n\nIf you think you\u2019d work better on a one-to-one basis then finding yourself a mentor could be a brilliant way to learn. The JavaScript community is very friendly and many people will be more than happy to give you their time. I\u2019d look out for someone who\u2019s active and friendly on Twitter, and does the kind of work you\u2019d like to do. Introduce yourself over Twitter or send them an email. I wouldn\u2019t expect a full tutoring course (although that is another option!) but they\u2019ll be very glad to answer a question and any follow-ups every now and then.\n\nGo to a workshop\n\nMany conferences and local meet-ups run workshops, hosted by experts in a particular field. See if there\u2019s one in your area. Workshops are great because you can ask direct questions, and you\u2019re in an environment where others are learning just like you are \u2014 no need to learn alone!\n\nSet yourself challenges\n\nThis is one way I like to learn new things. I have a new thing that I\u2019m not very good at, so I pick something that I think is just out of my reach and I try to build it. It\u2019s learning by doing and, even if you fail, it can be enormously valuable.\n\nWhere to start?\n\nIf you\u2019ve decided learning JavaScript is an important step for you, your next question may well be where to go from here.\n\nI\u2019ve collected some links to resources I know of or use, with some discussion about why you might want to check a particular site out. I hope this serves as a springboard for you to go out and learn as much as you want.\n\nBeginner\n\nIf you\u2019re just getting started with JavaScript, I\u2019d recommend heading to one of these places. They cover the basics and, in some cases, a little more advanced stuff. They\u2019re all reputable sources (although, I\u2019ve included something I wrote \u2014 you can decide about that one!) and will not lead you astray.\n\n\n\tjQuery\u2019s JavaScript 101 is a great first resource for JavaScript that will give you everything you need to work with jQuery like a pro.\n\tCodecademy\u2019s JavaScript Track is a small but useful JavaScript course. If you like learning interactively, this could be one for you.\n\tHTMLDog\u2019s JavaScript Tutorials take you right through from the basics of code to a brief introduction to newer technology like Node and Angular. [Disclaimer: I wrote this stuff, so it comes with a hazard warning!]\n\tThe tuts+ jQuery to JavaScript mentioned earlier is great for seeing how jQuery code looks when converted to pure JavaScript.\n\n\nGetting in-depth\n\nFor more comprehensive documentation and help I\u2019d recommend adding these places to your list of go-tos.\n\n\n\tMDN: the Mozilla Developer Network is the first place I go for many JavaScript questions. I mostly find myself there via a search, but it\u2019s a great place to just go and browse.\n\tAxel Rauschmayer\u2019s 2ality is a stunning collection of articles that will take you deep into JavaScript. It\u2019s certainly worth looking at.\n\tAddy Osmani\u2019s JavaScript Design Patterns is a comprehensive collection of patterns for writing high quality JavaScript, particularly as you (I hope) start to write bigger and more complex applications.\n\n\nAnd finally\u2026\n\nI think the key to learning anything is curiosity and perseverance. If you have a question, go out and search for the answer, even if you have no idea where to start. Keep going and going and eventually you\u2019ll get there. I bet you\u2019ll learn a whole lot along the way. Good luck!\n\nMany thanks to the people who gave me their time when I was working on this article: Tom Oakley, Jack Franklin, Ben Howdle and Laura Kalbag.", "year": "2013", "author": "Tom Ashworth", "author_slug": "tomashworth", "published": "2013-12-05T00:00:00+00:00", "url": "https://24ways.org/2013/javascript-taking-off-the-training-wheels/", "topic": "code"} {"rowid": 15, "title": "Git for Grown-ups", "contents": "You are a clever and talented person. You create beautiful designs, or perhaps you have architected a system that even my cat could use. Your peers adore you. Your clients love you. But, until now, you haven\u2019t *&^#^! been able to make Git work. It makes you angry inside that you have to ask your co-worker, again, for that *&^#^! command to upload your work.\n\nIt\u2019s not you. It\u2019s Git. Promise.\n\nYes, this is an article about the popular version control system, Git. But unlike just about every other article written about Git, I\u2019m not going to give you the top five commands that you need to memorize; and I\u2019m not going to tell you all your problems would be solved if only you were using this GUI wrapper or that particular workflow. You see, I\u2019ve come to a grand realization: when we teach Git, we\u2019re doing it wrong.\n\nLet me back up for a second and tell you a little bit about the field of adult education. (Bear with me, it gets good and will leave you feeling both empowered and righteous.) Andragogy, unlike pedagogy, is a learner-driven educational experience. There are six main tenets to adult education: \n\n\n\tAdults prefer to know why they are learning something.\n\tThe foundation of the learning activities should include experience.\n\tAdults prefer to be able to plan and evaluate their own instruction.\n\tAdults are more interested in learning things which directly impact their daily activities.\n\tAdults prefer learning to be oriented not towards content, but towards problems.\n\tAdults relate more to their own motivators than to external ones.\n\n\nNowhere in this list does it include \u201cmemorize the five most popular Git commands\u201d. And yet this is how we teach version control: init, add, commit, branch, push. You\u2019re an expert! Sound familiar? In the hierarchy of learning, memorizing commands is the lowest, or most basic, form of learning. At the peak of learning you are able to not just analyze and evaluate a problem space, but create your own understanding in relation to your existing body of knowledge.\n\n\u201cFine,\u201d I can hear you saying to yourself. \u201cBut I\u2019m here to learn about version control.\u201d Right you are! So how can we use this knowledge to master Git? First of all: I give you permission to use Git as a tool. A tool which you control and which you assign tasks to. A tool like a hammer, or a saw. Yes, your mastery of your tools will shape the kinds of interactions you have with your work, and your peers. But it\u2019s yours to control. Git was written by kernel developers for kernel development. The web world has adopted Git, but it is not a tool designed for us and by us. It\u2019s no Sass, y\u2019know? Git wasn\u2019t developed out of our frustration with managing CSS files in an increasingly complex ecosystem of components and atomic design. So, as you work through the next part of this article, give yourself a bit of a break. We\u2019re in this together, and it\u2019s going to be OK.\n\nWe\u2019re going to do a little activity. We\u2019re going to create your perfect Git cheatsheet.\n\nI want you to start by writing down a list of all the people on your code team. This list may include:\n\n\n\tdevelopers\n\tdesigners\n\tproject managers\n\tclients\n\n\nNext, I want you to write down a list of all the ways you interact with your team. Maybe you\u2019re a solo developer and you do all the tasks. Maybe you only do a few things. But I want you to write down a list of all the tasks you\u2019re actually responsible for. For example, my list looks like this:\n\n\n\twriting code\n\treviewing code\n\tpublishing tested code to your server(s)\n\ttroubleshooting broken code\n\n\nThe next list will end up being a series of boxes in a diagram. But to start, I want you to write down a list of your tools and constraints. This list potentially has a lot of noun-like items and verb-like items:\n\n\n\tcode hosting system (Bitbucket? GitHub? Unfuddle? self-hosted?)\n\tserver ecosystem (dev/staging/live)\n\tautomated testing systems or review gates\n\tautomated build systems (that Jenkins dude people keep referring to)\n\n\nBrilliant! Now you\u2019ve got your actors and your actions, it\u2019s time to shuffle them into a diagram. There are many popular workflow patterns. None are inherently right or wrong; rather, some are more or less appropriate for what you are trying to accomplish.\n\nCentralized workflow\n\nEveryone saves to a single place. This workflow may mean no version control, or a very rudimentary version control system which only ever has a single copy of the work available to the team at any point in time.\n\n \n\nBranching workflow\n\nEveryone works from a copy of the same place, merging their changes into the main copy as their work is completed. Think of the branches as a motorcycle sidecar: they\u2019re along for the ride and probably cannot exist in isolation of the main project for long without serious danger coming to the either the driver or sidecar passenger. Branches are a fundamental concept in version control \u2014 they allow you to work on new features, bug fixes, and experimental changes within a single repository, but without forcing the changes onto others working from the same branch.\n\n \n\nForking workflow\n\nEveryone works from their own, independent repository. A fork is an exact duplicate of a repository that a developer can make their own changes to. It can be kept up to date with additional changes made in other repositories, but it cannot force its changes onto another\u2019s repository. A fork is a complete repository which can use its own workflow strategies. If developers wish to merge their work with the main project, they must make a request of some kind (submit a patch, or a pull request) which the project collaborators may choose to adopt or reject. This workflow is popular for open source projects as it enforces a review process.\n\n \n\nGitflow workflow\n\nA specific workflow convention which includes five streams of parallel coding efforts: master, development, feature branches, release branches, and hot fixes. This workflow is often simplified down to a few elements by web teams, but may be used wholesale by software product teams. The original article describing this workflow was written by Vincent Driessen back in January 2010.\n\n \n\nBut these workflows aren\u2019t about you yet, are they? So let\u2019s make the connections.\n\nFrom the list of people on your team you identified earlier, draw a little circle. Give each of these circles some eyes and a smile. Now I want you to draw arrows between each of these people in the direction that code (ideally) flows. Does your designer create responsive prototypes which are pushed to the developer? Draw an arrow to represent this.\n\nChances are high that you don\u2019t just have people on your team, but you also have some kind of infrastructure. Hopefully you wrote about it earlier. For each of the servers and code repositories in your infrastructure, draw a square. Now, add to your diagram the relationships between the people and each of the machines in the infrastructure. Who can deploy code to the live server? How does it really get there? I bet it goes through some kind of code hosting system, such as GitHub. Draw in those arrows.\n\nBut wait!\n\nThe code that\u2019s on your development machine isn\u2019t the same as the live code. This is where we introduce the concept of a branch in version control. In Git, a repository contains all of the code (sort of). A branch is a fragment of the code that has been worked on in isolation to the other branches within a repository. Often branches will have elements in common. When we compare two (or more) branches, we are asking about the difference (or diff) between these two slivers. Often the master branch is used on production, and the development branch is used on our dev server. The difference between these two branches is the untested code that is not yet deployed.\n\nOn your diagram, see if you can colour-code according to the branch names at each of the locations within your infrastructure. You might find it useful to make a few different copies of the diagram to isolate each of the tasks you need to perform. For example: our team has a peer review process that each branch must go through before it is merged into the shared development branch.\n\nFinally, we are ready to add the Git commands necessary to make sense of the arrows in our diagram. If we are bringing code to our own workstation we will issue one of the following commands: clone (the first time we bring code to our workstation) or pull. Remembering that a repository contains all branches, we will issue the command checkout to switch from one branch to another within our own workstation. If we want to share a particular branch with one of our team mates, we will push this branch back to the place we retrieved it from (the origin). Along each of the arrows in your diagram, write the name of the command you are are going to use when you perform that particular task.\n\n \n\nFrom here, it\u2019s up to you to be selfish. Before asking Git what command it would like you to use, sketch the diagram of what you want. Git is your tool, you are not Git\u2019s tool. Draw the diagram. Communicate your tasks with your team as explicitly as you can. Insist on being a selfish adult learner \u2014 demand that others explain to you, in ways that are relevant to you, how to do the things you need to do today.", "year": "2013", "author": "Emma Jane Westby", "author_slug": "emmajanewestby", "published": "2013-12-04T00:00:00+00:00", "url": "https://24ways.org/2013/git-for-grownups/", "topic": "code"} {"rowid": 8, "title": "Coding Towards Accessibility", "contents": "\u201cCan we make it AAA-compliant?\u201d \u2013 does this question strike fear into your heart? Maybe for no other reason than because you will soon have to wade through the impenetrable WCAG documentation once again, to find out exactly what AAA-compliant means?\n\nI\u2019m not here to talk about that.\n\nThe Web Content Accessibility Guidelines are a comprehensive and peer-reviewed resource which we\u2019re lucky to have at our fingertips. But they are also a pig to read, and they may have contributed to the sense of mystery and dread with which some developers associate the word accessibility.\n\nThis Christmas, I want to share with you some thoughts and some practical tips for building accessible interfaces which you can start using today, without having to do a ton of reading or changing your tools and workflow.\n\nBut first, let\u2019s clear up a couple of misconceptions.\n\nDreary, flat experiences\n\nI recently built a front-end framework for the Post Office. This was a great gig for a developer, but when I found out about my client\u2019s stringent accessibility requirements I was concerned that I\u2019d have to scale back what was quite a complex set of visual designs.\n\nSites like Jakob Neilsen\u2019s old workhorse useit.com and even the pioneering GOV.UK may have to shoulder some of the blame for this. They put a premium on usability and accessibility over visual flourish. (Although, in fairness to Mr Neilsen, his new site nngroup.com is really quite a snazzy affair, comparatively.)\n\nOf course, there are other reasons for these sites\u2019 aesthetics \u2014 and it\u2019s not because of the limitations of the form. You can make an accessible site look as glossy or as plain as you want it to look. It\u2019s always our own ingenuity and attention to detail that are going to be the limiting factors.\n\nSynecdoche\n\nWe must always guard against the tendency to assume that catering to screen readers means we have the whole accessibility ballgame covered. \n\nThere\u2019s so much more to accessibility than assistive technology, as you know. And within the field of assistive technology there are plenty of other devices for us to consider.\n\nPlanning to accommodate all these users and devices can be daunting. When I first started working in this field I thought that the breadth of technology was prohibitive. I didn\u2019t even know what a screen reader looked like. (I assumed they were big and heavy, perhaps like an old typewriter, and certainly they would be expensive and difficult to fathom.) This is nonsense, of course. Screen reader emulators are readily available as browser extensions and can be activated in seconds. Chromevox and Fangs are both excellent and you should download one or the other right now.\n\nBut the really good news is that you can emulate many other types of assistive technology without downloading a byte. And this is where we move from misconceptions into some (hopefully) useful advice.\n\nThe mouse trap\n\nThe simplest and most effective way to improve your abilities as a developer of accessible interfaces is to unplug your mouse.\n\nKeyboard operation has its own WCAG chapter, because most users of assistive technology are navigating the web using only their keyboards. You can go some way towards putting yourself into their shoes so easily \u2014 just by ditching a peripheral.\n\nLearning this was a lightbulb moment for me. When I build interfaces I am constantly flicking between code and the browser, testing or viewing the changes I have made. Now, instead of checking a new element once, I check it twice: once with my mouse and then again without.\n\nDon\u2019t just :hover\n\nThe reality is that when you first start doing this you can find your site becomes unusable straightaway. It\u2019s easy to lose track of which element is in focus as you hit the tab key repeatedly.\n\nOne of the easiest changes you can make to your coding practice is to add :focus and :active pseudo-classes to every hover state that you write. I\u2019m still amazed at how many sites fail to provide a decent focus state for links (and despite previous 24 ways authors in 2007 and 2009 writing on this same issue!).\n\nYou may find that in some cases it makes sense to have something other than, or in addition to, the hover state on focus, but start with the hover state that your designer has taken the time to provide you with. It\u2019s a tiny change and there is no downside. So instead of this:\n\n.my-cool-link:hover {\n\tbackground-color: MistyRose ;\t\n}\n\n\u2026try writing this:\n\n.my-cool-link:hover,\n.my-cool-link:focus,\n.my-cool-link:active {\n\tbackground-color: MistyRose ;\t\n}\n\nI\u2019ve toyed with the idea of making a Sass mixin to take care of this for me, but I haven\u2019t yet. I worry that people reading my code won\u2019t see that I\u2019m explicitly defining my focus and active states so I take the hit and write my hover rules out longhand.\n\nJavaScript can play, too\n\nThis was another revelation for me. Keyboard-only navigation doesn\u2019t necessitate a JavaScript-free experience, and up-to-date screen readers can execute JavaScript. So we\u2019re able to create complex JavaScript-driven interfaces which all users can interact with.\n\nSome of the hard work has already been done for us. First, there are already conventions around keyboard-driven interfaces. Think about the last time you viewed a photo album on Facebook. You can use the arrow keys to switch between photos, and the escape key closes whichever lightbox-y UI thing Facebook is showing its photos in this week. Arrow keys (up/down as well as left/right) for progression through content; Escape to back out of something; Enter or space bar to indicate a positive intention \u2014 these are established keyboard conventions which we can apply to our interfaces to improve their accessiblity. \n\nOf course, by doing so we are improving our interfaces in general, giving all users the option to switch between keyboard and mouse actions as and when it suits them.\n\nSecond, this guy wants to help you out. Hans Hillen is a developer who has done a great deal of work around accessibility and JavaScript-powered interfaces. Along with The Paciello Group he has created a version of the jQuery UI library which has been fully optimised for keyboard navigation and screen reader use. It\u2019s a fantastic reference which I revisit all the time \n\nI\u2019m not a huge fan of the jQuery UI library. It\u2019s a pain to style and the code is a bit bloated. So I\u2019ve not used this demo as a code resource to copy wholesale. I use it by playing with the various components and seeing how they react to keyboard controls. Each component is also fully marked up with the relevant ARIA roles to improve screen reader announcement where possible (more on this below).\n\nCoding for accessibility promotes good habits\n\nThis is a another observation around accessibility and JavaScript. I noticed an improvement in the structure and abstraction of my code when I started adding keyboard controls to my interface elements. \n\nYour code has to become more modular and event-driven, because any number of events could trigger the same interaction. A mouse-click, the Enter key and the space bar could all conceivably trigger the same open function on a collapsed accordion element. (And you want to keep things DRY, don\u2019t you?) \n\nIf you aren\u2019t already in the habit of separating out your interface functionality into discrete functions, you will be soon.\n\nvar doSomethingCool = function(){\n\t// Do something cool here.\n}\n\n// Bind function to a button click - pretty vanilla\n$('.myCoolButton').on('click', function(){\n\tdoSomethingCool();\n\treturn false;\n});\n\n// Bind the same function to a range of keypresses\n$(document).keyup(function(e){\n\tswitch(e.keyCode) {\n\t\tcase 13: // enter\n\t\tcase 32: // spacebar\n\t\t\tdoSomethingCool();\n\t\t\tbreak;\n\t\tcase 27: // escape\n\t\t\tdoSomethingElse();\n\t\t\tbreak;\n\t}\n});\n\nTo be honest, if you\u2019re doing complex UI stuff with JavaScript these days, or if you\u2019ve been building any responsive interfaces which rely on JavaScript, then you are most likely working with an application framework such as Backbone, Angular or Ember, so an abstraced and event-driven application structure will be familar to you. It should be super easy for you to start helping out your keyboard-only users if you aren\u2019t already \u2014 just add a few more event bindings into your UI layer!\n\nManipulating the tab order\n\nSo, you\u2019ve adjusted your mindset and now you test every change to your codebase using a keyboard as well as a mouse. You\u2019ve applied all your hover states to :focus and :active so you can see where you\u2019re tabbing on the page, and your interactive components react seamlessly to a mixture of mouse and keyboard commands. Feels good, right?\n\nThere\u2019s another level of optimisation to consider: manipulating the tab order. Certain DOM elements are naturally part of the tab order, and others are excluded. Links and input elements are the main elements included in the tab order, and static elements like paragraphs and headings are excluded. What if you want to make a static element \u2018tabbable\u2019? \n\nA good example would be in an expandable accordion component. Each section of the accordion should be separated by a heading, and there\u2019s no reason to make that heading into a link simply because it\u2019s interactive.\n\n<div class=\"accordion-widget\">\n\t<h3>Tyrannosaurus</h3>\n\t<p>Tyrannosaurus; meaning \"tyrant lizard\"...<p>\n\n\t<h3>Utahraptor</h3>\n\t<p>Utahraptor is a genus of theropod dinosaurs...<p>\n\n\t<h3>Dromiceiomimus</h3>\n\t<p>Ornithomimus is a genus of ornithomimid dinosaurs...<p>\n</div>\n\nAdding the heading elements to the tab order is trivial. We just set their tabindex attribute to zero. You could do this on the server or the client. I prefer to do it with JavaScript as part of the accordion setup and initialisation process.\n\n$('.accordion-widget h3').attr('tabindex', '0');\n\nYou can apply this trick in reverse and take elements out of the tab order by setting their tabindex attribute to \u22121, or change the tab order completely by using other integers. This should be done with great care, if at all. You have to be sure that the markup you remove from the tab order comes out because it genuinely improves the keyboard interaction experience. This is hard to validate without user testing. The danger is that developers will try to sweep complicated parts of the UI under the carpet by taking them out of the tab order. This would be considered a dark pattern \u2014 at least on my team!\n\nA farewell ARIA\n\nThis is where things can get complex, and I\u2019m no expert on the ARIA specification: I feel like I\u2019ve only dipped my toe into this aspect of coding for accessibility. But, as with WCAG, I\u2019d like to demystify things a little bit to encourage you to look into this area further yourself.\n\nARIA roles are of most benefit to screen reader users, because they modify and augment screen reader announcements. \n\nLet\u2019s take our dinosaur accordion from the previous section. The markup is semantic, so a screen reader that can\u2019t handle JavaScript will announce all the content within the accordion, no problem.\n\nBut modern screen readers can deal with JavaScript, and this means that all the lovely dino information beneath each heading has probably been hidden on document.ready, when the accordion initialised. It might have been hidden using display:none, which prevents a screen reader from announcing content. If that\u2019s as far as you have gone, then you\u2019ve committed an accessibility sin by hiding content from screen readers. Your user will hear a set of headings being announced, with no content in between. It would sound something like this if you were using Chromevox:\n\n> Tyrannosaurus. Heading Three.\n> Utahraptor. Heading Three.\n> Dromiceiomimus. Heading Three.\n\nWe can add some ARIA magic to the markup to improve this, using the tablist role. Start by adding a role of tablist to the widget, and roles of tab and tabpanel to the headings and paragraphs respectively. Set boolean values for aria-selected, aria-hidden and aria-expanded. The markup could end up looking something like this.\n\n<div class=\"accordion-widget\" role=\"tablist\">\n\t<!-- T-rex -->\t\n\t<h3 role=\"tab\" \n\t\ttabindex=\"0\" \n\t\tid=\"tab-2\" \n\t\taria-controls=\"panel-2\" \n\t\taria-selected=\"false\">Utahraptor</h3>\n\t<p\trole=\"tabpanel\" \n\t\tid=\"panel-2\" \n\t\taria-labelledby=\"tab-2\" \n\t\taria-expanded=\"false\" \n\t\taria-hidden=\"true\">Utahraptor is a genus of theropod dinosaurs...</p>\n\t<!-- Dromiceiomimus -->\t\n</div>\n\nNow, if a screen reader user encounters this markup they will hear the following:\n\n> Tyrannosaurus. Tab not selected; one of three.\n> Utahraptor. Tab not selected; two of three.\n> Dromiceiomimus. Tab not selected; three of three.\n\nYou could add arrow key events to help the user browse up and down the tab list items until they find one they like. \n\nYour accordion open() function should update the ARIA boolean values as well as adding whatever classes and animations you have built in as standard. Your users know that unselected tabs are meant to be interacted with, so if a user triggers the open function (say, by hitting Enter or the space bar on the second item) they will hear this:\n\n> Utahraptor. Selected; two of three.\n\nThe paragraph element for the expanded item will not be hidden by your CSS, which means it will be announced as normal by the screen reader.\n\nThis kind of thing makes so much more sense when you have a working example to play with. Again, I refer you to the fantastic resource that Hans Hillen has put together: this is his take on an accessible accordion, on which much of my example is based.\n\nConclusion\n\nGetting complex interfaces right for all of your users can be difficult \u2014 there\u2019s no point pretending otherwise. And there\u2019s no substitute for user testing with real users who navigate the web using assistive technology every day. This kind of testing can be time-consuming to recruit for and to conduct. On top of this, we now have accessibility on mobile devices to contend with. That\u2019s a huge area in itself, and it\u2019s one which I have not yet had a chance to research properly.\n\nSo, there\u2019s lots to learn, and there\u2019s lots to do to get it right. But don\u2019t be disheartened. If you have read this far then I\u2019ll leave you with one final piece of advice: don\u2019t wait.\n\nDon\u2019t wait until you\u2019re building a site which mandates AAA-compliance to try this stuff out. Don\u2019t wait for a client with the will or the budget to conduct the full spectrum of user testing to come along. Unplug your mouse, and start playing with your interfaces in a new way. You\u2019ll be surprised at the things that you learn and the issues you uncover. \n\nAnd the next time an true accessibility project comes along, you will be way ahead of the game.", "year": "2013", "author": "Charlie Perrins", "author_slug": "charlieperrins", "published": "2013-12-03T00:00:00+00:00", "url": "https://24ways.org/2013/coding-towards-accessibility/", "topic": "code"} {"rowid": 20, "title": "Make Your Browser Dance", "contents": "It was a crisp winter\u2019s evening when I pulled up alongside the pier. I stepped out of my car and the bitterly cold sea air hit my face. I walked around to the boot, opened it and heaved out a heavy flight case. I slammed the boot shut, locked the car and started walking towards the venue.\n\nThis was it. My first gig. I thought about all those weeks of preparation: editing video clips, creating 3-D objects, making coloured patterns, then importing them all into software and configuring effects to change as the music did; targeting frequency, beat, velocity, modifying size, colour, starting point; creating playlists of these\u2026 and working out ways to mix them as the music played.\n\nThis was it. This was me VJing.\n\nThis was all a lifetime (well a decade!) ago.\n\nWhen I started web designing, VJing took a back seat. I was more interested in interactive layouts, semantic accessible HTML, learning all the IE bugs and mastering the quirks that CSS has to offer. More recently, I have been excited by background gradients, 3-D transforms, the @keyframe directive, as well as new APIs such as getUserMedia, indexedDB, the Web Audio API\n\nBut wait, have I just come full circle? Could it be possible, with these wonderful new things in technologies I am already familiar with, that I could VJ again, right here, in a browser?\n\nWell, there\u2019s only one thing to do: let\u2019s try it!\n\nLet\u2019s take to the dance floor \n\nOver the past couple of years working in The Lab I have learned to take a much more iterative approach to projects than before. One of my new favourite methods of working is to create a proof of concept to make sure my theory is feasible, before going on to create a full-blown product. So let\u2019s take the same approach here.\n\nThe main VJing functionality I want to recreate is manipulating visuals in relation to sound. So for my POC I need to create a visual, with parameters that can be changed, then get some sound and see if I can analyse that sound to detect some data, which I can then use to manipulate the visual parameters. Easy, right?\n\nSo, let\u2019s start at the beginning: creating a simple visual. For this I\u2019m going to create a CSS animation. It\u2019s just a funky i element with the opacity being changed to make it flash.\n\n See the Pen Creating a light by Rumyra (@Rumyra) on CodePen\n\nA note about prefixes: I\u2019ve left them out of the code examples in this post to make them easier to read. Please be aware that you may need them. I find a great resource to find out if you do is caniuse.com. You can also check out all the code for the examples in this article\n\nStart the music\n\nWell, that\u2019s pretty easy so far. Next up: loading in some sound. For this we\u2019ll use the Web Audio API. The Web Audio API is based around the concept of nodes. You have a source node: the sound you are loading in; a destination node: usually the device\u2019s speakers; and any number of processing nodes in between. All this processing that goes on with the audio is sandboxed within the AudioContext.\n\nSo, let\u2019s start by initialising our audio context.\n\nvar contextClass = window.AudioContext;\nif (contextClass) {\n //web audio api available.\n var audioContext = new contextClass();\n} else {\n //web audio api unavailable\n //warn user to upgrade/change browser\n}\n\nNow let\u2019s load our sound file into the new context we created with an XMLHttpRequest.\n\nfunction loadSound() {\n\t//set audio file url\n\tvar audioFileUrl = '/octave.ogg';\n\t//create new request\n\tvar request = new XMLHttpRequest();\n\trequest.open(\"GET\", audioFileUrl, true);\n\trequest.responseType = \"arraybuffer\";\n\n\trequest.onload = function() {\n\t\t//take from http request and decode into buffer\n\t\tcontext.decodeAudioData(request.response, function(buffer) {\n\t \taudioBuffer = buffer;\n\t });\n\t\t}\n\trequest.send();\n}\n\nPhew! Now we\u2019ve loaded in some sound! There are plenty of things we can do with the Web Audio API: increase volume; add filters; spatialisation. If you want to dig deeper, the O\u2019Reilly Web Audio API book by Boris Smus is available to read online free.\n\nAll we really want to do for this proof of concept, however, is analyse the sound data. To do this we really need to know what data we have.\n\n Learning the steps\n\nLet\u2019s take a minute to step back and remember our school days and science class. I\u2019m sure if I drew a picture of a sound wave, we would all start nodding our heads.\n\n \n\nThe sound you hear is caused by pressure differences in the particles in the air. Sound pushes these particles together, causing vibrations. Amplitude is basically strength of pressure. A simple example of change of amplitude is when you increase the volume on your stereo and the output wave increases in size.\n\nThis is great when everything is analogue, but the waveform varies continuously and it\u2019s not suitable for digital processing: there\u2019s an infinite set of values. For digital processing, we need discrete numbers.\n\nWe have to sample the waveform at set time intervals, and record data such as amplitude and frequency. Luckily for us, just the fact we have a digital sound file means all this hard work is done for us. What we\u2019re doing in the code above is piping that data in the audio context. All we need to do now is access it.\n\nWe can do this with the Web Audio API\u2019s analysing functionality. Just pop in an analysing node before we connect the source to its destination node.\n\nfunction createAnalyser(source) {\n\t//create analyser node\n\tanalyser = audioContext.createAnalyser();\n\t//connect to source\n\tsource.connect(analyzer);\n\t//pipe to speakers\n\tanalyser.connect(audioContext.destination);\n}\n\nThe data I\u2019m really interested in here is frequency. Later we could look into amplitude or time, but for now I\u2019m going to stick with frequency.\n\nThe analyser node gives us frequency data via the getFrequencyByteData method.\n\n Don\u2019t forget to count!\n\nTo collect the data from the getFrequencyByteData method, we need to pass in an empty array (a JavaScript typed array is ideal). But how do we know how many items the array will need when we create it?\n\nThis is really up to us and how high the resolution of frequencies we want to analyse is. Remember we talked about sampling the waveform; this happens at a certain rate (sample rate) which you can find out via the audio context\u2019s sampleRate attribute. This is good to bear in mind when you\u2019re thinking about your resolution of frequencies.\n\nvar sampleRate = audioContext.sampleRate;\n\nLet\u2019s say your file sample rate is 48,000, making the maximum frequency in the file 24,000Hz (thanks to a wonderful theorem from Dr Harry Nyquist, the maximum frequency in the file is always half the sample rate). The analyser array we\u2019re creating will contain frequencies up to this point. This is ideal as the human ear hears the range 0\u201320,000hz.\n\nSo, if we create an array which has 2,400 items, each frequency recorded will be 10Hz apart. However, we are going to create an array which is half the size of the FFT (fast Fourier transform), which in this case is 2,048 which is the default. You can set it via the fftSize property.\n\n//set our FFT size\nanalyzer.fftSize = 2048;\n//create an empty array with 1024 items\nvar frequencyData = new Uint8Array(1024);\n\nSo, with an array of 1,024 items, and a frequency range of 24,000Hz, we know each item is 24,000 \u00f7 1,024 = 23.44Hz apart.\n\nThe thing is, we also want that array to be updated constantly. We could use the setInterval or setTimeout methods for this; however, I prefer the new and shiny requestAnimationFrame.\n\nfunction update() {\n \t//constantly getting feedback from data\n \trequestAnimationFrame(update);\n \tanalyzer.getByteFrequencyData(frequencyData);\n}\n\n Putting it all together\n\nSweet sticks! Now we have an array of frequencies from the sound we loaded, updating as the sound plays. Now we want that data to trigger our animation from earlier.\n\nWe can easily pause and run our CSS animation from JavaScript:\n\nelement.style.webkitAnimationPlayState = \"paused\";\nelement.style.webkitAnimationPlayState = \"running\";\n\nUnfortunately, this may not be ideal as our animation might be a whole heap longer than just a flashing light. We may want to target specific points within that animation to have it stop and start in a visually pleasing way and perhaps not smack bang in the middle.\n\nThere is no really easy way to do this at the moment as Zach Saucier explains in this wonderful article. It takes some jiggery pokery with setInterval to try to ascertain how far through the CSS animation you are in percentage terms.\n\nThis seems a bit much for our proof of concept, so let\u2019s backtrack a little. We know by the animation we\u2019ve created which CSS properties we want to change. This is pretty easy to do directly with JavaScript.\n\nelement.style.opacity = \"1\";\nelement.style.opacity = \"0.2\";\n\nSo let\u2019s start putting it all together. For this example I want to trigger each light as a different frequency plays. For this, I\u2019ll loop through the HTML elements and change the opacity style if the frequency gain goes over a certain threshold.\n\n//get light elements\nvar lights = document.getElementsByTagName('i');\nvar totalLights = lights.length;\n\nfor (var i=0; i<totalLights; i++) {\n //get frequencyData key\n var freqDataKey = i*8;\n\t//if gain is over threshold for that frequency animate light\n if (frequencyData[freqDataKey] > 160){\n //start animation on element\n lights[i].style.opacity = \"1\";\n } else {\n lights[i].style.opacity = \"0.2\";\n }\n}\n\nSee all the code in action here. I suggest viewing in a modern browser :)\n\nAwesome! It is true \u2014 we can VJ in our browser!\n\nLet\u2019s dance!\n\nSo, let\u2019s start to expand this simple example. First, I feel the need to make lots of lights, rather than just a few. Also, maybe we should try a sound file more suited to gigs or clubs.\n\nCheck it out!\n\nI don\u2019t know about you, but I\u2019m pretty excited \u2014 that\u2019s just a bit of HTML, CSS and JavaScript!\n\nThe other thing to think about, of course, is the sound that you would get at a venue. We don\u2019t want to load sound from a file, but rather pick up on what is playing in real time. The easiest way to do this, I\u2019ve found, is to capture what my laptop\u2019s mic is picking up and piping that back into the audio context. We can do this by using getUserMedia.\n\nLet\u2019s include this in this demo. If you make some noise while viewing the demo, the lights will start to flash.\n\n And relax :)\n\nThere you have it. Sit back, play some music and enjoy the Winamp like experience in front of you.\n\nSo, where do we go from here? I already have a wealth of ideas. We haven\u2019t started with canvas, SVG or the 3-D features of CSS. There are other things we can detect from the audio as well. And yes, OK, it\u2019s questionable whether the browser is the best environment for this. For one, I\u2019m using a whole bunch of nonsensical HTML elements (maybe each animation could be held within a web component in the future). But hey, it\u2019s fun, and it looks cool and sometimes I think it\u2019s OK to just dance.", "year": "2013", "author": "Ruth John", "author_slug": "ruthjohn", "published": "2013-12-02T00:00:00+00:00", "url": "https://24ways.org/2013/make-your-browser-dance/", "topic": "code"} {"rowid": 16, "title": "URL Rewriting for the Fearful", "contents": "I think it was Marilyn Monroe who said, \u201cIf you can\u2019t handle me at my worst, please just fix these rewrite rules, I\u2019m getting an internal server error.\u201d Even the blonde bombshell hated configuring URL rewrites on her website, and I think most of us know where she was coming from.\n\nThe majority of website projects I work on require some amount of URL rewriting, and I find it mildly enjoyable \u2014 I quite like a good rewrite rule. I suspect you may not share my glee, so in this article we\u2019re going to go back to basics to try to make the whole rigmarole more understandable.\n\nWhen we think about URL rewriting, usually that means adding some rules to an .htaccess file for an Apache web server. As that\u2019s the most common case, that\u2019s what I\u2019ll be sticking to here. If you work with a different server, there\u2019s often documentation specifically for translating from Apache\u2019s mod_rewrite rules. I even found an automatic converter for nginx.\n\nThis isn\u2019t going to be a comprehensive guide to every URL rewriting problem you might ever have. That would take us until Christmas. If you consider yourself a trial-and-error dabbler in the HTTP 500-infested waters of URL rewriting, then hopefully this will provide a little bit more of a basis to help you figure out what you\u2019re doing. If you\u2019ve ever found yourself staring at the white screen of death after screwing up your .htaccess file, don\u2019t worry. As Michael Jackson once insipidly whined, you are not alone.\n\nThe basics\n\nRewrite rules form part of the Apache web server\u2019s configuration for a website, and can be placed in a number of different locations as part of your virtual host configuration. By far the simplest and most portable option is to use an .htaccess file in your website root. Provided your server has mod_rewrite available, all you need to do to kick things off in your .htaccess file is:\n\nRewriteEngine on\n\nThe general formula for a rewrite rule is:\n\nRewriteRule URL/to/match URL/to/use/if/it/matches [options]\n\nWhen we talk about URL rewriting, we\u2019re normally talking about one of two things: redirecting the browser to a different URL; or rewriting the URL internally to use a particular file. We\u2019ll look at those in turn.\n\nRedirects\n\nRedirects match an incoming URL, and then redirect the user\u2019s browser to a different address. These can be useful for maintaining legacy URLs if content changes location as part of a site redesign. Redirecting the old URL to the new location makes sure that any incoming links, such as those from search engines, continue to work. \n\nIn 1998, Sir Tim Berners-Lee wrote that Cool URIs don\u2019t change, encouraging us all to go the extra mile to make sure links keep working forever. I think that sometimes it\u2019s fine to move things around \u2014 especially to correct bad URL design choices of the past \u2014 provided that you can do so while keeping those old URLs working. That\u2019s where redirects can help.\n\nA redirect might look like this\n\nRewriteRule ^article/used/to/be/here.php$ /article/now/lives/here/ [R=301,L]\n\nRewriting\n\nBy default, web servers closely map page URLs to the files in your site. On receiving a request for http://example.com/about/history.html the server goes to the configured folder for the example.com website, and then goes into the about folder and returns the history.html file.\n\nA rewrite rule changes that process by breaking the direct relationship between the URL and the file system. \u201cWhen there\u2019s a request for /about/history.html\u201d a rewrite rule might say, \u201cuse the file /about_section.php instead.\u201d\n\nThis opens up lots of possibilities for creative ways to map URLs to the files that know how to serve up the page. Most MVC frameworks will have a single rule to rewrite all page URLs to one single file. That file will be a script which kicks off the framework to figure out what to do to serve the page.\n\nRewriteRule ^for/this/url/$ /use/this/file.php [L] \n\nMatching patterns\n\nBy now you\u2019ll have noted the weird ^ and $ characters wrapped around the URL we\u2019re trying to match. That\u2019s because what we\u2019re actually using here is a pattern. Technically, it is what\u2019s called a Perl Compatible Regular Expression (PCRE) or simply a regex or regexp. We\u2019ll call it a pattern because we\u2019re not animals.\n\nWhat are these patterns? If I asked you to enter your credit card expiry date as MM/YY then chances are you\u2019d wonder what I wanted your credit card details for, but you\u2019d know that I wanted a two-digit month, a slash, and a two-digit year. That\u2019s not a regular expression, but it\u2019s the same idea: using some placeholder characters to define the pattern of the input you\u2019re trying to match.\n\nWe\u2019ve already met two regexp characters.\n\n\n\t^\n\tMatches the beginning of a string\n\t$\n\tMatches the end of a string\n\n\nWhen a pattern starts with ^ and ends with $ it\u2019s to make sure we match the complete URL start to finish, not just part of it. There are lots of other ways to match, too:\n\n\n\t[0-9]\n\tMatches a number, 0\u20139. [2-4] would match numbers 2 to 4 inclusive.\n\t[a-z]\n\tMatches lowercase letters a\u2013z\n\t[A-Z]\n\tMatches uppercase letters A\u2013Z\n\t[a-z0-9]\n\tCombining some of these, this matches letters a\u2013z and numbers 0\u20139\n\n\nThese are what we call character groups. The square brackets basically tell the server to match from the selection of characters within them. You can put any specific characters you\u2019re looking for within the brackets, as well as the ranges shown above. \n\nHowever, all these just match one single character. [0-9] would match 8 but not 84 \u2014 to match 84 we\u2019d need to use [0-9] twice.\n\n[0-9][0-9]\n\nSo, if we wanted to match 1984 we could to do this:\n\n[0-9][0-9][0-9][0-9] \n\n\u2026but that\u2019s getting silly. Instead, we can do this:\n\n[0-9]{4}\n\nThat means any character between 0 and 9, four times. If we wanted to match a number, but didn\u2019t know how long it might be (for example, a database ID in the URL) we could use the + symbol, which means one or more.\n\n[0-9]+\n\nThis now matches 1, 123 and 1234567.\n\nPutting it into practice\n\nLet\u2019s say we need to write a rule to match article URLs for this website, and to rewrite them to use /article.php under the hood. The articles all have URLs like this:\n\n2013/article-title/\n\nThey start with a year (from 2005 up to 2013, currently), a slash, and then have a URL-safe version of the article title (a slug), ending in a slash. We\u2019d match it like this:\n\n^[0-9]{4}/[a-z0-9-]+/$\n\nIf that looks frightening, don\u2019t worry. Breaking it down, from the start of the URL (^) we\u2019re looking for four numbers ([0-9]{4}). Then a slash \u2014 that\u2019s just literal \u2014 and then anything lowercase a\u2013z or 0\u20139 or a dash ([a-z0-9-]) one or more times (+), ending in a slash (/$).\n\nPutting that into a rewrite rule, we end up with this:\n\nRewriteRule ^[0-9]{4}/[a-z0-9-]+/$ /article.php\n\nWe\u2019re getting close now. We can match the article URLs and rewrite them to use article.php. Now we just need to make sure that article.php knows which article it\u2019s supposed to display.\n\nCapturing groups, and replacements\n\nWhen rewriting URLs you\u2019ll often want to take important parts of the URL you\u2019re matching and pass them along to the script that handles the request. That\u2019s usually done by adding those parts of the URL on as query string arguments. For our example, we want to make sure that article.php knows the year and the article title we\u2019re looking for. That means we need to call it like this:\n\n/article.php?year=2013&slug=article-title\n\nTo do this, we need to mark which parts of the pattern we want to reuse in the destination. We do this with round brackets or parentheses. By placing parentheses around parts of the pattern we want to reuse, we create what\u2019s called a capturing group. To capture an important part of the source URL to use in the destination, surround it in parentheses.\n\nOur pattern now looks like this, with parentheses around the parts that match the year and slug, but ignoring the slashes:\n\n^([0-9]{4})/([a-z0-9-]+)/$ \n\nTo use the capturing groups in the destination URL, we use the dollar sign and the number of the group we want to use. So, the first capturing group is $1, the second is $2 and so on. (The $ is unrelated to the end-of-pattern $ we used before.)\n\nRewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 \n\nThe value of the year capturing group gets used as $1 and the article title slug is $2. Had there been a third group, that would be $3 and so on. In regexp parlance, these are called back-references as they refer back to the pattern.\n\nOptions\n\nSeveral brain-taxing minutes ago, I mentioned some options as the final part of a rewrite rule. There are lots of options (or flags) you can set to change how the rule is processed. The most useful (to my mind) are:\n\n\n\tR=301\n\tPerform an HTTP 301 redirect to send the user\u2019s browser to the new URL. A status of 301 means a resource has moved permanently and so it\u2019s a good way of both redirecting the user to the new URL, and letting search engines know to update their indexes.\n\tL\n\tLast. If this rule matches, don\u2019t bother processing the following rules.\n\n\nOptions are set in square brackets at the end of the rule. You can set multiple options by separating them with commas:\n\nRewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 [L]\n\nor\n\nRewriteRule ^about/([a-z0-9-]+).jsp/$ /about/$1/ [R=301,L] \n\nCommon pitfalls\n\nOnce you\u2019ve built up a few rewrite rules, things can start to go wrong. You may have been there: a rule which looks perfectly good is somehow not matching. One common reason for this is hidden behind that [L] flag. \n\nL for Last is a useful option to tell the rewrite engine to stop once the rule has been matched. This is what it does \u2014 the remaining rules in the .htaccess file are then ignored. However, once a URL has been rewritten, the entire set of rules are then run again on the new URL. If the new URL matches any of the rules, that too will be rewritten and on it goes. \n\nOne way to avoid this problem is to keep your \u2018real\u2019 pages under a folder path that will never match one of your rules, or that you can exclude from the rewrite rules.\n\nUseful snippets\n\nI find myself reusing the same few rules over and over again, just with minor changes. Here are some useful examples to refer back to.\n\nExcluding a directory\n\nAs mentioned above, if you\u2019re rewriting lots of fancy URLs to a collection of real files it can be helpful to put those files in a folder and exclude it from rewrite rules. This helps solve the issue of rewrite rules reapplying to your newly rewritten URL. To exclude a directory, put a rule like this at the top of your file, before your other rules. Our files are in a folder called _source, the dash in the rule means do nothing, and the L flag means the following rules won\u2019t be applied.\n\nRewriteRule ^_source - [L]\n\nThis is also useful for excluding things like CMS folders from your website\u2019s rewrite rules\n\nRewriteRule ^perch - [L] \n\nAdding or removing www from the domain\n\nSome folk like to use a www and others don\u2019t. Usually, it\u2019s best to pick one and go with it, and redirect the one you don\u2019t want. On this site, we don\u2019t use www.24ways.org so we redirect those requests to 24ways.org.\n\nThis uses a RewriteCond which is like an if for a rewrite rule: \u201cIf this condition matches, then apply the following rule.\u201d In this case, it\u2019s if the HTTP HOST (or domain name, basically) matches this pattern, then redirect everything:\n\nRewriteCond %{HTTP_HOST} ^www.24ways.org$ [NC]\nRewriteRule ^(.*)$ http://24ways.org/$1 [R=301,L]\n\nThe [NC] flag means \u2018no case\u2019 \u2014 the match is case-insensitive. The dots in the domain are escaped with a backslash, as a dot is a regular expression character which means match anything, so we escape it because we literally mean a dot in this instance.\n\nRemoving file extensions\n\nSometimes all you need to do to tidy up a URL is strip off the technology-specific file extension, so that /about/history.php becomes /about/history. This is easily achieved with the help of some more rewrite conditions.\n\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_FILENAME}.php -f\nRewriteRule ^(.+)$ $1.php [L,QSA]\n\nThis says if the file being asked for isn\u2019t a file (!-f) and if it isn\u2019t a directory (!-d) and if the file name plus .php is an actual file (-f) then rewrite by adding .php on the end. The QSA flag means \u2018query string append\u2019: append the existing query string onto the rewritten URL.\n\nIt\u2019s these sorts of more generic catch-all rules that you need to watch out for when your .htaccess gets rerun after a successful match. Without care they can easily rematch the newly rewritten URL.\n\nLogging for when it all goes wrong\n\nAlthough not possible within your .htaccess file, if you have access to your Apache configuration files you can enable rewrite logging. This can be useful to track down where a rule is going wrong, if it\u2019s matching incorrectly or failing to match. It also gives you an overview of the amount of work being done by the rewrite engine, enabling you to rearrange your rules and maximise performance.\n\nRewriteEngine On\nRewriteLog \"/full/system/path/to/rewrite.log\"\nRewriteLogLevel 5\n\nTo be doubly clear: this will not work from an .htaccess file \u2014 it needs to be added to the main Apache configuration files. (I sometimes work using MAMP PRO locally on my Mac, and this can be pasted into the snappily named Customized virtual host general settings box in the Advanced tab for your site.)\n\nThe white screen of death\n\nOne of the most frustrating things when working with rewrite rules is that when you make a mistake it can result in the server returning an HTTP 500 Internal Server Error. This in itself isn\u2019t an error message, of course. It\u2019s more of a notification that an error has occurred. The real error message can usually be found in your Apache error log.\n\nIf you have access to your server logs, check the Apache error log and you\u2019ll usually find a much more descriptive error message, pointing you towards your mistake. (Again, if using MAMP PRO, go to Server, Apache and the View Log button.)\n\nIn conclusion\n\nRewriting URLs can be a bear, but the advantages are clear. Keeping a tidy URL structure, disconnected from the technology or file structure of your site can result in URLs that are easier to use and easier to maintain into the future.\n\nIf you\u2019re redesigning a site, remember that cool URIs don\u2019t change, so budget some time to make sure that any content you move has a rewrite rule associated with it to keep any links working.\n\nFurther reading\n\nTo find out more about URL rewriting and perhaps even learn more about regular expressions, I can recommend the following resources.\n\n\n\tFrom the horse\u2019s mouth, the Apache mod_rewrite documentation\n\tParticularly useful with that documentation is the RewriteRule Flags listing\n\tYou may wish to don sunglasses to follow the otherwise comprehensive Regular-Expressions.info tutorial\n\tFriend of 24 ways, Neil Crosby has a mod_rewrite Beginner\u2019s Guide which I\u2019ve found handy over the years.\n\n\nAs noted at the start, this isn\u2019t a fully comprehensive guide, but I hope it\u2019s useful in finding your feet with a powerful but sometimes annoying technology. Do you have useful snippets you often use on projects? Feel free to share them in the comments.", "year": "2013", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2013-12-01T00:00:00+00:00", "url": "https://24ways.org/2013/url-rewriting-for-the-fearful/", "topic": "code"} {"rowid": 91, "title": "Infinite Canvas: Moving Beyond the Page", "contents": "Remember Web 2.0? I do. In fact, that phrase neatly bifurcates my life on the internet. Pre-2.0, I was occupied by chatting on AOL and eventually by learning HTML so I could build sites on Geocities. Around 2002, however, I saw a WYSIWYG demo in Dreamweaver. The instructor was dragging boxes and images around a canvas. With a few clicks he was able to build a dynamic, single-page interface. Coming from the world of tables and inline HTML styles, I was stunned.\n\nAs I entered college the next year, the web was blossoming: broadband, Wi-Fi, mobile (proud PDA owner, right here), CSS, Ajax, Bloglines, Gmail and, soon, Google Maps. I was a technology fanatic and a hobbyist web developer. For me, the web had long been informational. It was now rapidly becoming something else, something more: sophisticated, presentational, actionable.\n\nIn 2003 we watched as the internet changed. The predominant theme of those early Web 2.0 years was the withering of Internet Explorer 6 and the triumph of web standards. Upon cresting that mountain, we looked around and collectively breathed the rarefied air of pristine HMTL and CSS, uncontaminated by toxic hacks and forks \u2013 only to immediately begin hurtling down the other side at what is, frankly, terrifying speed.\n\nTen years later, we are still riding that rocket. Our days (and nights) are spent cramming for exams on CSS3 and RWD and Sass and RESS. We are the proud, frazzled owners of tiny pocket computers that annihilate the best laptops we could have imagined, and the architects of websites that are no longer restricted to big screens nor even segregated by device. We dragoon our sites into working any time, anywhere. At this point, we can hardly ask the spec developers to slow down to allow us to catch our breath, nor should we. It is, without a doubt, a most wonderful time to be a web developer.\n\nBut despite the newfound luxury of rounded corners, gradients, embeddable fonts, low-level graphics APIs, and, glory be, shadows, the canyon between HTML and native appears to be as wide as ever. The improvements in HTML and CSS have, for the most part, been conveniences rather than fundamental shifts. What I\u2019d like to do now, if you\u2019ll allow me, is outline just a few of the remaining gaps that continue to separate web sites and applications from their native companions.\n\nWhat I\u2019d like for Christmas\n\nThere is one irritant which is the grandfather of them all, the one from which all others flow and have their being, and it is, simply, the page refresh. That\u2019s right, the foundational principle of the web is our single greatest foe. To paraphrase a patron saint of designers everywhere, if you see a page refresh, we blew it.\n\nThe page refresh brings with it, of course, many noble and lovely benefits: addressability, for one; and pagination, for another. (See also caching, resource loading, and probably half a dozen others.) Still, those concerns can be answered (and arguably answered more compellingly) by replacing the weary page with the young and hearty document. Flash may be dead, but it has many lessons yet to bequeath.\n\nPreparing a single document when the site loads allows us to engage the visitor in a smooth and engrossing experience. We have long known this, of course. Twitter was not the first to attempt, via JavaScript, to envelop the user in a single-page application, nor the first to abandon it. Our shared task is to move those technologies down the stack, to make them more primitive, so that the next Twitter can be built with the most basic combination of HTML and CSS rather than relying on complicated, slow, and unreliable scripted solutions.\n\nSo, let\u2019s take a look at what we can do, right now, that we might have a better idea of where our current tools fall short.\n\nA print magazine in HTML clothing\n\nLike many others, I suspect, one of my earliest experiences with publishing was laying out newsletters and newspapers on a computer for print. If you\u2019ve ever used InDesign or Quark or even Microsoft Publisher, you\u2019ll remember reflowing content from page to page. The advent of the internet signaled, in many ways, the abandonment of that model. Articles were no longer constrained by the physical limitations of paper. In shedding our chains, however, it is arguable that we\u2019ve lost something useful. We had a self-contained and complete package, a closed loop. It was a thing that could be handled and finished, and doing so provided a sense of accomplishment that our modern, infinitely scrolling, ever-fractal web of content has stolen.\n\nFor our purposes today, we will treat 24 ways as the online equivalent of that newspaper or magazine. A single year\u2019s worth of articles could easily be considered an issue. Right now, navigating between articles means clicking on the article you\u2019d like to view and being taken to that specific address via a page reload. If Drew wanted to, it wouldn\u2019t be difficult to update the page in place (via JavaScript) and change the address (again via JavaScript with the History API) to reflect the new content found at the new location. But what if Drew wanted to do that without JavaScript? And what if he wanted the site to not merely load the content but actually whisk you along the page in a compelling and delightful way, \u00e0 la the Mag+ demo we all saw a few years ago when the iPad was first introduced? Uh, no.\n\nWe\u2019re all familiar with websites that have attempted to go beyond the page by weaving many chunks of content together into a large document and for good reason. There is tremendous appeal in opening and exploring the canvas beyond the edges of our screens.\n\nIn one rather straightforward example from last year, Mozilla contacted Full Stop to build a website promoting Aza Raskin\u2019s proposal for a set of Creative Commons-style privacy icons. Like a lot of the sites we build (including our own), the amount of information we were presenting was minimal. In these instances, we encourage our clients to consider including everything on a single page. The result was a horizontally driven site that was, if not whimsical, at least clever and attractive to the intended audience. An experience that is taken for granted when using device-native technology is utterly, maddeningly impossible to replicate on the web without jumping through JavaScript hoops.\n\nIn another, more complex example, we again had the pleasure of working with Aza earlier this year, this time on a redesign of the Massive Health website. Our assignment was to design and build a site that communicated Massive\u2019s commitment to modern personal health. The site had to be visually and interactively stunning while maintaining a usable and clear interface for the casual visitor. Our solution was to extend the infinite company logo into a ribbon that carried the visitor through the site narrative. It also meant we\u2019d be asking the browser to accommodate something it was never designed to handle: a non-linear design. (Be sure to play around. There\u2019s a lot going on under the hood. We were also this close to a ZUI, if WebKit didn\u2019t freak out when pages were scaled beyond 10\u00d7.) Despite the apparent and deliberate design simplicity, the techniques necessary to implement it are anything but. From updating the URL to moving the visitor from section to section, we\u2019re firmly in JavaScript territory. And that\u2019s a shame.\n\nWhat can we do?\n\nWe might not be able to specify these layouts in HTML and CSS just yet, but that doesn\u2019t mean we can\u2019t learn a few new tricks while we wait. Let\u2019s see how close we can come to recreating the privacy icons design, the Massive design, or the Mag+ design without resorting to JavaScript.\n\nA horizontally paginated site\n\nThe first thing we\u2019re going to need is the concept of a page within our HTML document. Using plain old HTML and CSS, we can stack a series of <div>s sideways (with a little assist from our new friend, the viewport-width unit, not that he was strictly necessary). All we need to know is how many pages we have. (And, boy, wouldn\u2019t it be nice to be able to know that without having to predetermine it or use JavaScript?)\n\n.window {\noverflow: hidden;\n width: 100%;\n}\n.pages {\n width: 200vw;\n}\n.page {\n float: left;\n overflow: hidden;\n width: 100vw;\n}\n\nIf you look carefully, you\u2019ll see that the conceit we\u2019ll use in the rest of the demos is in place. Despite the document containing multiple pages, only one is visible at any given time. This allows us to keep the user focused on the task (or content) at hand.\n\nBy the way, you\u2019ll need to use a modern, WebKit-based browser for these demos. I recommend downloading the WebKit nightly builds, Chrome Canary, or being comfortable with setting flags in Chrome.\n\nA horizontally paginated site, with transitions\n\nAh, here\u2019s the rub. We have functional navigation, but precious few cues for the user. It\u2019s not much good shoving the visitor around various parts of the document if they don\u2019t get the pleasant whooshing experience of the journey. You might be thinking, what about that new CSS selector, target-something\u2026? Well, my friend, you\u2019re on the right track. Let\u2019s test it. We\u2019re going to need to use a bit of sleight of hand. While we\u2019d like to simply offset the containing element by the number of pages we\u2019re moving (like we did on Massive), CSS alone can\u2019t give us that information, and that means we\u2019re going to need to fake it by expanding and collapsing pages as you navigate. Here are the bits we\u2019re going to need:\n\n.page {\n -webkit-transition: width 1s; // Naturally you're going to want to include all the relevant prefixes here\n float: left;\n left: 0;\n overflow: hidden;\n position: relative;\n width: 100vw;\n}\n.page:not(:target) {\n width: 0;\n}\n\nAh, but we\u2019re not fooling anyone with that trick. As soon as you move beyond a single page, the visitor\u2019s disbelief comes tumbling down when the linear page transitions are unaffected by the distance the pages are allegedly traveling. And you may have already noticed an even more fatal flaw: I secretly linked you to the first page rather than the unadorned URL. If you visit the same page with no URL fragment, you get a blank screen. Sure, we could force a redirect with some server-side trickery, but that feels like cheating. Perhaps if we had the CSS4 subject selector we could apply styles to the parent based on the child being targeted by the URL. We might also need a few more abilities, like determining the total number of pages and having relative sibling selectors (e.g. nth-sibling), but we\u2019d sure be a lot closer.\n\nA horizontally paginated site, with transitions \u2013 no cheating\n\nWell, what other cards can we play? How about the checkbox hack? Sure, it\u2019s a garish trick, but it might be the best we can do today. Check it out. \n\nlabel {\n cursor: pointer;\n}\ninput {\n display: none;\n}\ninput:not(:checked) + .page {\n max-height: 100vh;\n width: 0;\n}\n\nFinally, we can see the first page thanks to the state we are able to set on the appropriate radio button. Of course, now we don\u2019t have URLs, so maybe this isn\u2019t a winning plan after all. While our HTML and CSS toolkit may feel primitive at the moment, we certainly don\u2019t want to sacrifice the addressability of the web. If there\u2019s one bedrock principle, that\u2019s it.\n\nA horizontally paginated site, with transitions \u2013 no cheating and a gorgeous homepage\n\nGorgeous may not be the right word, but our little magazine is finally shaping up. Thanks to the CSS regions spec, we\u2019ve got an exciting new power, the ability to begin an article in one place and bend it to our will. (Remember, your everyday browser isn\u2019t going to work for these demos. Try the WebKit nightly build to see what we\u2019re talking about.) As with the rest of the examples, we\u2019re clearly abusing these features. Off-canvas layouts (you can thank Luke Wroblewski for the name) are simply not considered to be normal patterns\u2026 yet.\n\nHere\u2019s a quick look at what\u2019s going on:\n\n.excerpt-container {\n float: left;\n padding: 2em;\n position: relative;\n width: 100%;\n}\n.excerpt {\n height: 16em;\n}\n.excerpt_name_article-1,\n.page-1 .article-flow-region {\n -webkit-flow-from: article-1;\n}\n.article-content_for_article-1 {\n -webkit-flow-into: article-1;\n}\n\nThe regions pattern is comprised of at least three components: a beginning; an ending; and a source. Using CSS, we\u2019re able to define specific elements that should be available for the content to flow through. If magazine-style layouts are something you\u2019re interested in learning more about (and you should be), be sure to check out the great work Adobe has been doing.\n\nLooking forward, and backward\n\nAs designers, builders, and consumers of the web, we share a desire to see the usability and enjoyability of websites continue to rise. We are incredibly lucky to be working in a time when a three-month-old website can be laughably outdated. Our goal ought to be to improve upon both the weaknesses and the strengths of the web platform. We seek not only smoother transitions and larger canvases, but fine-grained addressability. Our URLs should point directly and unambiguously to specific content elements, be they pages, sections, paragraphs or words. Moreover, off-screen design patterns are essential to accommodating and empowering the multitude of devices we use to access the web. We should express the desire that interpage links take advantage of the CSS transitions which have been put to such good effect in every other aspect of our designs. Transitions aren\u2019t just nice to have, they\u2019re table stakes in the highly competitive world of native applications. \n\nThe tools and technologies we have right now allow us to create smart, beautiful, useful webpages. With a little help, we can begin removing the seams and sutures that bind the web to an earlier, less sophisticated generation.", "year": "2012", "author": "Nathan Peretic", "author_slug": "nathanperetic", "published": "2012-12-21T00:00:00+00:00", "url": "https://24ways.org/2012/infinite-canvas-moving-beyond-the-page/", "topic": "code"} {"rowid": 89, "title": "Direction, Distance and Destinations", "contents": "With all these new smartphones in the hands of lost and confused owners, we need a better way to represent distances and directions to destinations. The immediate examples that jump to mind are augmented reality apps which let you see another world through your phone\u2019s camera. While this is interesting, there is a simpler way: letting people know how far away they are and if they are getting warmer or colder. \n\nIn the app world, you can easily tap into the phone\u2019s array of sensors such as the GPS and compass, but what people rarely know is that you can do the same with HTML. The native versus web app debate will never subside, but at least we can show you how to replicate some of the functionality progressively in HTML and JavaScript.\n\nIn this tutorial, we\u2019ll walk through how to create a simple webpage listing distances and directions of a few popular locations around the world. We\u2019ll use JavaScript to access the device\u2019s geolocation API and also attempt to access the compass to get a heading. Both of these APIs are documented, to be included in the W3C geolocation API specification, and can be used on both desktop and mobile devices today.\n\nTo get started, we need a list of a few locations around the world. I have chosen the highest mountain peak on each continent so you can see a diverse set of distances and directions. \n\n\n\t\t\n\t\t\tMountain \n\t\t\t\u00b0Latitude \n\t\t\t\u00b0Longitude \n\t\t\n\t\t\n\t\t\tKilimanjaro\n\t\t\t-3.075833\n\t\t\t37.353333\n\t\t\n\t\t\n\t\t\tVinson Massif\n\t\t\t-78.525483\n\t\t\t-85.617147\n\t\t\n\t\t\n\t\t\tPuncak Jaya\n\t\t\t-4.078889\n\t\t\t137.158333\n\t\t\n\t\t\n\t\t\tEverest\n\t\t\t27.988056\n\t\t\t86.925278\n\t\t\n\t\t\n\t\t\tElbrus\n\t\t\t43.355\n\t\t\t42.439167\n\t\t\n\t\t\n\t\t\tMount McKinley\n\t\t\t63.0695\n\t\t\t-151.0074\n\t\t\n\t\t\n\t\t\tAconcagua\n\t\t\t-32.653431\n\t\t\t-70.011083\n\t\t\n\n\nSource: Wikipedia \n\nWe can put those into an HTML list to be styled and accessed by JavaScript to create some distance and directions calculations.\n\nThe next thing we need to do is check to see if the browser and operating system have geolocation support. To do this we test to see if the function is available or not using a single JavaScript if statement.\n\n<script>\n// If this is true, then the method is supported and we can try to access the location\nif (navigator.geolocation) {\n\tnavigator.geolocation.getCurrentPosition(geo_success, geo_error);\n}\n</script>\n\nThe if statement will be false if geolocation support is not present, and then it is up to you to do something else instead as a fallback. For this example, we\u2019ll do nothing since our page should work as is and only get progressively better if more functionality is available. \n\nThe if statement will be true if there is support and therefore will continue inside the curly brackets to try to get the location. This should prompt the reader to accept or deny the request to get their location. If they say no, the second function callback is processed, in this case a function called geo_error; whereas if the location is available, it fires the geo_success function callback.\n\nThe function geo_error(){ } isn\u2019t that exciting. You can handle this in any way you see fit. The success function is more interesting. We get a position object passed into the function which contains a series of exciting attributes, namely the latitude and longitude of the device\u2019s current location.\n\nfunction geo_success(position){\n\tgLat = position.coords.latitude;\n\tgLon = position.coords.longitude;\n}\n\nNow, in the variables gLat and gLon we have the user\u2019s approximate geographical position. We can use this information to start to calculate some distances between where they are and all the destinations.\n\nAt the time of writing, you can also get position.coords.heading, but on Windows and iOS devices this returned NULL. In the future, if and when this is supported, this is also where you can easily grab the compass information.\n\nInside the geo_success function, we want to loop through the HTML to get all of the mountain peaks\u2019 latitudes and longitudes and compute the distance.\n\n...\n$('.geo').each(function(){\n\t// Get the lat/lon from the HTML\n\ttLat = $(this).find('.lat').html()\n\ttLon = $(this).find('.lon').html()\n\n\t// compute the distances between the current location and this points location\n\tdist = distance(tLat,tLon,gLat,gLon);\n\n\t// set the return values into something useful\n\td = parseInt(dist[0]*10)/10;\n\ta = parseFloat(dist[1]);\n\n\t// display the value in the HTML and style the arrow\n\t$(this).find('.distance').html(d+' km away');\n\t$(this).find('.direction').css('-webkit-transform','rotate(-' + a + 'deg)');\n\n\t// store the arc for later use if compass is available\n\t$(this).attr('data-arc',a);\n}\n\nIn the variable d we have the distance between the current location and the location of the mountain peak based on the Haversine Formula. The variable a is the arc, which has a value from 0 to 359.99. This will be useful later if we have compass support. Given these two values we have a distance and a heading to style the HTML.\n\nThe next thing we want to do is check to see if the device has a compass and then get access to the the current heading. As we\u2019ll see, there are several ways to do this, some of which work on certain devices but not others. The W3C geolocation spec says that, along with the coordinates, there are several other attributes: accuracy; altitude; and heading. Heading is the direction to true north, which is different than magnetic north! WebKit and Windows return NULL for the heading value, but WebKit has an experimental method to fetch the heading. If you get into accessing these sensors, you\u2019ll have to try to catch a few of these methods to finally get a value. Assuming you do, we can move on to the more interesting display opportunities.\n\nIn an ideal world, this would succeed and set a variable we\u2019ll call compassHeading to get a value between 0 and 359.99 degrees. Now we know which direction north is, we also know the direction relative to north of the path to our destination, so we can can subtract the two values to get an arrow to display on the screen. But we\u2019re not finished yet: we also need to get the device\u2019s orientation (landscape or portrait) and subtract the correct amount from the angle for the arrow. Once we have a value, we can use CSS to rotate the arrow the correct number of degrees.\n\n-webkit-transform: rotate(-180deg)\n\nNot all devices support a standard way to access compass information, so in the meantime we need to use a work around. On iOS, you can use the experimental event method e.webkitCompassHeading. We want the compass to update in real time as the device is moved around, so we\u2019ll put this inside an event listener.\n\nwindow.addEventListener('deviceorientation', function(e) {\n\t// Loop through all the locations on the page\n\t$('.geo').each(function(){\n\t\t// get the arc value from north we computed and stored earlier\n\t\tdestination_arc = parseInt($(this).attr('data-arc'))\n\t\tcompassHeading = e.webkitCompassHeading + window.orientation + destination_arc;\n\t\t// find the arrow element and rotate it accordingly\n\t\t$(this).find('.direction').css('-webkit-transform','rotate(-' + compassHeading + 'deg)');\t\t\n\t}\n}\n\nAs the device is rotated, the compass arrow will constantly be updated. If you want to see an example, you can have a look at this page which shows the distances to all the peaks on each continent.\n\nWith progressive enhancement, we slowly layer on additional functionality as we go. The reader will first see the list of locations with a latitude and longitude. If the device is capable and permissions allow, it will then compute the distance. If a compass is available, with the correct permissions it will then add the final layer which is direction.\n\nYou should consider this code a stub for your projects. If you are making a hyperlocal webpage with restaurant locations, for example, then consider adding these features. Knowing not only how far away a place is, but also the direction can be hugely important, and since the compass is always active, it acts as a guide to the location. \n\nFuture developments\n\nImprovements to this could include setting a timer and recalling the navigator.geolocation.getCurrentPosition() function and updating the distances. I chose very distant mountains so kilometres made sense, but you can divide again by 1,000 to convert to metres if you are dealing with much nearer places. Walking or driving would change the distances so the ability to refresh would be important. \n\nIt is outside the scope of this article, but if you manage to get this HTML to work offline, then you can make a nice web app which sits on your devices\u2019 homescreens and works even without an internet connection. This could be ideal for travellers in an unknown city looking for your destination. Just with offline storage, base64 encoding and data URIs, it is possible to embed plenty of design and functionality into a small offline webpage.\n\nNow you know how to use JavaScript to look up a destination\u2019s location and figure out the distance and direction \u2013 never get lost again.", "year": "2012", "author": "Brian Suda", "author_slug": "briansuda", "published": "2012-12-19T00:00:00+00:00", "url": "https://24ways.org/2012/direction-distance-and-destinations/", "topic": "code"} {"rowid": 95, "title": "Giving Content Priority with CSS3 Grid Layout", "contents": "Browser support for many of the modules that are part of CSS3 have enabled us to use CSS for many of the things we used to have to use images for. The rise of mobile browsers and the concept of responsive web design has given us a whole new way of looking at design for the web. However, when it comes to layout, we haven\u2019t moved very far at all. We have talked for years about separating our content and source order from the presentation of that content, yet most of us have had to make decisions on source order in order to get a certain visual layout. \n\nOwing to some interesting specifications making their way through the W3C process at the moment, though, there is hope of change on the horizon. In this article I\u2019m going to look at one CSS module, the CSS3 grid layout module, that enables us to define a grid and place elements on to it. This article comprises a practical demonstration of the basics of grid layout, and also a discussion of one way in which we can start thinking of content in a more adaptive way.\n\nBefore we get started, it is important to note that, at the time of writing, these examples work only in Internet Explorer 10. CSS3 grid layout is a module created by Microsoft, and implemented using the -ms prefix in IE10. My examples will all use the -ms prefix, and not include other prefixes simply because this is such an early stage specification, and by the time there are implementations in other browsers there may be inconsistencies. The implementation I describe today may well change, but is also there for your feedback.\n\nIf you don\u2019t have access to IE10, then one way to view and test these examples is by signing up for an account with Browserstack \u2013 the free trial would give you time to have a look. I have also included screenshots of all relevant stages in creating the examples.\n\nWhat is CSS3 grid layout?\n\nCSS3 grid layout aims to let developers divide up a design into a grid and place content on to that grid. Rather than trying to fabricate a grid from floats, you can declare an actual grid on a container element and then use that to position the elements inside. Most importantly, the source order of those elements does not matter. \n\nDeclaring a grid\n\nWe declare a grid using a new value for the display property: display: grid. As we are using the IE10 implementation here, we need to prefix that value: display: -ms-grid;.\n\nOnce we have declared our grid, we set up the columns and rows using the grid-columns and grid-rows properties.\n\n.wrapper {\n display: -ms-grid;\n -ms-grid-columns: 200px 20px auto 20px 200px;\n -ms-grid-rows: auto 1fr;\n}\n\nIn the above example, I have declared a grid on the .wrapper element. I have used the grid-columns property to create a grid with a 200 pixel-wide column, a 20 pixel gutter, a flexible width auto column that will stretch to fill the available space, another 20 pixel-wide gutter and a final 200 pixel sidebar: a flexible width layout with two fixed width sidebars. Using the grid-rows property I have created two rows: the first is set to auto so it will stretch to fill whatever I put into it; the second row is set to 1fr, a new value used in grids that means one fraction unit. In this case, one fraction unit of the available space, effectively whatever space is left.\n\nPositioning items on the grid\n\nNow I have a simple grid, I can pop items on to it. If I have a <div> with a class of .main that I want to place into the second row, and the flexible column set to auto I would use the following CSS:\n\n.content {\n -ms-grid-column: 3;\n -ms-grid-row: 2;\n -ms-grid-row-span: 1;\n}\n\nIf you are old-school, you may already have realised that we are essentially creating an HTML table-like layout structure using CSS. I found the concept of a table the most helpful way to think about the grid layout module when trying to work out how to place elements.\n\nCreating grid systems\n\nAs soon as I started to play with CSS3 grid layout, I wanted to see if I could use it to replicate a flexible grid system like this fluid 16-column 960 grid system.\n\nI started out by defining a grid on my wrapper element, using fractions to make this grid fluid.\n\n.wrapper {\t \n width: 90%;\n margin: 0 auto 0 auto;\n display: -ms-grid;\n -ms-grid-columns: 1fr (4.25fr 1fr)[16];\n -ms-grid-rows: (auto 20px)[24];\n}\n\nLike the 960 grid system I was using as an example, my grid starts with a gutter, followed by the first actual column, plus another gutter repeated sixteen times. What this means is that if I want to span two columns, as far as the grid layout module is concerned that is actually three columns: two wide columns, plus one gutter. So this needs to be accounted for when positioning items.\n\nI created a CSS class for each positioning option: column position; rows position; and column span. For example:\n\n.grid1 {-ms-grid-column: 2;} /* applying this class positions an item in the first column (the gutter is column 1) */\n.grid2 {-ms-grid-column: 4;} /* 2nd column - gutter|column 1|gutter */\n.grid3 {-ms-grid-column: 6;} /* 3rd column - gutter|column 1|gutter|column2|gutter */\n\n.row1 {-ms-grid-row:1;}\n.row2 {-ms-grid-row:3;}\n.row3 {-ms-grid-row:5;}\n\n.colspan1 {-ms-grid-column-span:1;}\n.colspan2 {-ms-grid-column-span:3;}\n.colspan3 {-ms-grid-column-span:5;}\n\nI could then add multiple classes to each element to set the position on on the grid.\n\n\n\nThis then gives me a replica of the fluid grid using CSS3 grid layout. To see this working fire up IE10 and view Example 1.\n\nThis works, but\u2026\n\nThis worked, but isn\u2019t ideal. I considered not showing this stage of my experiment \u2013 however, I think it clearly shows how the grid layout module works and is a useful starting point. That said, it\u2019s not an approach I would take in production. First, we have to add classes to our markup that tie an element to a position on the grid. This might not be too much of a problem if we are always going to maintain the sixteen-column grid, though, as I will show you that the real power of the grid layout module appears once you start to redefine the grid, using different grids based on media queries. If you drop to a six-column layout for small screens, positioning items into column 16 makes no sense any more.\n\nCalculating grid position using LESS\n\nAs we\u2019ve seen, if you want to use a grid with main columns and gutters, you have to take into account the spacing between columns as well as the actual columns. This means we have to do some calculating every time we place an item on the grid. In my example above I got around this by creating a CSS class for each position, allowing me to think in sixteen rather than thirty-two columns. But by using a CSS preprocessor, I can avoid using all the classes yet still think in main columns.\n\nI\u2019m using LESS for my example. My simple grid framework consists of one simple mixin.\n\n.position(@column,@row,@colspan,@rowspan) {\n -ms-grid-column: @column*2;\n -ms-grid-row: @row*2-1;\n -ms-grid-column-span: @colspan*2-1;\n -ms-grid-row-span: @rowspan*2-1;\n}\n\nMy mixin takes four parameters: column; row; colspan; and rowspan. So if I wanted to place an item on column four, row three, spanning two columns and one row, I would write the following CSS:\n\n.box {\n .position(4,3,2,1);\n}\n\nThe mixin would return:\n\n.box {\n -ms-grid-column: 8;\n -ms-grid-row: 5;\n -ms-grid-column-span: 3;\n -ms-grid-row-span: 1;\n}\n\nThis saves me some typing and some maths. I could also add other prefixed values into my mixin as other browsers started to add support.\n\nWe can see this in action creating a new grid. Instead of adding multiple classes to each element, I can add one class; that class uses the mixin to create the position. I have also played around with row spans using my mixin and you can see we end up with a quite complicated arrangement of boxes. Have a look at example two in IE10. I\u2019ve used the JavaScript LESS parser so that you can view the actual LESS that I use. Note that I have needed to escape the -ms prefixed properties with ~\"\" to get LESS to accept them.\n\n\n\nThis is looking better. I don\u2019t have direct positioning information on each element in the markup, just a class name \u2013 I\u2019ve used grid(x), but it could be something far more semantic. We can now take the example a step further and redefine the grid based on screen width.\n\nMedia queries and the grid\n\nThis example uses exactly the same markup as the previous example. However, we are now using media queries to detect screen width and redefine the grid using a different number of columns depending on that width.\n\nI start out with a six-column grid, defining that on .wrapper, then setting where the different items sit on this grid:\n\n.wrapper {\t \n width: 90%;\n margin: 0 auto 0 auto;\n display: ~\"-ms-grid\"; /* escaped for the LESS parser */\n -ms-grid-columns: ~\"1fr (4.25fr 1fr)[6]\"; /* escaped for the LESS parser */\n -ms-grid-rows: ~\"(auto 20px)[40]\"; /* escaped for the LESS parser */\n}\n.grid1 { .position(1,1,1,1); } \n.grid2 { .position(2,1,1,1); } \n/* ... see example for all declarations ... */\n\n\n\nUsing media queries, I redefine the grid to nine columns when we hit a minimum width of 700 pixels.\n\n@media only screen and (min-width: 700px) {\n.wrapper {\n -ms-grid-columns: ~\"1fr (4.25fr 1fr)[9]\";\n -ms-grid-rows: ~\"(auto 20px)[50]\";\n}\n.grid1 { .position(1,1,1,1); } \n.grid2 { .position(2,1,1,1); } \n/* ... */\n}\n\n\n\nFinally, we redefine the grid for 960 pixels, back to the sixteen-column grid we started out with.\n\n@media only screen and (min-width: 940px) {\n.wrapper {\t \n -ms-grid-columns:~\" 1fr (4.25fr 1fr)[16]\";\n -ms-grid-rows:~\" (auto 20px)[24]\";\n}\n.grid1 { .position(1,1,1,1); } \n.grid2 { .position(2,1,1,1); } \n/* ... */\n}\n\nIf you view example three in Internet Explorer 10 you can see how the items reflow to fit the window size. You can also see, looking at the final set of blocks, that source order doesn\u2019t matter. You can pick up a block from anywhere and place it in any position on the grid.\n\nLaying out a simple website\n\nSo far, like a toddler on Christmas Day, we\u2019ve been playing with boxes rather than thinking about what might be in them. So let\u2019s take a quick look at a more realistic layout, in order to see why the CSS3 grid layout module can be really useful. At this time of year, I am very excited to get out of storage my collection of odd nativity sets, prompting my family to suggest I might want to open a museum. Should I ever do so, I\u2019ll need a website, and here is an example layout.\n\n\n\nAs I am using CSS3 grid layout, I can order my source in a logical manner. In this example my document is as follows, though these elements could be in any order I please:\n\n<div class=\"wrapper\">\n <div class=\"welcome\">\n ...\n </div>\n <article class=\"main\">\n ...\n </article>\n <div class=\"info\">\n ...\n </div>\n <div class=\"ads\">\n ...\n </div>\n</div>\n\nFor wide viewports I can use grid layout to create a sidebar, with the important information about opening times on the top righ,t with the ads displayed below it. This creates the layout shown in the screenshot above.\n\n@media only screen and (min-width: 940px) {\n .wrapper {\t \n -ms-grid-columns:~\" 1fr (4.25fr 1fr)[16]\";\n -ms-grid-rows:~\" (auto 20px)[24]\";\n }\n .welcome {\n .position(1,1,12,1);\n padding: 0 5% 0 0;\n }\n .info {\n .position(13,1,4,1);\n border: 0;\n padding:0;\n }\n .main {\n .position(1,2,12,1);\n padding: 0 5% 0 0;\n } \n .ads {\n .position(13,2,4,1);\n display: block;\n margin-left: 0;\n }\n}\n\nIn a floated layout, a sidebar like this often ends up being placed under the main content at smaller screen widths. For my situation this is less than ideal. I want the important information about opening times to end up above the main article, and to push the ads below it. With grid layout I can easily achieve this at the smallest width .info ends up in row two and .ads in row five with the article between.\n\n.wrapper {\t \n display: ~\"-ms-grid\";\n -ms-grid-columns: ~\"1fr (4.25fr 1fr)[4]\";\n -ms-grid-rows: ~\"(auto 20px)[40]\";\n}\n.welcome {\n .position(1,1,4,1);\n}\n.info {\n .position(1,2,4,1);\n border: 4px solid #fff;\n padding: 10px;\n}\n.content {\n .position(1,3,4,5);\n}\n.main {\n .position(1,3,4,1);\n}\n.ads {\n .position(1,4,4,1);\n}\n\n\n\nFinally, as an extra tweak I add in a breakpoint at 600 pixels and nest a second grid on the ads area, arranging those three images into a row when they sit below the article at a screen width wider than the very narrow mobile width but still too narrow to support a sidebar. \n\n@media only screen and (min-width: 600px) {\n .ads {\n display: ~\"-ms-grid\";\n -ms-grid-columns: ~\"20px 1fr 20px 1fr 20px 1fr\";\n -ms-grid-rows: ~\"1fr\";\n margin-left: -20px;\n }\n .ad:nth-child(1) {\n .position(1,1,1,1);\n }\n .ad:nth-child(2) {\n .position(2,1,1,1);\n }\n .ad:nth-child(3) {\n .position(3,1,1,1);\n }\n}\n\nView example four in Internet Explorer 10.\n\n\n\nThis is a very simple example to show how we can use CSS grid layout without needing to add a lot of classes to our document. It also demonstrates how we can mainpulate the content depending on the context in which the user is viewing it.\n\nLayout, source order and the idea of content priority\n\nCSS3 grid layout isn\u2019t the only module that starts to move us away from the issue of visual layout being linked to source order. However, with good support in Internet Explorer 10, it is a nice way to start looking at how this might work. If you look at the grid layout module as something to be used in conjunction with the flexible box layout module and the very interesting CSS regions and exclusions specifications, we have, tantalizingly on the horizon, a powerful set of tools for layout.\n\nI am particularly keen on the potential separation of source order from layout as it dovetails rather neatly into something I spend a lot of time thinking about. As a CMS developer, working on larger scale projects as well as our CMS product Perch, I am interested in how we better enable content editors to create content for the web. In particular, I search for better ways to help them create adaptive content; content that will work in a variety of contexts rather than being tied to one representation of that content.\n\nIf the concept of adaptive content is new to you, then Karen McGrane\u2019s presentation Adapting Ourselves to Adaptive Content is the place to start. Karen talks about needing to think of content as chunks, that might be used in many different places, displayed differently depending on context.\n\nI absolutely agree with Karen\u2019s approach to content. We have always attempted to move content editors away from thinking about creating a page and previewing it on the desktop. However at some point content does need to be published as a page, or a collection of content if you prefer, and bits of that content have priority. Particularly in a small screen context, content gets linearized, we can only show so much at a time, and we need to make sure important content rises to the top. In the case of my example, I wanted to ensure that the address information was clearly visible without scrolling around too much. Dropping it with the entire sidebar to the bottom of the page would not have been so helpful, though neither would moving the whole sidebar to the top of the screen so a visitor had to scroll past advertising to get to the article.\n\nIf our layout is linked to our source order, then enabling the content editor to make decisions about priority is really hard. Only a system that can do some regeneration of the source order on the server-side \u2013 perhaps by way of multiple templates \u2013 can allow those kinds of decisions to be made. For larger systems this might be a possibility; for smaller ones, or when using an off-the-shelf CMS, it is less likely to be. Fortunately, any system that allows some form of custom field type can be used to pop a class on to an element, and with CSS grid layout that is all that is needed to be able to target that element and drop it into the right place when the content is viewed, be that on a desktop or a mobile device.\n\nThis approach can move us away from forcing editors to think visually. At the moment, I might have to explain to an editor that if a certain piece of content needs to come first when viewed on a mobile device, it needs to be placed in the sidebar area, tying it to a particular layout and design. I have to do this because we have to enforce fairly strict rules around source order to make the mechanics of the responsive design work. If I can instead advise an editor to flag important content as high priority in the CMS, then I can make decisions elsewhere as to how that is displayed, and we can maintain the visual hierarchy across all the different ways content might be rendered.\n\nWhy frustrate ourselves with specifications we can\u2019t yet use in production?\n\nThe CSS3 grid layout specification is listed under the Exploring section of the list of current work of the CSS Working Group. While discussing a module at this stage might seem a bit pointless if we can\u2019t use it in production work, there is a very real reason for doing so. If those of us who will ultimately be developing sites with these tools find out about them early enough, then we can start to give our feedback to the people responsible for the specification. There is information on the same page about how to get involved with the disussions.\n\nSo, if you have a bit of time this holiday season, why not have a play with the CSS3 grid layout module? I have outlined here some of my thoughts on how grid layout and other modules that separate layout from source order can be used in the work that I do. Likewise, wherever in the stack you work, playing with and thinking about new specifications means you can think about how you would use them to enhance your work. Spot a problem? Think that a change to the specification would improve things for a specific use case? Then you have something you could post to www-style to add to the discussion around this module.\n\nAll the examples are on CodePen so feel free to play around and fork them.", "year": "2012", "author": "Rachel Andrew", "author_slug": "rachelandrew", "published": "2012-12-18T00:00:00+00:00", "url": "https://24ways.org/2012/css3-grid-layout/", "topic": "code"} {"rowid": 83, "title": "Cut Copy Paste", "contents": "Long before I got into this design thing, I was heavily into making my own music inspired by the likes of Coldcut and Steinski. I would scour local second-hand record shops in search of obscure beats, loops and bits of dialogue in the hope of finding that killer sample I could then splice together with other things to make a huge hit that everyone would love. While it did eventually lead to a record contract and getting to release a few 12\u2033 singles, ultimately I knew I\u2019d have to look for something else to pay the bills.\n\nI may not make my own records any more, but the approach I took back then \u2013 finding (even stealing) things, cutting and pasting them into interesting combinations \u2013 is still at the centre of how I work, only these days it\u2019s pretty much bits of code rather than bits of vinyl. Over the years I\u2019ve stored these little bits of code (some I\u2019ve found, some I\u2019ve created myself) in Evernote, ready to be dialled up whenever I need them. \n\nSo when Drew got in touch and asked if I\u2019d like to do something for this year\u2019s 24 ways I thought it might be kind of cool to share with you a few of these snippets that I find really useful. Think of these as a kind of coding mix tape; but remember \u2013 don\u2019t just copy as is: play around, combine and remix them into other wonderful things. \n\nSome of this stuff is dirty; some of it will make hardcore programmers feel ill. For those people, remember this \u2013 while you were complaining about the syntax, I made something.\n\nCreate unique colours\n\nLet\u2019s start right away with something I stole. Well, actually it was given away at the time by Matt Biddulph who was then at Dopplr before Nokia destroyed it. Imagine you have thousands of words and you want to assign each one a unique colour. Well, Matt came up with a crazily simple but effective way to do that using an MD5 hash. Just encode said word using an MD5 hash, then take the first six characters of the string you get back to create a hexadecimal colour representation. \n\nI can\u2019t guarantee that it will be a harmonious colour palette, but it\u2019s still really useful. The thing I love the most about this technique is the left-field thinking of using an encryption system to create colours! Here\u2019s an example using JavaScript:\n\n// requires the MD5 library available at http://pajhome.org.uk/crypt/md5\n\n function MD5Hex(str){\n result = MD5.hex(str).substring(0, 6);\n return result;\n }\n\nMake something breathe using a sine wave\n\nI never paid attention in school, especially during double maths. As a matter of fact, the only time I received corporal punishment \u2013 several strokes of the ruler \u2013 was in maths class. Anyway, if they had shown me then how beautiful mathematics actually is, I might have paid more attention. Here\u2019s a little example of how a sine wave can be used to make something appear to breathe. \n\nI recently used this on an Arduino project where an LED ring surrounding a button would gently breathe. Because of that it felt much more inviting. I love mathematics.\n\nfor(int i = 0; i<360; i++){ \n float rad = DEG_TO_RAD * i;\n int sinOut = constrain((sin(rad) * 128) + 128, 0, 255);\n analogWrite(LED, sinOut);\n delay(10); \n}\n\nSnap position to grid\n\nThis is so elegant I love it, and it was shown to me by Gary Burgess, or Boom Boom as myself and others like to call him. It snaps a position, in this case the X-position, to a grid. Just define your grid size (say, twenty pixels) and you\u2019re good.\n\nsnappedXpos = floor( xPos / gridSize) * gridSize;\n\nCalculate the distance between two objects\n\nFor me, interaction design is about the relationship between two objects: you and another object; you and another person; or simply one object to another. How close these two things are to each other can be a handy thing to know, allowing you to react to that information within your design. Here\u2019s how to calculate the distance between two objects in a 2-D plane:\n\ndeltaX = round(p2.x-p1.x);\ndeltaY = round(p2.y-p1.y);\ndiff = round(sqrt((deltaX*deltaX)+(deltaY*deltaY)));\n\nFind the X- and Y-position between two objects\n\nWhat if you have two objects and you want to place something in-between them? A little bit of interruption and disruption can be a good thing. This small piece of code will allow you to place an object in-between two other objects:\n\n// set the position: 0.5 = half-way\t\n\nfloat position = 0.5;\nfloat x = x1 + (x2 - x1) *position; \nfloat y = y1 + (y2 - y1) *position; \n\nDistribute objects equally around a circle \t\n\nMore fun with maths, this time adding cosine to our friend sine. Let\u2019s say you want to create a circular navigation of arbitrary elements (yeah, Jakob, you heard), or you want to place images around a circle. Well, this piece of code will do just that. You can adjust the size of the circle by changing the distance variable and alter the number of objects with the numberOfObjects variable. Example below is for use in Processing.\n\n// Example for Processing available for free download at processing.org\n\nvoid setup() {\n\n size(800,800);\n int numberOfObjects = 12;\n int distance = 100;\n float inc = (TWO_PI)/numberOfObjects;\n float x,y;\n float a = 0;\n\n for (int i=0; i < numberOfObjects; i++) {\n x = (width/2) + sin(a)*distance;\n y = (height/2) + cos(a)*distance;\n ellipse(x,y,10,10);\n a += inc;\n\n }\n}\n\nUse modulus to make a grid\n\nThe modulus operator, represented by %, returns the remainder of a division. Fallen into a coma yet? Hold on a minute \u2013 this seemingly simple function is very powerful in lots of ways. At a simple level, you can use it to determine if a number is odd or even, great for creating alternate row colours in a table for instance:\n\nboolean checkForEven(numberToCheck) {\n if (numberToCheck % 2 == 0) \n return true;\n } else {\n return false; \n }\n}\n\nThat\u2019s all well and good, but here\u2019s a use of modulus that might very well blow your mind. Construct a grid with only a few lines of code. Again the example is in Processing but can easily be ported to any other language.\n\nvoid setup() {\n\nsize(600,600);\nint numItems = 120;\nint numOfColumns = 12;\nint xSpacing = 40;\nint ySpacing = 40;\nint totalWidth = xSpacing*numOfColumns;\n\nfor (int i=0; i < numItems; i++) {\n\nellipse(floor((i*xSpacing)%totalWidth),floor((i*xSpacing)/totalWidth)*ySpacing,10,10);\n\n}\n}\n\nNot all the bits of code I keep around are for actual graphical output. I also have things that are very utilitarian, but which I still consider part of the design process. Here\u2019s a couple of things that I\u2019ve found really handy lately in my design workflow. They may be a little specific, but I hope they demonstrate that it\u2019s not about working harder, it\u2019s about working smarter. \n\nMerge CSV files into one file\n\nRecently, I\u2019ve had to work with huge \u2013 about 1GB \u2013 CSV text files that I then needed to combine into one master CSV file so I could then process the data. Opening up each text file and then copying and pasting just seemed really dumb, not to mention slow, so I thought there must be a better way. After some Googling I found this command line script that would combine .txt files into one file and add a new line after each: \n\nawk 1 *.txt > finalfile.txt\n\nBut that wasn\u2019t what I was ideally after. I wanted to merge the CSV files, keeping the first row of the first file (the column headings) and then ignore the first row of subsequent files. Sure enough I found the answer after some Googling and it worked like a charm. Apologies to the original author but I can\u2019t remember where I found it, but you, sir or madam, are awesome. Save this as a shell script:\n\nFIRST=\n\nfor FILE in *.csv\n do\n exec 5<\"$FILE\" # Open file\n read LINE <&5 # Read first line\n [ -z \"$FIRST\" ] && echo \"$LINE\" # Print it only from first file\n FIRST=\"no\"\n\n cat <&5 # Print the rest directly to standard output\n exec 5<&- # Close file\n # Redirect stdout for this section into file.out \n\ndone > file.out\n\nCreate a symbolic link to another file or folder\n\nOftentimes, I\u2019ll find myself hunting through a load of directories to load a file to be processed, like a CSV file. Use a symbolic link (in the Terminal) to place a link on your desktop or wherever is most convenient and it\u2019ll save you loads of time. Especially great if you\u2019re going through a Java file dialogue box in Processing or something that doesn\u2019t allow the normal Mac dialog box or aliases.\n\ncd /DirectoryYouWantShortcutToLiveIn\nln -s /Directory/You/Want/ShortcutTo/ TheShortcut\n\nYou can do it, in the mix\n\nI hope you\u2019ve found some of the above useful and that they\u2019ve inspired a few ideas here and there. Feel free to tell me better ways of doing things or offer up any other handy pieces of code. Most of all though, collect, remix and combine the things you discover to make lovely new things.", "year": "2012", "author": "Brendan Dawes", "author_slug": "brendandawes", "published": "2012-12-17T00:00:00+00:00", "url": "https://24ways.org/2012/cut-copy-paste/", "topic": "code"} {"rowid": 75, "title": "A Harder-Working Class", "contents": "Class is only becoming more important. Focusing on its original definition as an attribute for grouping (or classifying) as well as linking HTML to CSS, recent front-end development practices are emphasizing class as a vessel for structured, modularized style packages. These patterns reduce the need for repetitive declarations that can seriously bloat file sizes, and instil human-readable understanding of how the interface, layout, and aesthetics are constructed.\n\nIn the next handful of paragraphs, we will look at how these emerging practices \u2013 such as object-oriented CSS and SMACSS \u2013 are pushing the relevance of class. We will also explore how HTML and CSS architecture can be further simplified, performance can be boosted, and CSS utility sharpened by combining class with the attribute selector.\n\nA primer on attribute selectors\n\nWhile attribute selectors were introduced in the CSS 2 spec, they are still considered rather exotic. These well-established and well-supported features give us vastly improved flexibility in targeting elements in CSS, and offer us opportunities for smarter markup. With an attribute selector, you can directly style an element based on any of its unique \u2013 or uniquely shared \u2013 attributes, without the need for an ID or extra classes. Unlike pseudo-classes, pseudo-elements, and other exciting features of CSS3, attribute selectors do not require any browser-specific syntax or prefix, and are even supported in Internet Explorer 7. \n\nFor example, say we want to target all anchor tags on a page that link to our homepage. Where otherwise we might need to manually identify and add classes to the HTML for these specific links, we could simply write:\n\n[href=index.html] { }\n\nThis selector reads: target every element that has an href attribute of \u201cindex.html\u201d. \n\nAttribute selectors are more faceted, though, as they also give us some very simple regular expression-like logic that helps further narrow (or widen) a selector\u2019s scope. In our previous example, what if we wanted to also give indicative styles to any anchor tag linking to an external site? With no way to know what the exact href value would be for every external link, we need to use an expression to match a common aspect of those links. In this case, we know that all external links need to start with \u201chttp\u201d, so we can use that as a hook:\n\n[href^=http] { }\n\nThe selector here reads: target every element that has an href attribute that begins with \u201chttp\u201d (which will also include \u201chttps\u201d). The ^= means \u201cstarts with\u201d. There are a few other simple expressions that give us a lot of flexibility in targeting elements, and I have found that a deep understanding of these and other selector types to be very useful.\n\nThe class-attribute selector\n\nBy matching classes with the attribute selector, CSS can be pushed to accomplish some exciting new feats. What I call a class-attribute selector combines the advantages of classes with attribute selectors by targeting the class attribute, rather than a specific class. Instead of selecting .urgent, you could select [class*=urgent]. The latter may seem like a more verbose way of accomplishing the former, but each would actually match two subtly different groups of elements.\n\nEric Meyer first explored the possibility of using classes with attribute selectors over a decade ago. While his interest in this technique mostly explored the different facets of the syntax, I have found that using class-attribute selectors can have distinct advantages over either using an attribute selector or a straightforward class selector.\n\nFirst, let\u2019s explore some of the subtleties of why we would target class before other attributes:\n\n\n\tClasses are ubiquitous. They have been supported since the HTML 4 spec was released in 1999. Newer attributes, such as the custom data attribute, have only recently begun to be adopted by browsers.\n\tClasses have multiple ways of being targeted. You can use the class selector or attribute selector (.classname or [class=classname]), allowing more flexible specificity than resorting to an ID or !important.\n\tClasses are already widely used, so adding more classes will usually require less markup than adding more attributes.\n\tClasses were designed to abstractly group and specify elements, making them the most appropriate attribute for styling using object-oriented methods (as we will learn in a moment).\n\n\nAlso, as Meyer pointed out, we can use the class-attribute selector to be more strict about class declarations. Of these two elements:\n\n<h2 class=\"very urgent\">\n\n<h2 class=\"urgent\">\n\n\u2026only the second h2 would be selected by [class=urgent], while .urgent would select both. The use of = matches any element with the exact class value of \u201curgent\u201d. Eric explores these nuances further in his series on attribute selectors, but perhaps more dramatic is the added power that class-attribute selectors can bring to our CSS.\n\nMore object-oriented, more scalable and modular\n\nNicole Sullivan has been pushing abstracted, object-oriented thinking in CSS development for years now. She has shared stacks of knowledge on how behemoth sites have seen impressive gains in maintenance overhead and CSS file sizes by leaning heavier on classes derived from common patterns. Jonathan Snook also speaks, writes and is genuinely passionate about improving our markup by using more stratified and modular class name conventions. With SMACSS, he shows this to be highly useful across sites \u2013 both complex and simple \u2013 that exhibit repeated design patterns. Sullivan and Snook both push the use of class for styling over other attributes, and many front-end developers are fast advocating such thinking as best practice.\n\nWith class-attribute selectors, we can further abstract our CSS, pushing its scalability. In his chapter on modules, Snook gives the example of a .pod class that might represent a certain set of styles. A .pod style set might be used in varying contexts, leading to CSS that might normally look like this:\n\n.pod { }\nform .pod { }\naside .pod { }\n\nAccording to Snook, we can make these styles more portable by targeting more verbose classes, rather than context:\n\n.pod { }\n.pod-form { }\n.pod-sidebar { }\n\n\u2026resulting in the following HTML:\n\n<div class=\"pod\">\n<div class=\"pod pod-form\">\n<div class=\"pod pod-sidebar\">\n\nThis divorces the <div>\u2019s styles from its context, making it applicable to any situation in which it is needed. The markup is clean and portable, and the classes are imbued with meaning as to what module they belong to. \n\nUsing class-attribute selectors, we can simplify this further:\n\n[class*=pod] { }\n.pod-form { }\n.pod-sidebar { }\n\nThe *= tells the browser to look for any element with a class attribute containing \u201cpod\u201d, so it matches \u201cpod\u201d, \u201cpod-form\u201d, \u201cpod-sidebar\u201d, etc. This allows only one class per element, resulting in simpler HTML:\n\n<div class=\"pod\">\n<div class=\"pod-form\">\n<div class=\"pod-sidebar\">\n\nWe could further abstract the concept of \u201cform\u201d and \u201csidebar\u201d adjustments if we knew that each of those alterations would always need the same treatment.\n\n/* Modules */\n[class*=pod] { }\n[class*=btn] { }\n\n/* Alterations */\n[class*=-form] { }\n[class*=-sidebar] { }\n\nIn this case, all elements with classes appended \u201c-form\u201d or \u201c-sidebar\u201d would be altered in the same manner, allowing the markup to stay simple:\n\n<form>\n <h2 class=\"pod-form\">\n <a class=\"btn-form\" href=\"#\">\n\n<aside>\n <h2 class=\"pod-sidebar\">\n <a class=\"btn-sidebar\" href=\"#\">\n\n50+ shades of specificity\n\nClasses are just powerful enough to override element selectors and default styling, but still leave room to be trumped by IDs and !important styles. This makes them more suitable for object-oriented patterns and helps avoid messy specificity issues that can not only be a pain for developers to maintain, but can also affect a site\u2019s performance. As Sullivan notes, \u201cIn almost every case, classes work well and have fewer unintended consequences than either IDs or element selectors\u201d. Proper use of specificity and cascade is crucial in building straightforward, efficient CSS.\n\nOne interesting aspect of attribute selectors is that they can be compounded for increasing levels of specificity. Attribute selectors are assigned a specificity level of ten, the same as class selectors, but both class and attribute selectors can be chained together, giving them more and more specificity with each link. Some examples:\n\n.box { } \n/* Specificity of 10 */\n\n.box.promo { } \n/* Specificity of 20 */\n\n[class*=box] { } \n/* Specificity of 10 */\n\n[class*=box][class*=promo] { } \n/* Specificity of 20 */\n\nYou can chain both types together, too:\n\n.box[class*=promo] { } \n/* Specificity of 20 */\n\nI was amused to find, though, that you can chain the exact same class and attribute selectors for infinite levels of specificity\n\n.box { } \n/* Specificity of 10 */\n\n.box.box { } \n/* Specificity of 20 */\n\n.box.box.box { } \n/* Specificity of 30 */\n\n[class*=box] { }\n/* Specificity of 10 */\n\n[class*=box][class*=box] { }\n/* Specificity of 20 */\n\n[class*=box][class*=box][class*=box] { }\n/* Specificity of 30 */\n\n.box[class*=box].box[class*=box] { } \n/* Specificity of 40 */\n\nTo override .box styles for promo, we wouldn\u2019t need to add an ID, change the order of .promo and .box in the CSS, or resort to an !important style. Granted, any issue that might need this fine level of specificity tweaking could probably be better solved with clever cascades, but having options never hurts.\n\nSmarter CSS\n\nOne of the most powerful aspects of the class-attribute selector is its ability to expand the simple logic found in CSS. When developing Gridset (an online tool for building grids and outputting them as CSS), I realized that with the right class name conventions, class-attribute selectors would allow the CSS to be smart enough to automatically adjust for column offsets without the need for extra classes. This imbued the CSS output with logic that other frameworks lacked, and makes a developer\u2019s job much easier. \n\nSay you need an element that spans column five (c5) to column six (c6) on your grid, and is preceded by an element spanning column one (c1) to column three (c3). The CSS can anticipate such a scenario:\n\n.c1-c3 + .c5-c6 {\n margin-left: 25%; /* \u2026or the width of column four plus two gutter widths */\n}\n\n\u2026but to accommodate all of the margin offsets that could span that same gap, we would need to write a rather protracted list for just a six column grid:\n\n.c1-c3 + .c5-c6,\n.c1-c3 + .c5,\n.c2-c3 + .c5-c6,\n.c2-c3 + .c5,\n.c3 + .c5-c6,\n.c3 + .c5 {\n margin-left: 25%; \n}\n\nNow imagine how the verbosity compounds when we repeat this type of declaration for every possible margin in a grid. The more columns added to the grid, the longer this selector list would get, too, making the CSS harder for the developer to maintain and slowing the load time. Using class-attribute selectors, though, this can be much simpler:\n\n[class*=c3] + [class*=c5] {\n margin-left: 25%;\n}\n\nI\u2019ve detailed how we extract as much logic as possible from as little CSS as needed on the Gridset blog.\n\nMore flexible selectors\n\nIn a recent project, I was working with Drupal-generated classes to change styles for certain special pages on a site. Without being able to change the code base, I was left trying to find some specific aspect of the generated HTML to target. I noticed that every special page was given a prefixed class, unique to the page, resulting in CSS like this:\n\n.specialpage-about,\n.specialpage-contact,\n.specialpage-info,\n\u2026\n\n\u2026and the list kept growing with each new special page. Such bloat would lead to problems down the line, and add development overhead to editorial decisions, which was a situation we were trying to avoid. I was easily able to fix this, though, with a concise class-attribute selector:\n\n[class*=specialpage-]\n\nThe CSS was now flexible enough to accommodate both the editorial needs of the client, and the development restrictions of the CMS.\n\nSelector performance\n\nAs Snook tells us in his chapter on Selector Performance, selectors are read by the browser from right to left, matching every element that adheres to each rule (or part of the selector). The more specific we can make the right-most rules \u2013 and every other part of your selectors \u2013 the more performant your CSS will be. So this selector:\n\n.home-page .promo .main-header\n\n\u2026would be more performant than:\n\n.home-page div header\n\n\u2026because there are likely many more header and div elements on the page, but not so many elements with those specific classes.\n\nNow, the class-attribute selector could be more general than a class selector, but not by much. I ran numerous tests based on the work of Steve Souders (and a few others) to test a class-attribute selector against a normal class selector. Given that Javascript will freeze during style rendering, I created a script that will add, then remove, a stylesheet on a page 5000 times, and measure only the time that elapses during the rendering freeze. The script runs four tests, essentially: one where a class selector and class-attribute Selector match a single element, and one they match multiple elements on the page.\n\nAfter running the test over 100 times and averaging the results, I have not seen a significant difference in rendering times. (As of this writing, the class-attribute selector has been 0.398% slower on average.) View the results here.\n\nGiven the sheer amount of bytes potentially saved by reducing selector lists, though, I am confident class-attribute selectors could shorten load times on larger sites and, at the very least, save precious development time.\n\nConclusion\n\nWith its flexibility and broad remit, class has at times been derided as too lenient, allowing CMSes and lazy developers to fill its values with presentational hacks or verbose gibberish. There have even been calls for an early retirement. Class continues, though, to be one of our most crucial tools.\n\nFront-end developers are rightfully eager to expand production abilities through innovations such as Sass or LESS, but this should not preclude us from honing the tools we already know as well. Every technique demonstrated in this article was achievable over a decade ago and most of the same thinking could be applied to IDs, rels, or any other attribute (though the reasons listed above give class an edge). The recent advent of methods such as object-oriented CSS and SMACSS shows there is still much room left to expand what simple HTML and CSS can accomplish. Progress may not always be found in the innovation of our tools, but through sharpening our understanding of them.", "year": "2012", "author": "Nathan Ford", "author_slug": "nathanford", "published": "2012-12-15T00:00:00+00:00", "url": "https://24ways.org/2012/a-harder-working-class/", "topic": "code"} {"rowid": 92, "title": "Redesigning the Media Query", "contents": "Responsive web design is showing us that designing content is more important than designing containers. But if you\u2019ve given RWD a serious try, you know that shifting your focus from the container is surprisingly hard to do. There are many factors and\ninstincts working against you, and one culprit is a perpetrator you\u2019d least suspect.\n\nThe media query is the ringmaster of responsive design. It lets us establish the rules of the game and gives us what we need most: control. However, like some kind of evil double agent, the media query is actually working against you.\n\nIts very nature diverts your attention away from content and forces you to focus on the container.\n\nThe very act of choosing a media query value means choosing a screen size.\n\nLook at the history of the media query\u2014it\u2019s always been about the container. Values like screen, print, handheld and tv don\u2019t have anything to do with content. The modern media query lets us choose screen dimensions, which is great because it makes RWD possible. But it\u2019s still the act of choosing something that is completely unpredictable.\n\nContent should dictate our breakpoints, not the container. In order to get our focus back to the only thing that matters, we need a reengineered media query\u2014one that frees us from thinking about screen dimensions. A media query that works for your content, not the window. Fortunately, Sass 3.2 is ready and willing to take on this challenge.\n\nThinking in Columns\n\nFluid grids never clicked for me. I feel so disoriented and confused by their squishiness. Responsive design demands their use though, right?\n\nI was ready to surrender until I found a grid that turned my world upright again. The Frameless Grid by Joni Korpi demonstrates that column and gutter sizes can stay fixed. As the screen size changes, you simply add or remove columns to accommodate. This made sense to me and armed with this concept I was able to give Sass the first component it needs to rewrite the media query: fixed column and gutter size variables.\n\n$grid-column: 60px;\n$grid-gutter: 20px;\n\nWe\u2019re going to want some resolution independence too, so let\u2019s create a function that converts those nasty pixel values into ems.\n\n@function em($px, $base: $base-font-size) {\n\t@return ($px / $base) * 1em;\n}\n\nWe now have the components needed to figure out the width of multiple columns in ems. Let\u2019s put them together in a function that will take any number of columns and return the fixed width value of their size.\n\n@function fixed($col) {\n\t@return $col * em($grid-column + $grid-gutter)\n}\n\nWith the math in place we can now write a mixin that takes a column count as a parameter, then generates the perfect media query necessary to fit that number of columns on the screen. We can also build in some left and right margin for our layout by adding an additional gutter value (remembering that we already have one gutter built into our fixed function).\n\n@mixin breakpoint($min) {\n\t@media (min-width: fixed($min) + em($grid-gutter)) {\n\t\t@content\n\t}\n}\n\nAnd, just like that, we\u2019ve rewritten the media query. Instead of picking a minimum screen size for our layout, we can simply determine the number of columns needed. Let\u2019s add a wrapper class so that we can center our content on the screen.\n\n@mixin breakpoint($min) {\n @media (min-width: fixed($min) + em($grid-gutter)) {\n\t.wrapper {\n\t\twidth: fixed($min) - em($grid-gutter);\n\t\tmargin-left: auto; margin-right: auto;\n\t}\n\t@content\n }\n}\n\nDesigning content with a column count gives us nice, easy, whole numbers to work with. Sizing content, sidebars or widgets is now as simple as specifying a single-digit number.\n\n@include breakpoint(8) {\n\t.main { width: fixed(5); }\n\t.sidebar { width: fixed(3); }\n}\n\nThose four lines of Sass just created a responsive layout for us. When the screen is big enough to fit eight columns, it will trigger a fixed width layout. And give widths to our main content and sidebar. The following is the outputted CSS\u2026\n\n@media (min-width: 41.25em) {\n .wrapper {\n width: 38.75em;\n margin-left: auto; margin-right: auto;\n }\n .main { width: 25em; }\n .sidebar { width: 15em; }\n}\n\nDemo\n\nI\u2019ve created a Codepen demo that demonstrates what we\u2019ve covered so far. I\u2019ve added to the demo some grid classes based on Griddle by Nicolas Gallagher to create a floatless layout. I\u2019ve also added a CSS gradient overlay to help you visualize columns. Try changing the column variable sizes or the breakpoint includes to see how the layout reacts to different screen sizes.\n\nResponsive Images\n\nResponsive images are a serious problem, but I\u2019m excited to see the community talk so passionately about a solution. Now, there are some excellent stopgaps while we wait for something official, but these solutions require you to mirror your breakpoints in JavaScript or HTML. This poses a serious problem for my Sass-generated media queries, because I have no idea what the real values of my breakpoints are anymore. For responsive images to work, JavaScript needs to recognize which media query is active so that proper images can be loaded for that layout.\n\nWhat I need is a way to label my breakpoints. Fortunately, people much smarter than I have figured this out. Jeremy Keith devised a labeling method by using CSS-generated content as the storage method for breakpoint labels. We can use this technique in our breakpoint mixin by passing a label as another argument.\n\n@include breakpoint(8, 'desktop') { /* styles */ }\n\nSass can take that label and use it when writing the corresponding media query. We just need to slightly modify our breakpoint mixin.\n\n@mixin breakpoint($min, $label) {\n @media (min-width: fixed($min) + em($grid-gutter)) {\n\n // label our mq with CSS generated content\n\tbody::before { content: $label; display: none; }\n\n\t.wrapper {\n\t\twidth: fixed($min) - em($grid-gutter);\n\t\tmargin-left: auto; margin-right: auto;\n\t}\n\t@content\n }\n}\n\nThis allows us to label our breakpoints with a user-friendly string. Now that our media queries are defined and labeled, we just need JavaScript to step in and read which label is active.\n\n// get css generated label for active media query\nvar label = getComputedStyle(document.body, '::before')['content'];\n\nJavaScript now knows which layout is active by reading the label in the current media query\u2014we just need to match that label to an image. I prefer to store references to different image sizes as data attributes on my image tag.\n\n<img class=\"responsive-image\" data-mobile=\"mobile.jpg\" data-desktop=\"desktop.jpg\" />\n<noscript><img src=\"desktop.jpg\" /></noscript>\n\nThese data attributes have names that match the labels set in my CSS. So while there is some duplication going on, setting a keyword like \u2018tablet\u2019 in two places is much easier than hardcoding media query values. With matching labels in CSS and HTML our script can marry the two and load the right sized image for our layout.\n\n// get css generated label for active media query\nvar label = getComputedStyle(document.body, '::before')['content'];\n\n// select image\nvar $image = $('.responsive-image');\n\n// create source from data attribute\n$image.attr('src', $image.data(label));\n\nDemo\n\nWith some slight additions to our previous Codepen demo you can see this responsive image technique in action. While the above JavaScript will work it is not nearly robust enough for production so the demo uses a jQuery plugin that can accomodate multiple images, reloading on screen resize and fallbacks if something doesn\u2019t match up.\n\nCreating a Framework\n\nThis media query mixin and responsive image JavaScript are the center piece of a front end framework I use to develop websites. It\u2019s a fluid, mobile first foundation that uses the breakpoint mixin to structure fixed width layouts for tablet and desktop. Significant effort was focused on making this framework completely cross-browser. For example, one of the problems with using media queries is that essential desktop structure code ends up being hidden from legacy Internet Explorer. Respond.js is an excellent polyfill, but if you\u2019re comfortable serving a single desktop layout to older IE, we don\u2019t need JavaScript. We simply need to capture layout code outside of a media query and sandbox it under an IE only class name.\n\n// set IE fallback layout to 8 columns\n$ie-support = 8;\n\n// inside of our breakpoint mixin (but outside the media query)\n@if ($ie-support and $min <= $ie-support) {\n\t.lt-ie9 { @content; }\n}\n\nPerspective Regained\n\nThinking in columns means you are thinking about content layout. How big of a screen do you need for 12 columns? Who cares? Having Sass write media queries means you can use intuitive numbers for content layout. A fixed grid means more layout control and less edge cases to test than a fluid grid. Using CSS labels for activating responsive images means you don\u2019t have to duplicate breakpoints across separations of concern. \n\nIt\u2019s a harmonious blend of approaches that gives us something we need\u2014responsive design that feels intuitive. And design that, from the very outset, focuses on what matters most. Just like our kindergarten teachers taught us: It\u2019s what\u2019s inside that counts.", "year": "2012", "author": "Les James", "author_slug": "lesjames", "published": "2012-12-13T00:00:00+00:00", "url": "https://24ways.org/2012/redesigning-the-media-query/", "topic": "code"} {"rowid": 79, "title": "Responsive Images: What We Thought We Needed", "contents": "If you were to read a web designer\u2019s Christmas wish list, it would likely include a solution for displaying images responsively. For those concerned about users downloading unnecessary image data, or serving images that look blurry on high resolution displays, finding a solution has become a frustrating quest.\n\nHaving experimented with complex and sometimes devilish hacks, consensus is forming around defining new standards that could solve this problem. Two approaches have emerged.\n\nThe <picture> element markup pattern was proposed by Mat Marquis and is now being developed by the Responsive Images Community Group. By providing a means of declaring multiple sources, authors could use media queries to control which version of an image is displayed and under what conditions:\n\n<picture width=\"500\" height=\"500\">\n <source media=\"(min-width: 45em)\" src=\"large.jpg\">\n <source media=\"(min-width: 18em)\" src=\"med.jpg\">\n <source src=\"small.jpg\">\n <img src=\"small.jpg\" alt=\"\">\n <p>Accessible text</p>\n</picture>\n\nA second proposal put forward by Apple, the srcset attribute, uses a more concise syntax intended for use with the <img> element, although it could be compatible with the <picture> element too. This would allow authors to provide a set of images, but with the decision on which to use left to the browser:\n\n<img src=\"fallback.jpg\" alt=\"\" srcset=\"small.jpg 640w 1x, small-hd.jpg 640w 2x, med.jpg 1x, med-hd.jpg 2x \">\n\nEnter Scrooge\n\n\n\tMen\u2019s courses will foreshadow certain ends, to which, if persevered in, they must lead.\nEbenezer Scrooge\n\n\nGiven the complexity of this issue, there\u2019s a heated debate about which is the best option. Yet code belies a certain truth. That both feature verbose and opaque syntax, I\u2019m not sure either should find its way into the browser \u2013 especially as alternative approaches have yet to be fully explored.\n\nSo, as if to dampen the festive cheer, here are five reasons why I believe both proposals are largely redundant.\n\n1. We need better formats, not more markup\n\nAs we move away from designs defined with fixed pixel values, bitmap images look increasingly unsuitable. While simple images and iconography can use scalable vector formats like SVG, for detailed photographic imagery, raster formats like GIF, PNG and JPEG remain the only suitable option.\n\nThere is scope within current formats to account for varying bandwidth but this requires cooperation from browser vendors. Newer formats like JPEG2000 and WebP generate higher quality images with smaller file sizes, but aren\u2019t widely supported.\n\nWhile it\u2019s tempting to try to solve this issue by inventing new markup, the crux of it remains at the file level.\n\nDaan Jobsis\u2019s experimentation with image compression strengthens this argument. He discovered that by increasing the dimensions of a JPEG image while simultaneously reducing its quality, a smaller files could be produced, with the resulting image looking just as good on both standard and high-resolution displays.\n\nThis may be a hack in lieu of a more permanent solution, but it\u2019s applied in the right place. Easy to accomplish with existing tools and without compatibility issues, it has few downsides. Further experimentation in this area should be encouraged, with standardisation efforts more helpful if focused on developing new image formats or, preferably, extending existing ones.\n\n2. Art direction doesn\u2019t belong in markup\n\nA desired benefit of the <picture> markup pattern is to allow for greater art direction. For example, rather than scaling down images on smaller displays to the point that their content is hard to discern, we could present closer crops instead:\n\n\n\nThis can be achieved with CSS of course, although with a download penalty for those parts of an image not shown. This point may be negligible, however, since in the context of adaptable layouts, these hidden areas may end up being revealed anyway.\n\nArt direction concerns design, not content. If we wish to maintain a separation of concerns, including presentation within our markup seems misguided.\n\n3. The size of a display has little relation to the size of an image\n\nBy using media queries, the <picture> element allows authors to choose which characteristics of the screen or viewport to query for different images to be displayed.\n\nIn developing sites at Clearleft, we have noticed that the viewport is essentially arbitrary, with the size of an image\u2019s containing element more important. For example, look at how this grid of images may adapt at different viewport widths:\n\n\n\nAs we build more modular systems, components need to be adaptable in and of themselves. There is a case to be made for developing more contextual methods of querying, rather than those based on attributes of the display.\n\n4. We haven\u2019t lived with the problem long enough\n\nA key strength of the web is that the underlying platform can be continually iterated. This can also be problematic if snap judgements are made about what constitutes an improvement.\n\nThe early history of the web is littered with such examples, be it the perceived need for blinking text or inline typographic styling. To build a platform for the future, additions to it should be carefully considered. And if we want more consistent support across browsers, burdening vendors with an ever increasing list of features seems counterproductive.\n\nOnly once the need for a new feature is sufficiently proven, should we look to standardise it. Before we could declare hover effects, rounded corners and typographic styling in CSS, we used JavaScript as a polyfill. Sure, doing so was painful, but use cases were fully explored, and the CSS specification better reflected the needs of authors.\n\n5. Images and the web aesthetic\n\nThe srcset proposal has emerged from a company that markets its phones as being able to browse the real \u2013 yet squashed down, tapped and zoomable \u2013 web. Perhaps Apple should make its own website responsive before suggesting how the rest of us should do so.\n\nConverserly, while the <picture> proposal has the backing of a few respected developers and designers, it was born out of the work Mat Marquis and Filament Group did for the Boston Globe. As the first large-scale responsive design, this was a landmark project that ignited the responsive web design movement and proved its worth. But it was the first.\n\nIts design shares a vernacular to that of contemporary newspaper websites, with a columnar, image-laden and densely packed layout. Compared to more recent examples \u2013 Quartz, The Next Web and the New York Times Skimmer \u2013 it feels out of step with the future direction of news sites. In seeking out a truer aesthetic for the web in which software interfaces have greater influence, we might discover that the need for responsive images isn\u2019t as great as originally thought.\n\n\n\nBuilding for the future\n\nWith responsive design, we\u2019ve accepted the idea that a fully fluid layout, rather than a set of fixed layouts, is best suited to the web\u2019s unpredictable nature. Current responsive image proposals are antithetical to this approach.\n\nWe need solutions that lack complexity, are device-agnostic and work within existing workflows. Any proposal that requires different versions of the same image to be created, is likely to have to acquiesce under the pressure of reality.\n\nWhile it\u2019s easy to get distracted about the size and quality of an image, and how we might choose to serve it, often the simplest solution is not to include it at all. After years of gluttonous design practice, in which fast connections and expansive display sizes were an accepted norm, we have got use to filling pages with needless images and countless items of page furniture.\n\nTo design more adaptable experiences, the presence of every element needs to be questioned, for its existence requires additional data to be downloaded or futher complexity within a design system. Conditional loading techniques mean that the inclusion of images is no longer a binary choice, but can instead appear in a progressively enhanced manner.\n\nSo here is my proposal. Instead of spending the next year worrying about responsive images, let\u2019s embrace the constraints of the medium, and seek out new solutions that can work within them.", "year": "2012", "author": "Paul Lloyd", "author_slug": "paulrobertlloyd", "published": "2012-12-11T00:00:00+00:00", "url": "https://24ways.org/2012/responsive-images-what-we-thought-we-needed/", "topic": "code"} {"rowid": 76, "title": "Giving CSS Animations and Transitions Their Place", "contents": "CSS animations and transitions may not sit squarely in the realm of the behaviour layer, but they\u2019re stepping up into this area that used to be pure JavaScript territory. Heck, CSS might even perform better than its JavaScript equivalents in some cases. That\u2019s pretty serious! With CSS\u2019s new tricks blurring the lines between presentation and behaviour, it can start to feel bloated and messy in our CSS files. It\u2019s an uncomfortable feeling.\n\nHere are a pair of methods I\u2019ve found to be pretty helpful in keeping the potential bloat and wire-crossing under control when CSS has its hands in both presentation and behaviour.\n\nSame eggs, more baskets\n\nStructuring your CSS to have separate files for layout, typography, grids, and so on is a fairly common approach these days. But which one do you put your transitions and animations in? The initial answer, as always, is \u201cit depends\u201d.\n\nSmall effects here and there will likely sit just fine with your other styles. When you move into more involved effects that require multiple animations and some logic support from JavaScript, it\u2019s probably time to choose none of the above, and create a separate CSS file just for them.\n\nPutting all your animations in one file is a huge help for code organization. Even if you opt for a name less literal than animations.css, you\u2019ll know exactly where to go for anything CSS animation related. That saves time and effort when it comes to editing and maintenance. Keeping track of which animations are still currently used is easier when they\u2019re all grouped together as well. And as an added bonus, you won\u2019t have to look at all those horribly unattractive and repetitive prefixed @-keyframe rules unless you actually need to.\n\nAn animations.css file might look something like the snippet below. It defines each animation\u2019s keyframes and defines a class for each variation of that animation you\u2019ll be using. Depending on the situation, you may also want to include transitions here in a similar way. (I\u2019ve found defining transitions as their own class, or mixin, to be a huge help in past projects for me.)\n\n// defining the animation\n@keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n@-webkit-keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n@-moz-keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n@-ms-keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n\n\u2026\n\n// class that assigns the animation\n\n.catsBackground {\n height: 100%;\n background: transparent url(../endlessKittens.png) 0 0 repeat-y;\n animation: catFall 1s linear infinite;\n -webkit-animation: catFall 1s linear infinite;\n -moz-animation: catFall 1s linear infinite;\n -ms-animation: catFall 1s linear infinite;\n}\n\nIf we don\u2019t need it, why load it?\n\nHaving all those CSS animations and transitions in one file gives us the added flexibility to load them only when we want to. Loading a whole lot of things that will never be used might seem like a bit of a waste.\n\nWhile CSS has us impressed with its motion chops, it falls flat when it comes to the logic and fine-grained control. JavaScript, on the other hand, is pretty good at both those things. Chances are the content of your animations.css file isn\u2019t acting alone. You\u2019ll likely be adding and removing classes via JavaScript to manage your CSS animations at the very least. If your CSS animations are so entwined with JavaScript, why not let them hang out with the rest of the behaviour layer and only come out to play when JavaScript is supported?\n\nDynamically linking your animations.css file like this means it will be completely ignored if JavaScript is off or not supported. No JavaScript? No additional behaviour, not even the parts handled by CSS.\n\n<script>\ndocument.write('<link rel=\"stylesheet\" type=\"text/css\" href=\"animations.css\">');\n</script>\n\nThis technique comes up in progressive enhancement techniques as well, but it can help here to keep your presentation and behaviour nicely separated when more than one language is involved. The aim in both cases is to avoid loading files we won\u2019t be using.\n\nIf you happen to be doing something a bit fancier \u2013 like 3-D transforms or critical animations that require more nuanced fallbacks \u2013 you might need something like modernizr to step in to determine support more specifically. But the general idea is the same.\n\nSumming it all up\n\nUsing a couple of simple techniques like these, we get to pick where to best draw the line between behaviour and presentation based on the situation at hand, not just on what language we\u2019re using. The power of when to separate and how to reassemble the individual pieces can be even greater if you use preprocessors as part of your process. We\u2019ve got a lot of options! The important part is to make forward-thinking choices to save your future self, and even your current self, unnecessary headaches.", "year": "2012", "author": "Val Head", "author_slug": "valhead", "published": "2012-12-08T00:00:00+00:00", "url": "https://24ways.org/2012/giving-css-animations-and-transitions-their-place/", "topic": "code"} {"rowid": 86, "title": "Flashless Animation", "contents": "Animation in a Flashless world\n\nWhen I splashed down in web design four years ago, the first thing I wanted to do was animate a cartoon in the browser. I\u2019d been drawing comics for years, and I\u2019ve wanted to see them come to life for nearly as long. Flash animation was still riding high, but I didn\u2019t want to learn Flash. I wanted to learn JavaScript!\n\nSadly, animating with JavaScript was limiting and resource-intensive. My initial foray into an infinitely looping background did more to burn a hole in my CPU than amaze my friends (although it still looks pretty cool). And there was still no simple way to incorporate audio. The browser technology just wasn\u2019t there.\n\nThings are different now. CSS3 transitions and animations can do most of the heavy lifting and HTML5 audio can serve up the music and audio clips. You can do a lot without leaning on JavaScript at all, and when you lean on JavaScript, you can do so much more!\n\nIn this project, I\u2019m going to show you how to animate a simple walk cycle with looping audio. I hope this will inspire you to do something really cool and impress your friends. I\u2019d love to see what you come up with, so please send your creations my way at rachelnabors.com!\n\nNote: Because every browser wants to use its own prefixes with CSS3 animations, and I have neither the time nor the space to write all of them out, I will use the W3C standard syntaxes; that is, going prefix-less. You can implement them out of the box with something like Prefixfree, or you can add prefixes on your own. If you take the latter route, I recommend using Sass and Compass so you can focus on your animations, not copying and pasting.\n\nThe walk cycle\n\nWalk cycles are the \u201cHello world\u201d of animation. One of the first projects of animation students is to spend hours drawing dozens of frames to complete a simple loopable animation of a character walking.\n\nMost animators don\u2019t have to draw every frame themselves, though. They draw a few key frames and send those on to production animators to work on the between frames (or tween frames). This is meticulous, grueling work requiring an eye for detail and natural movement. This is also why so much production animation gets shipped overseas where labor is cheaper.\n\nLuckily, we don\u2019t have to worry about our frame count because we can set our own frames-per-second rate on the fly in CSS3. Since we\u2019re trying to impress friends, not animation directors, the inconsistency shouldn\u2019t be a problem. (Unless your friend is an animation director.)\n\nThis is a simple walk cycle I made of my comic character Tuna for my CSS animation talk at CSS Dev Conference this year:\n\n\n\nThe magic lies here:\n\nanimation: walk-cycle 1s steps(12) infinite;\n\nBreaking those properties down:\n\nanimation: <name> <duration> <timing-function> <iteration-count>;\n\nwalk-cycle is a simple @keyframes block that moves the background sprite on .tuna around:\n\n@keyframes walk-cycle { \n 0% {background-position: 0 0; }\n 100% {background-position: 0 -2391px;}\n}\n\nThe background sprite has exactly twelve images of Tuna that complete a full walk cycle. We\u2019re setting it to cycle through the entire sprite every second, infinitely. So why isn\u2019t the background image scrolling down the .tuna container? It\u2019s all down to the timing function steps(). Using steps() let us tell the CSS to make jumps instead of the smooth transitions you\u2019d get from something like linear. Chris Mills at dev.opera wrote in his excellent intro to CSS3 animation :\n\n\n\tInstead of giving a smooth animation throughout, [steps()] causes the animation to jump between a set number of steps placed equally along the duration. For example, steps(10) would make the animation jump along in ten equal steps. There\u2019s also an optional second parameter that takes a value of start or end. steps(10, start) would specify that the change in property value should happen at the start of each step, while steps(10, end) means the change would come at the end.\n\n\n(Seriously, go read his full article. I\u2019m not going to touch on half the stuff he does because I cannot improve on the basics any more than he already has.)\n\nThe background\n\nA cat walking in a void is hardly an impressive animation and certainly your buddy one cube over could do it if he chopped up some of those cat GIFs he keeps using in group chat. So let\u2019s add a parallax background! Yes, yes, all web designers signed a peace treaty to not abuse parallax anymore, but this is its true calling\u2014treaty be damned.\n\n\n\nAnd to think we used to need JavaScript to do this! It\u2019s still pretty CPU intensive but much less complicated. We start by splitting up the page into different layers, .foreground, .midground, and .background. We put .tuna in the .midground.\n\n.background has multiple background images, all set to repeat horizontally:\n\nbackground-image:\n url(background_mountain5.png),\n url(background_mountain4.png),\n url(background_mountain3.png),\n url(background_mountain2.png),\n url(background_mountain1.png);\nbackground-repeat: repeat-x;\n\nWith parallax, things in the foreground move faster than those in the background. Next time you\u2019re driving, notice how the things closer to you move out of your field of vision faster than something in the distance, like a mountain or a large building. We can imitate that here by making the background images on top (in the foreground, closer to us) wider than those on the bottom of the stack (in the distance).\n\nThe different lengths let us use one animation to move all the background images at different rates in the same interval of time: \n\nanimation: parallax_bg linear 40s infinite;\n\nThe shorter images have less distance to cover in the same amount of time as the longer images, so they move slower.\n\n\n\nLet\u2019s have a look at the background\u2019s animation:\n\n@keyframes parallax_bg { \n 0% {\n background-position: -2400px 100%, -2000px 100%, -1800px 100%, -1600px 100%, -1200px 100%;\n }\n 100% {\n background-position: 0 100%, 0 100%, 0 100%, 0 100%, 0 100%;\n }\n}\n\nAt 0%, all the background images are positioned at the negative value of their own widths. Then they start moving toward background-position: 0 100%. If we wanted to move them in the reverse direction, we\u2019d remove the negative values at 0% (so they would start at 2400px 100%, 2000px 100%, etc.). Try changing the values in the codepen above or changing background-repeat to none to see how the images play together.\n\n.foreground and .midground operate on the same principles, only they use single background images.\n\nThe music\n\nAfter finishing the first draft of my original walk cycle, I made a GIF with it and posted it on YTMND with some music from the movie Paprika, specifically the track \u201cThe Girl in Byakkoya.\u201d After showing it to some colleagues in my community, it became clear that this was a winning combination sure to drive away dresscode blues. So let\u2019s use HTML5 to get a clip of that music looping in there!\n\nWarning, there is sound. Please adjust your volume or apply headphones as needed.\n\n\n\nWe\u2019re using HTML5 audio\u2019s loop and autoplay abilities to automatically play and loop a sound file on page load:\n\n<audio loop autoplay>\n <source src=\"http://music.com/clip.mp3\" />\n</audio>\n\nUnfortunately, you may notice there is a small pause between loops. HTML5 audio, thou art half-baked still. Let\u2019s hope one day the Web Audio API will be able to help us out, but until things improve, we\u2019ll have to hack our way around these shortcomings.\n\nTurns out there\u2019s a handy little script called seamlessLoop.js which we can use to patch this. Mind you, if we were really getting crazy with the Cheese Whiz, we\u2019d want to get out big guns like sound.js. But that\u2019d be overkill for a mere loop (and explaining the Web Audio API might bore, rather than impress your friends)!\n\nInstalling seamlessLoop.js will get rid of the pause, and now our walk cycle is complete.\n\n(I\u2019ve done some very rough sniffing to see if the browser can play MP3 files. If not, we fall back to using .ogg formatted clips (Opera and Firefox users, you\u2019re welcome).)\n\nReally impress your friends by adding a run cycle\n\nSo we have music, we have a walk cycle, we have parallax. It will be a snap to bring them all together and have a simple, endless animation. But let\u2019s go one step further and knock the socks off our viewers by adding a run cycle.\n\nThe run cycle\n\nTacking a run cycle on to our walk cycle will require a third animation sequence: a transitional animation of Tuna switching from walking to running. I have added all these to the sprite:\n\n\n\nLet\u2019s work on getting that transition down. We\u2019re going to use multiple animations on the same .tuna div, but we\u2019re going to kick them off at different intervals using animation-delay\u2014no JavaScript required! Isn\u2019t that magical?\n\n\n\nIt requires a wee bit of math (not much, it doesn\u2019t hurt) to line them up. We want to:\n\n\n\tLoop the walk animation twice\n\tPlay the transitional cycle once (it has a finite beginning and end perfectly drawn to pick up between the last frame of the walk cycle and the first frame of the run cycle\u2014no looping this baby)\n\tRUN FOREVER.\n\n\nUsing the pattern animation: <name> <duration> <timing-function> <delay> <iteration-count>, here\u2019s what that looks like:\n\nanimation:\n walk-cycle 1s steps(12) 2,\n walk-to-run .75s steps(12) 2s 1,\n run-cycle .75s steps(13) 2.75s infinite;\n\nI played with the times to get make the movement more realistic. You may notice that the running animation looks smoother than the walking animation. That\u2019s because it has 13 keyframes running over .75 second instead of 12 running in one second. Remember, professional animation studios use super-high frame counts. This little animation isn\u2019t even up to PBS\u2019s standards!\n\nThe music: extended play with HTML5 audio sprites\n\nMy favorite part in the The Girl in Byakkoya is when the calm opening builds and transitions into a bouncy motif. I want to start with Tuna walking during the opening, and then loop the running and bounciness together for infinity.\n\n\n\tThe intro lasts for 24 seconds, so we set our 1 second walk cycle to run for 24 repetitions: \nwalk-cycle 1s steps(12) 24\n\tWe delay walk-to-run by 24 seconds so it runs for .75 seconds before\u2026\n\tWe play run-cycle at 24.75 seconds and loop it infinitely\n\n\nFor the music, we need to think of it as two parts: the intro and the bouncy loop. We can do this quite nicely with audio sprites: using one HTML5 audio element and using JavaScript to change the play head location, like skipping tracks with a CD player. Although this technique will result in a small gap in music shifts, I think it\u2019s worth using here to give you some ideas.\n\n// Get the audio element\nvar byakkoya = document.querySelector('audio');\n// create function to play and loop audio\nfunction song(a){\n //start playing at 0\n a.currentTime = 0;\n a.play();\n //when we hit 64 seconds...\n setTimeout(function(){\n // skip back to 24.5 seconds and keep playing...\n a.currentTime = 24.55;\n // then loop back when we hit 64 again, or every 59.5 seconds.\n setInterval(function(){\n a.currentTime = 24.55;\n },39450);\n },64000);\n}\n\nThe load screen\n\nI\u2019ve put it off as long as I can, but now that the music and the CSS are both running on their own separate clocks, it\u2019s imperative that both images and music be fully downloaded and ready to run when we kick this thing off. So we need a load screen (also, it\u2019s nice to give people a heads-up that you\u2019re about to blast them with music, no matter how wonderful that music may be).\n\nSince the two timers are so closely linked, we\u2019d best not run the animations until we run the music:\n\n* { animation-play-state: paused; }\n\nanimation-play-state can be set to paused or running, and it\u2019s the most useful thing you will learn today.\n\nFirst we use an event listener to see when the browser thinks we can play through from the beginning to end of the music without pause for buffering:\n\nbyakkoya.addEventListener(\"canplaythrough\", function () { });\n\n(More on HTML5 audio\u2019s media events at HTML5doctor.com)\n\nInside our event listener, I use a bit of jQuery to add class of .playable to the body when we\u2019re ready to enable the play button:\n\n$(\"body\").addClass(\"playable\");\n $(\"#play-me\").html(\"Play me.\").click(function(){\n song(byakkoya);\n $(\"body\").addClass(\"playing\");\n });\n\nThat .playing class is special because it turns on the animations at the same time we start playing the song:\n\n.playing * { animation-play-state: running; }\n\nThe background\n\nWe\u2019re almost done here! When we add the background, it needs to speed up at the same time that Tuna starts running. The music picks up speed around 24.75 seconds in, and so we\u2019re going to use animation-delay on those backgrounds, too.\n\nThis will require some math. If you try to simply shorten the animation\u2019s duration at the 24.75s mark, the backgrounds will, mid-scroll, jump back to their initial background positions to start the new animation! Argh! So let\u2019s make a new @keyframe and calculate where the background position would be just before we speed up the animation.\n\nHere\u2019s the formula:\n\nnew 0% value = delay \u00f7 old duration \u00d7 length of image\n\nnew 100% value = new 0% value + length of image\n\nHere\u2019s the formula put to work on a smaller scale:\n\n\n\nVoil\u00e0! The finished animation!\n\n\n\nI\u2019ve always wanted to bring my illustrations to life. Then I woke up one morning and realized that I had all the tools to do so in my browser and in my head. Now I have fallen in love with Flashless animation.\n\nI\u2019m sure there will be detractors who say HTML wasn\u2019t meant for this and it\u2019s a gross abuse of the DOM! But I say that these explorations help us expand what we expect from devices and software and challenge us in good ways as artists and programmers. The browser might not be the most appropriate place for animation, but is certainly a fun place to start.\n\nThere is so much you can do with the spec implemented today, and so much of the territory is still unexplored. I have not yet begun to show you everything. In eight months I expect this demo will represent the norm, not the bleeding edge. I look forward to seeing the wonderful things you create.\n\n(Also, someone, please, do something about that gappy HTML5 audio looping. It\u2019s a crying shame!)", "year": "2012", "author": "Rachel Nabors", "author_slug": "rachelnabors", "published": "2012-12-06T00:00:00+00:00", "url": "https://24ways.org/2012/flashless-animation/", "topic": "code"} {"rowid": 80, "title": "HTML5 Video Bumpers", "contents": "Video is a bigger part of the web experience than ever before. With native browser support for HTML5 video elements freeing us from the tyranny of plugins, and the availability of faster internet connections to the workplace, home and mobile networks, it\u2019s now pretty straightforward to publish video in a way that can be consumed in all sorts of ways on all sorts of different web devices.\n\nI recently worked on a project where the client had shot some dedicated video shorts to publish on their site. They also had some five-second motion graphics produced to top and tail the videos with context and branding. This pretty common requirement is a great idea on the web, where a user might land at your video having followed a link and be viewing a page without much context.\n\nKnown as bumpers, these short introduction clips help brand a video and make it look a lot more professional.\n\n\n\nAdding bumpers to a video\n\nThe simplest way to add bumpers to a video would be to edit them on to the start and end of the video file itself. Cooking the bumpers into the video file is easy, but should you ever want to update them it can become a real headache. If the branding needs updating, for example, you\u2019d need to re-edit and re-encode all your videos. Not a fun task.\n\nWhat if the bumpers could be added dynamically? That would enable you to use the same bumper for multiple videos (decreasing download time for users who might watch more than one) and to update the bumpers whenever you wanted. You could change them seasonally, update them for special promotions, run different advertising slots, perform multivariate testing, or even target different bumpers to different users.\n\nThe trade-off, of course, is that if you dynamically add your bumpers, there\u2019s a chance that a user in a given circumstance might not see the bumper. For example, if the main video feature was uploaded to YouTube, you\u2019d have no way to control the playback. As always, you need to weigh up the pros and cons and make your choice.\n\nHTML5 bumpers\n\nIf you wanted to dynamically add bumpers to your HTML5 video, how would you go about it? That was the question I found myself needing to answer for this particular client project.\n\nMy initial thought was to treat it just like an image slideshow. If I were building a slideshow that moved between images, I\u2019d use CSS absolute positioning with z-index to stack the images up on top of each other in a pile, with the first image on top. To transition to the second image, I\u2019d use JavaScript to fade the top image out, revealing the second image beneath it.\n\n\n\nNow that video is just a native object in the DOM, just like an image, why not do the same? Stack the videos up with the opening bumper on top, listen for the video\u2019s onended event, and fade it out to reveal the main feature behind. Good idea, right?\n\nWrong\n\nRemember that this is the web. It\u2019s never going to be that easy. The problem here is that many non-desktop devices use native, dedicated video players. Think about watching a video on a mobile phone \u2013 when you play the video, the phone often goes full-screen in its native player, leaving the web page behind. There\u2019s no opportunity to fade or switch z-index, as the video isn\u2019t being viewed in the page. Your page is left powerless. Powerless!\n\n\n\nSo what can we do? What can we control?\n\nThose of us with particularly long memories might recall a time before CSS, when we\u2019d have to use JavaScript to perform image rollovers. As CSS background images weren\u2019t a practical reality, we would use lots of <img> elements, and perform a rollover by modifying the src attribute of the image. \n\nTurns out, this old trick of modifying the source can help us out with video, too. In most cases, modifying the src attribute of a <video> element, or perhaps more likely the src attribute of a source element, will swap from one video to another.\n\nSwappin\u2019 it\n\nLet\u2019s take a deliberately simple example of a super-basic video tag:\n\n<video src=\"mycat.webm\" controls>no fallback coz i is lame, innit.</video>\n\nWe could very simply write a script to find all video tags and give them a new src to show our bumper.\n\n<script>\n\tvar videos, i, l;\n\tvideos = document.getElementsByTagName('video');\n\tfor(i=0, l=videos.length; i<l; i++) {\n\t\tvideos[i].setAttribute('src', 'bumper-in.webm');\n\t}\n</script>\n\nView the example in a browser with WebM support. You\u2019ll see that the video is swapped out for the opening bumper. Great!\n\nBeefing it up\n\nOf course, we can\u2019t just publish video in one format. In practical use, you need a <video> element with multiple <source> elements containing your different source formats.\n\n<video controls>\n <source src=\"mycat.mp4\" type=\"video/mp4\" />\n <source src=\"mycat.webm\" type=\"video/webm\" />\n <source src=\"mycat.ogv\" type=\"video/ogg\" />\n</video>\n\nThis time, our script needs to loop through the sources, not the videos. We\u2019ll use a regular expression replacement to swap out the file name while maintaining the correct file extension.\n\n<script>\n var sources, i, l, orig;\n sources = document.getElementsByTagName('source');\n for(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('src');\n sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));\n // reload the video\n sources[i].parentNode.load();\n }\n</script>\n\nThe difference this time is that when changing the src of a <source> we need to call the .load() method on the video to get it to acknowledge the change.\n\nSee the code in action, this time in a wider range of browsers.\n\nBut, my video!\n\nI guess we should get the original video playing again. Keeping the same markup, we need to modify the script to do two things:\n\n\n\tStore the original src in a data- attribute so we can access it later\n\tAdd an event listener so we can detect the end of the bumper playing, and load the original video back in\n\n\nAs we need to loop through the videos this time to add the event listener, I\u2019ve moved the .load() call into that loop. It\u2019s a bit more efficient to call it only once after modifying all the video\u2019s sources.\n\n<script>\nvar videos, sources, i, l, orig;\nsources = document.getElementsByTagName('source');\nfor(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('src');\n sources[i].setAttribute('data-orig', orig);\n sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));\n}\nvideos = document.getElementsByTagName('video');\nfor(i=0, l=videos.length; i<l; i++) {\n videos[i].load();\n videos[i].addEventListener('ended', function(){\n sources = this.getElementsByTagName('source');\n for(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('data-orig');\n if (orig) {\n sources[i].setAttribute('src', orig);\n }\n sources[i].setAttribute('data-orig','');\n }\n this.load();\n this.play();\n });\n}\n</script>\n\nAgain, view the example to see the bumper play, followed by our spectacular main feature. (That\u2019s my cat, Widget. His interests include sleeping and internet marketing.)\n\nTidying things up\n\nThe final thing to do is add our closing bumper after the main video has played. This involves the following changes:\n\n\n\tWe need to keep track of whether the src has been changed, so we only play the video if it\u2019s changed. I\u2019ve added the modified variable to track this, and it stops us getting into a situation where the video just loops forever.\n\tAdd an else to the event listener, for when the orig is false (so the main feature has been playing) to load in the end bumper. We also check that we\u2019re not already playing the end bumper. Because looping.\n\n\n<script>\nvar videos, sources, i, l, orig, current, modified;\nsources = document.getElementsByTagName('source');\nfor(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('src');\n sources[i].setAttribute('data-orig', orig);\n sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));\n}\nvideos = document.getElementsByTagName('video');\nfor(i=0, l=videos.length; i<l; i++) {\n videos[i].load();\n modified = false;\n videos[i].addEventListener('ended', function(){\n sources = this.getElementsByTagName('source');\n for(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('data-orig');\n if (orig) {\n sources[i].setAttribute('src', orig);\n modified = true;\n }else{\n current = sources[i].getAttribute('src');\n if (current.indexOf('bumper-out')==-1) {\n sources[i].setAttribute('src', current.replace(/([w]+).(w+)/, 'bumper-out.$2'));\n modified = true;\n }else{\n this.pause();\n modified = false;\n }\n }\n sources[i].setAttribute('data-orig','');\n }\n if (modified) {\n this.load();\n this.play();\n }\n });\n}\n</script>\n\nYo ho ho, that\u2019s a lot of JavaScript. See it in action \u2013 you should get a bumper, the cat video, and an end bumper.\n\nOf course, this code works fine for demonstrating the principle, but it\u2019s very procedural. Nothing wrong with that, but to do something similar in production, you\u2019d probably want to make the code more modular to ease maintainability. Besides, you may want to use a framework, rather than basic JavaScript. \n\nThe end credits\n\nOne really important principle here is that of progressive enhancement. If the browser doesn\u2019t support JavaScript, the user won\u2019t see your bumper, but they will get the main video. If the browser supports JavaScript but doesn\u2019t allow you to modify the src (as was the case with older versions of iOS), the user won\u2019t see your bumper, but they will get the main video.\n\nIf a search engine or social media bot grabs your page and looks for content, they won\u2019t see your bumper, but they will get the main video \u2013 which is absolutely what you want.\n\nThis means that if the bumper is absolutely crucial, you may still need to cook it into the video. However, for many applications, running it dynamically can work quite well.\n\nAs always, it comes down to three things:\n\n\n\tMeasure your audience: know how people access your site\n\tTest the solution: make sure it works for your audience\n\tPlan for failure: it\u2019s the web and that\u2019s how things work \u2018round these parts\n\n\nBut most of all play around with it, have fun and build something awesome.", "year": "2012", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2012-12-01T00:00:00+00:00", "url": "https://24ways.org/2012/html5-video-bumpers/", "topic": "code"} {"rowid": 283, "title": "CSS3 Patterns, Explained", "contents": "Many of you have probably seen my CSS3 patterns gallery. It became very popular throughout the year and it showed many web developers how powerful CSS3 gradients really are. But how many really understand how these patterns are created? The biggest benefit of CSS-generated backgrounds is that they can be modified directly within the style sheet. This benefit is void if we are just copying and pasting CSS code we don\u2019t understand. We may as well use a data URI instead.\n\nImportant note\n\nIn all the examples that follow, I\u2019ll be using gradients without a vendor prefix, for readability and brevity. However, you should keep in mind that in reality you need to use all the vendor prefixes (-moz-, -ms-, -o-, -webkit-) as no browser currently implements them without a prefix. Alternatively, you could use -prefix-free and have the current vendor prefix prepended at runtime, only when needed.\n\nThe syntax described here is the one that browsers currently implement. The specification has since changed, but no browser implements the changes yet. If you are interested in what is coming, I suggest you take a look at the dev version of the spec.\n\nIf you are not yet familiar with CSS gradients, you can read these excellent tutorials by John Allsopp and return here later, as in the rest of the article I assume you already know the CSS gradient basics:\n\n\n\tCSS3 Linear Gradients\n\tCSS3 Radial Gradients\n\n\nThe main idea\n\nI\u2019m sure most of you can imagine the background this code generates:\n\nbackground: linear-gradient(left, white 20%, #8b0 80%);\n\nIt\u2019s a simple gradient from one color to another that looks like this:\n\n See this example live\n\nAs you probably know, in this case the first 20% of the container\u2019s width is solid white and the last 20% is solid green. The other 60% is a smooth gradient between these colors. Let\u2019s try moving these color stops closer to each other:\n\nbackground: linear-gradient(left, white 30%, #8b0 70%);\n\n See this example live\n\nbackground: linear-gradient(left, white 40%, #8b0 60%);\n\n See this example live\n\nbackground: linear-gradient(left, white 50%, #8b0 50%);\n\n See this example live\n\nNotice how the gradient keeps shrinking and the solid color areas expanding, until there is no gradient any more in the last example. We can even adjust the position of these two color stops to control where each color abruptly changes into another:\n\nbackground: linear-gradient(left, white 30%, #8b0 30%);\n\n See this example live\n\nbackground: linear-gradient(left, white 90%, #8b0 90%);\n\n See this example live\n\nWhat you need to take away from these examples is that when two color stops are at the same position, there is no gradient, only solid colors. Even without going any further, this trick is useful for a number of different use cases like faux columns or the effect I wanted to achieve in my homepage or the -prefix-free page where the background is only shown on one side and hidden on the other:\n\n\n\nCombining with background-size\n\nWe can do wonders, however, if we combine this with the CSS3 background-size property:\n\nbackground: linear-gradient(left, white 50%, #8b0 50%);\nbackground-size: 100px 100px;\n\n See this example live\n\nAnd there it is. We just created the simplest of patterns: (vertical) stripes. We can remove the first parameter (left) or replace it with top and we\u2019ll get horizontal stripes. However, let\u2019s face it: Horizontal and vertical stripes are kinda boring. Most stripey backgrounds we see on the web are diagonal. So, let\u2019s try doing that.\n\nOur first attempt would be to change the angle of the gradient to something like 45deg. However, this results in an ugly pattern like this: \n\n See this example live\n\nBefore reading on, think for a second: why didn\u2019t this produce the desired result? Can you figure it out?\n\nThe reason is that the gradient angle rotates the gradient inside each tile, not the tiled background as a whole. However, didn\u2019t we have the same problem the first time we tried to create diagonal stripes with an image? And then we learned that every stripe has to be included twice, like so:\n\n\n\nSo, let\u2019s try to create that effect with CSS gradients. It\u2019s essentially what we tried before, but with more color stops:\n\nbackground: linear-gradient(45deg, white 25%,\n #8b0 25%, #8b0 50%, \n white 50%, white 75%, \n #8b0 75%);\nbackground-size:100px 100px;\n\n See this example live\n\nAnd there we have our stripes! An easy way to remember the order of the percentages and colors it is that you always have two of the same in succession, except the first and last color.\n\nNote: Firefox for Mac also needs an additional 100% color stop at the end of any pattern with more than two stops, like so: ..., white 75%, #8b0 75%, #8b0). The bug was reported in February 2011 and you can vote for it and track its progress at Bugzilla.\n\nUnfortunately, this is essentially a hack and we will realize that if we try to change the gradient angle to 60deg:\n\n See this example live\n\nNot that maintainable after all, eh? Luckily, CSS3 offers us another way of declaring such backgrounds, which not only helps this case but also results in much more concise code:\n\nbackground: repeating-linear-gradient(60deg, white, white 35px, #8b0 35px, #8b0 70px);\n\n See this example live\n\nIn this case, however, the size has to be declared in the color stop positions and not through background-size, since the gradient is supposed to cover the entire container. You might notice that the declared size is different from the one specified the previous way. This is because the size of the stripes is measured differently: in the first example we specify the dimensions of the tile itself; in the second, the width of the stripes (35px), which is measured diagonally.\n\nMultiple backgrounds\n\nUsing only one gradient you can create stripes and that\u2019s about it. There are a few more patterns you can create with just one gradient (linear or radial) but they are more or less boring and ugly. Almost every pattern in my gallery contains a number of different backgrounds. For example, let\u2019s create a polka dot pattern:\n\nbackground: radial-gradient(circle, white 10%, transparent 10%),\nradial-gradient(circle, white 10%, black 10%) 50px 50px;\nbackground-size:100px 100px;\n\n See this example live\n\nNotice that the two gradients are almost the same image, but positioned differently to create the polka dot effect. The only difference between them is that the first (topmost) gradient has transparent instead of black. If it didn\u2019t have transparent regions, it would effectively be the same as having a single gradient, as the topmost gradient would obscure everything beneath it.\n\nThere is an issue with this background. Can you spot it?\n\nThis background will be fine for browsers that support CSS gradients but, for browsers that don\u2019t, it will be transparent as the whole declaration is ignored. We have two ways to provide a fallback, each for different use cases. We have to either declare another background before the gradient, like so:\n\nbackground: black;\nbackground: radial-gradient(circle, white 10%, transparent 10%),\nradial-gradient(circle, white 10%, black 10%) 50px 50px;\nbackground-size:100px 100px;\n\nor declare each background property separately:\n\nbackground-color: black;\nbackground-image: radial-gradient(circle, white 10%, transparent 10%),\nradial-gradient(circle, white 10%, transparent 10%);\nbackground-size:100px 100px;\nbackground-position: 0 0, 50px 50px;\n\nThe vigilant among you will have noticed another change we made to our code in the last example: we altered the second gradient to have transparent regions as well. This way background-color serves a dual purpose: it sets both the fallback color and the background color of the polka dot pattern, so that we can change it with just one edit. Always strive to make code that can be modified with the least number of edits. You might think that it will never be changed in that way but, almost always, given enough time, you\u2019ll be proved wrong.\n\nWe can apply the exact same technique with linear gradients, in order to create checkerboard patterns out of right triangles:\n\nbackground-color: white;\nbackground-image: linear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%), \nlinear-gradient(45deg, black 25%, transparent 25%, transparent 75%, black 75%);\nbackground-size:100px 100px;\nbackground-position: 0 0, 50px 50px;\n\n See this example live\n\nUsing the right units\n\nDon\u2019t use pixels for the sizes without any thought. In some cases, ems make much more sense. For example, when you want to make a lined paper background, you want the lines to actually follow the text. If you use pixels, you have to change the size every time you change font-size. If you set the background-size in ems, it will naturally follow the text and you will only have to update it if you change line-height.\n\nIs it possible?\n\nThe shapes that can be achieved with only one gradient are:\n\n\n\tstripes\n\tright triangles\n\tcircles and ellipses\n\tsemicircles and other shapes formed from slicing ellipses horizontally or vertically\n\n\nYou can combine several of them to create squares and rectangles (two right triangles put together), rhombi and other parallelograms (four right triangles), curves formed from parts of ellipses, and other shapes.\n\nJust because you can doesn\u2019t mean you should\n\nTechnically, anything can be crafted with these techniques. However, not every pattern is suitable for it. The main advantages of this technique are:\n\n\n\tno extra HTTP requests\n\tshort code\n\thuman-readable code (unlike data URIs) that can be changed without even leaving the CSS file.\n\n\nComplex patterns that require a large number of gradients are probably better left to SVG or bitmap images, since they negate almost every advantage of this technique:\n\n\n\tthey are not shorter\n\tthey are not really comprehensible \u2013 changing them requires much more effort than using an image editor\n\n\nThey still save an HTTP request, but so does a data URI.\n\nI have included some very complex patterns in my gallery, because even though I think they shouldn\u2019t be used in production (except under very exceptional conditions), understanding how they work and coding them helps somebody understand the technology in much more depth.\n\nAnother rule of thumb is that if your pattern needs shapes to obscure parts of other shapes, like in the star pattern or the yin yang pattern, then you probably shouldn\u2019t use it. In these patterns, changing the background color requires you to also change the color of these shapes, making edits very tedious.\n\nIf a certain pattern is not practicable with a reasonable amount of CSS, that doesn\u2019t mean you should resort to bitmap images. SVG is a very good alternative and is supported by all modern browsers.\n\nBrowser support\n\nCSS gradients are supported by Firefox 3.6+, Chrome 10+, Safari 5.1+ and Opera 11.60+ (linear gradients since Opera 11.10). Support is also coming in Internet Explorer when IE10 is released. You can get gradients in older WebKit versions (including most mobile browsers) by using the proprietary -webkit-gradient(), if you really need them.\n\nEpilogue\n\nI hope you find these techniques useful for your own designs. If you come up with a pattern that\u2019s very different from the ones already included, especially if it demonstrates a cool new technique, feel free to send a pull request to the github repo of the patterns gallery. Also, I\u2019m always fascinated to see my techniques put in practice, so if you made something cool and used CSS patterns, I\u2019d love to know about it!\n\nHappy holidays!", "year": "2011", "author": "Lea Verou", "author_slug": "leaverou", "published": "2011-12-16T00:00:00+00:00", "url": "https://24ways.org/2011/css3-patterns-explained/", "topic": "code"} {"rowid": 276, "title": "Your jQuery: Now With 67% Less Suck", "contents": "Fun fact: more websites are now using jQuery than Flash.\n\njQuery is an amazing tool that\u2019s made JavaScript accessible to developers and designers of all levels of experience. However, as Spiderman taught us, \u201cwith great power comes great responsibility.\u201d The unfortunate downside to jQuery is that while it makes it easy to write JavaScript, it makes it easy to write really really f*&#ing bad JavaScript. Scripts that slow down page load, unresponsive user interfaces, and spaghetti code knotted so deep that it should come with a bottle of whiskey for the next sucker developer that has to work on it. \n\nThis becomes more important for those of us who have yet to move into the magical fairy wonderland where none of our clients or users view our pages in Internet Explorer. The IE JavaScript engine moves at the speed of an advancing glacier compared to more modern browsers, so optimizing our code for performance takes on an even higher level of urgency.\n\nThankfully, there are a few very simple things anyone can add into their jQuery workflow that can clear up a lot of basic problems. When undertaking code reviews, three of the areas where I consistently see the biggest problems are: inefficient selectors; poor event delegation; and clunky DOM manipulation. We\u2019ll tackle all three of these and hopefully you\u2019ll walk away with some new jQuery batarangs to toss around in your next project.\n\nSelector optimization\n\nSelector speed: fast or slow?\n\nSaying that the power behind jQuery comes from its ability to select DOM elements and act on them is like saying that Photoshop is a really good tool for selecting pixels on screen and making them change color \u2013 it\u2019s a bit of a gross oversimplification, but the fact remains that jQuery gives us a ton of ways to choose which element or elements in a page we want to work with. However, a surprising number of web developers are unaware that all selectors are not created equal; in fact, it\u2019s incredible just how drastic the performance difference can be between two selectors that, at first glance, appear nearly identical. For instance, consider these two ways of selecting all paragraph tags inside a <div> with an ID.\n\n$(\"#id p\");\n\n$(\"#id\").find(\"p\");\n\nWould it surprise you to learn that the second way can be more than twice as fast as the first? Knowing which selectors outperform others (and why) is a pretty key building block in making sure your code runs well and doesn\u2019t frustrate your users waiting for things to happen.\n\nThere are many different ways to select elements using jQuery, but the most common ways can be basically broken down into five different methods. In order, roughly, from fastest to slowest, these are:\n\n\n\t$(\"#id\"); \nThis is without a doubt the fastest selector jQuery provides because it maps directly to the native document.getElementbyId() JavaScript method. If possible, the selectors listed below should be prefaced with an ID selector in conjunction with jQuery\u2019s .find() method to limit the scope of the page that has to be searched (as in the $(\"#id\").find(\"p\") example shown above).\n\t$(\"p\");, $(\"input\");, $(\"form\"); and so on\nSelecting elements by tag name is also fast, since it maps directly to the native document.getElementsByTagname() method.\n\t$(\".class\"); \nSelecting by class name is a little trickier. While still performing very well in modern browsers, it can cause some pretty significant slowdowns in IE8 and below. Why? IE9 was the first IE version to support the native document.getElementsByClassName() JavaScript method. Older browsers have to resort to using much slower DOM-scraping methods that can really impact performance.\n\t$(\"[attribute=value]\");\nThere is no native JavaScript method for this selector to use, so the only way that jQuery can perform the search is by crawling the entire DOM looking for matches. Modern browsers that support the querySelectorAll() method will perform better in certain cases (Opera, especially, runs these searches much faster than any other browser) but, generally speaking, this type of selector is Slowey McSlowersons.\n\t$(\":hidden\");\nLike attribute selectors, there is no native JavaScript method for this one to use. Pseudo-selectors can be painfully slow since the selector has to be run against every element in your search space. Again, modern browsers with querySelectorAll() will perform slightly better here, but try to avoid these if at all possible. If you must use one, try to limit the search space to a specific portion of the page: $(\"#list\").find(\":hidden\");\n\n\nBut, hey, proof is in the performance testing, right? It just so happens that said proof is sitting right here. Be sure to notice the class selector numbers beside IE7 and 8 compared to other browsers and then wonder how the people on the IE team at Microsoft manage to sleep at night. Yikes.\n\nChaining\n\nAlmost all jQuery methods return a jQuery object. This means that when a method is run, its results are returned and you can continue executing more methods on them. Rather than writing out the same selector multiple times over, just making a selection once allows multiple actions to be run on it.\n\nWithout chaining\n\n$(\"#object\").addClass(\"active\");\n$(\"#object\").css(\"color\",\"#f0f\");\n$(\"#object\").height(300);\n\nWith chaining\n\n$(\"#object\").addClass(\"active\").css(\"color\", \"#f0f\").height(300);\n\nThis has the dual effect of making your code shorter and faster. Chained methods will be slightly faster than multiple methods made on a cached selector, and both ways will be much faster than multiple methods made on non-cached selectors. Wait\u2026 \u201ccached selector\u201d? What is this new devilry? \n\nCaching\n\nAnother easy way to speed up your code that seems to be a mystery to developers is the idea of caching your selectors. Think of how many times you end up writing the same selector over and over again in any project. Every $(\".element\") selector has to search the entire DOM each time, regardless of whether or not that selector had been previously run. Running the selection once and then storing the results in a variable means that the DOM only has to be searched once. Once the results of a selector have been cached, you can do anything with them.\n\nFirst, run your search (here we\u2019re selecting all of the <li> elements inside <ul id=\"blocks\">): \n\nvar blocks = $(\"#blocks\").find(\"li\");\n\nNow, you can use the blocks variable wherever you want without having to search the DOM every time.\n\n$(\"#hideBlocks\").click(function() {\n blocks.fadeOut();\n});\n$(\"#showBlocks\").click(function() {\n blocks.fadeIn();\n});\n\nMy advice? Any selector that gets run more than once should be cached. This jsperf test shows just how much faster a cached selector runs compared to a non-cached one (and even throws some chaining love in to boot).\n\nEvent delegation\n\nEvent listeners cost memory. In complex websites and apps it\u2019s not uncommon to have a lot of event listeners floating around, and thankfully jQuery provides some really easy methods for handling event listeners efficiently through delegation.\n\nIn a bit of an extreme example, imagine a situation where a 10\u00d710 cell table needs to have an event listener on each cell; let\u2019s say that clicking on a cell adds or removes a class that defines the cell\u2019s background color. A typical way that this might be written (and something I\u2019ve often seen during code reviews) is like so:\n\n$('table').find('td').click(function() {\n $(this).toggleClass('active');\n});\n\njQuery 1.7 has provided us with a new event listener method, .on(). It acts as a utility that wraps all of jQuery\u2019s previous event listeners into one convenient method, and the way you write it determines how it behaves. To rewrite the above .click() example using .on(), we\u2019d simply do the following:\n\n$('table').find('td').on('click',function() {\n $(this).toggleClass('active');\n});\n\nSimple enough, right? Sure, but the problem here is that we\u2019re still binding one hundred event listeners to our page, one to each individual table cell. A far better way to do things is to create one event listener on the table itself that listens for events inside it. Since the majority of events bubble up the DOM tree, we can bind a single event listener to one element (in this case, the <table>) and wait for events to bubble up from its children. The way to do this using the .on() method requires only one change from our code above:\n\n$('table').on('click','td',function() {\n $(this).toggleClass('active');\n});\n\nAll we\u2019ve done is moved the td selector to an argument inside the .on() method. Providing a selector to .on() switches it into delegation mode, and the event is only fired for descendants of the bound element (table) that match the selector (td). With that one simple change, we\u2019ve gone from having to bind one hundred event listeners to just one. You might think that the browser having to do one hundred times less work would be a good thing and you\u2019d be completely right. The difference between the two examples above is staggering.\n\n(Note that if your site is using a version of jQuery earlier than 1.7, you can accomplish the very same thing using the .delegate() method. The syntax of how you write the function differs slightly; if you\u2019ve never used it before, it\u2019s worth checking the API docs for that page to see how it works.)\n\nDOM manipulation\n\njQuery makes it very easy to manipulate the DOM. It\u2019s trivial to create new nodes, insert them, remove other ones, move things around, and so on. While the code to do this is simple to write, every time the DOM is manipulated, the browser has to repaint and reflow content which can be extremely costly. This is no more evident than in a long loop, whether it be a standard for() loop, while() loop, or jQuery $.each() loop.\n\nIn this case, let\u2019s say we\u2019ve just received an array full of image URLs from a database or Ajax call or wherever, and we want to put all of those images in an unordered list. Commonly, you\u2019ll see code like this to pull this off:\n\nvar arr = [reallyLongArrayOfImageURLs]; \n $.each(arr, function(count, item) {\n var newImg = '<li><img src=\"'+item+'\"></li>';\n $('#imgList').append(newImg);\n });\n\nThere are a couple of problems with this. For one (which you should have already noticed if you\u2019ve read the earlier part of this article), we\u2019re making the $(\"#imgList\") selection once for each iteration of our loop. The other problem here is that each time the loop iterates, it\u2019s adding a new <li> to the DOM. Each of those insertions is going to be costly, and if our array is quite large then this could lead to a massive slowdown or even the dreaded \u2018A script is causing this page to run slowly\u2019 warning.\n\nvar arr = [reallyLongArrayOfImageURLs],\n tmp = ''; \n$.each(arr, function(count, item) {\n tmp += '<li><img src=\"'+item+'\"></li>';\n});\n$('#imgList').append(tmp);\n\nAll we\u2019ve done here is create a tmp variable that each <li> is added to as it\u2019s created. Once our loop has finished iterating, that tmp variable will contain all of our list items in memory, and can be appended to our <ul> all in one go. Browsers work much faster when working with objects in memory rather than on screen, so this is a much faster, more CPU-cycle-friendly method of building a list.\n\nWrapping up\n\nThese are far from being the only ways to make your jQuery code run better, but they are among the simplest ones to implement. Though each individual change may only make a few milliseconds of difference, it doesn\u2019t take long for those milliseconds to add up. Studies have shown that the human eye can discern delays of as few as 100ms, so simply making a few changes sprinkled throughout your code can very easily have a noticeable effect on how well your website or app performs. Do you have other jQuery optimization tips to share? Leave them in the comments and help make us all better.\n\nNow go forth and make awesome!", "year": "2011", "author": "Scott Kosman", "author_slug": "scottkosman", "published": "2011-12-13T00:00:00+00:00", "url": "https://24ways.org/2011/your-jquery-now-with-less-suck/", "topic": "code"} {"rowid": 288, "title": "Displaying Icons with Fonts and Data- Attributes", "contents": "Traditionally, bitmap formats such as PNG have been the standard way of delivering iconography on websites. They\u2019re quick and easy, and it also ensures they\u2019re as pixel crisp as possible. Bitmaps have two drawbacks, however: multiple HTTP requests, affecting the page\u2019s loading performance; and a lack of scalability, noticeable when the page is zoomed or viewed on a screen with a high pixel density, such as the iPhone 4 and 4S.\n\nThe requests problem is normally solved by using CSS sprites, combining the icon set into one (physically) large image file and showing the relevant portion via background-position. While this works well, it can get a bit fiddly to specify all the positions. In particular, scalability is still an issue. A vector-based format such as SVG sounds ideal to solve this, but browser support is still patchy.\n\n\n\nThe rise and adoption of web fonts have given us another alternative. By their very nature, they\u2019re not only scalable, but resolution-independent too. No need to specify higher resolution graphics for high resolution screens! \n\nThat\u2019s not all though:\n\n\n\tBrowser support: Unlike a lot of new shiny techniques, they have been supported by Internet Explorer since version 4, and, of course, by all modern browsers. We do need several different formats, however!\n\tDesign on the fly: The font contains the basic graphic, which can then be coloured easily with CSS \u2013 changing colours for themes or :hover and :focus styles is done with one line of CSS, rather than requiring a new graphic. You can also use CSS3 properties such as text-shadow to add further effects. Using -webkit-background-clip: text;, it\u2019s possible to use gradient and inset shadow effects, although this creates a bitmap mask which spoils the scalability.\n\tSmall file size: specially designed icon fonts, such as Drew Wilson\u2019s Pictos font, can be as little as 12Kb for the .woff font. This is because they contain fewer characters than a fully fledged font. You can see Pictos being used in the wild on sites like Garrett Murray\u2019s Maniacal Rage.\n\n\nAs with all formats though, it\u2019s not without its disadvantages: \n\n\n\tIcons can only be rendered in monochrome or with a gradient fill in browsers that are capable of rendering CSS3 gradients. Specific parts of the icon can\u2019t be a different colour.\n\tIt\u2019s only appropriate when there is an accompanying text to provide meaning. This can be alleviated by wrapping the text label in a tag (I like to use <b> rather than <span>, due to the fact that it\u2019s smaller and isn\u2019 t being used elsewhere) and then hiding it from view with text-indent:-999em.\n\tCreating an icon font can be a complex and time-consuming process. While font editors can carry out hinting automatically, the best results are achieved manually.\n\tUnless you\u2019re adept at creating your own fonts, you\u2019re restricted to what is available in the font. However, fonts like Pictos will cover the most common needs, and icons are most effective when they\u2019re using familiar conventions.\n\n\nThe main complaint about using fonts for icons is that it can mean adding a meaningless character to our markup. The good news is that we can overcome this by using one of two methods \u2013 CSS generated content or the data-icon attribute \u2013 in combination with the :before and :after pseudo-selectors, to keep our markup minimal and meaningful. \n\nOur simple markup looks like this:\n\n<a href=\"/basket\" class=\"icon basket\">View Basket</a>\n\nNote the multiple class attributes. Next, we\u2019ll import the Pictos font using the @font-face web fonts property in CSS:\n\n@font-face {\n font-family: 'Pictos';\n src: url('pictos-web.eot');\n src: local('\u263a'), \n url('pictos-web.woff') format('woff'), \n url('pictos-web.ttf') format('truetype'),\n url('pictos-web.svg#webfontIyfZbseF') format('svg');\n}\n\nThis rather complicated looking set of rules is (at the time of writing) the most bulletproof way of ensuring as many browsers as possible load the font we want. We\u2019ll now use the content property applied to the :before pseudo-class selector to generate our icon. Once again, we\u2019ll use those multiple class attribute values to set common icon styles, then specific styles for .basket. This helps us avoid repeating styles:\n\n.icon {\n font-family: 'Pictos';\n font-size: 22px:\n}\n\n.basket:before {\n content: \"$\";\n}\n\nWhat does the :before pseudo-class do? It generates the dollar character in a browser, even when it\u2019s not present in the markup. Using the generated content approach means our markup stays simple, but we\u2019ll need a new line of CSS, defining what letter to apply to each class attribute for every icon we add.\n\ndata-icon is a new alternative approach that uses the HTML5 data- attribute in combination with CSS attribute selectors. This new attribute lets us add our own metadata to elements, as long as its prefixed by data- and doesn\u2019t contain any uppercase letters. In this case, we want to use it to provide the letter value for the icon. Look closely at this markup and you\u2019ll see the data-icon attribute.\n\n<a href=\"/basket\" class=\"icon\" data-icon=\"$\">View Basket</a>\n\n\n\nWe could add others, in fact as many as we like.\n\n<a href=\"/\" class=\"icon\" data-icon=\"k\">Favourites</a>\n<a href=\"/\" class=\"icon\" data-icon=\"t\">History</a>\n<a href=\"/\" class=\"icon\" data-icon=\"@\">Location</a>\n\n\n\nThen, we need just one CSS attribute selector to style all our icons in one go:\n\n.icon:before {\n content: attr(data-icon);\n /* Insert your fancy colours here */\n }\n\nBy placing our custom attribute data-icon in the selector in this way, we can enable CSS to read the value of that attribute and display it before the element (in this case, the anchor tag). It saves writing a lot of CSS rules. I can imagine that some may not like the extra attribute, but it does keep it out of the actual content \u2013 generated or not.\n\n\n\n\n\nThis could be used for all manner of tasks, including a media player and large simple illustrations. See the demo for live examples. Go ahead and zoom the page, and the icons will be crisp, with the exception of the examples that use -webkit-background-clip: text as mentioned earlier.\n\nFinally, it\u2019s worth pointing out that with both generated content and the data-icon method, the letter will be announced to people using screen readers. For example, with the shopping basket icon above, the reader will say \u201cdollar sign view basket\u201d. As accessibility issues go, it\u2019s not exactly the worst, but could be confusing. You would need to decide whether this method is appropriate for the audience. Despite the disadvantages, icon fonts have huge potential.", "year": "2011", "author": "Jon Hicks", "author_slug": "jonhicks", "published": "2011-12-12T00:00:00+00:00", "url": "https://24ways.org/2011/displaying-icons-with-fonts-and-data-attributes/", "topic": "code"} {"rowid": 271, "title": "Creating Custom Font Stacks with Unicode-Range", "contents": "Any web designer or front-end developer worth their salt will be familiar with the CSS @font-face rule used for embedding fonts in a web page. We\u2019ve all used it \u2014 either directly in our code ourselves, or via one of the web font services like Fontdeck, Typekit or Google Fonts.\n\nIf you\u2019re like me, however, you\u2019ll be used to just copying and pasting in a specific incantation of lines designed to get different formats of fonts working in different browsers, and may not have really explored all the capabilities of @font-face properties as defined by the spec.\n\nOne such property \u2014 the unicode-range descriptor \u2014 sounds pretty dull and is easily overlooked. It does, however, have some fairly interesting possibilities when put to use in creative ways.\n\nUnicode-range\n\nThe unicode-range descriptor is designed to help when using fonts that don\u2019t have full coverage of the characters used in a page. By adding a unicode-range property to a @font-face rule it is possible to specify the range of characters the font covers. \n\n@font-face {\n font-family: BBCBengali;\n src: url(fonts/BBCBengali.ttf) format(\"opentype\");\n unicode-range: U+00-FF;\n}\n\nIn this example, the font is to be used for characters in the range of U+00 to U+FF which runs from the unexciting control characters at the start of the Unicode table (symbols like the exclamation mark start at U+21) right through to \u00ff at U+FF \u2013 the extent of the Basic Latin character range.\n\nBy adding multiple @font-face rules for the same family but with different ranges, you can build up complete coverage of the characters your page uses by using different fonts.\n\nWhen I say that it\u2019s possible to specify the range of characters the font covers, that\u2019s true, but what you\u2019re really doing with the unicode-range property is declaring which characters the font should be used for. This becomes interesting, because instead of merely working with the technical constraints of available characters in a given font, we can start picking and choosing characters to use and selectively mix fonts together.\n\nThe best available ampersand\n\nA few years back, Dan Cederholm wrote a post encouraging designers to use the best available ampersand. Dan went on to outline how this can be achieved by wrapping our ampersands in a <span> element with a class applied:\n\n<span class=\"amp\">&</span>\n\nA CSS rule can then be written to select the <span> and apply a different font:\n\nspan.amp {\n font-family: Baskerville, Palatino, \"Book Antiqua\", serif;\n}\n\nThat\u2019s a perfectly serviceable technique, but the drawbacks are clear \u2014 you have to add extra markup which is borderline presentational, and you also have to be able to add that markup, which isn\u2019t always possible when working with a CMS.\n\nPerhaps we could do this with unicode-range.\n\nA better best available ampersand\n\nThe Unicode code point for an ampersand is U+26, so the ampersand font stack above can be created like so:\n\n@font-face {\n font-family: 'Ampersand';\n src: local('Baskerville'), local('Palatino'), local('Book Antiqua');\n unicode-range: U+26;\n}\n\nWhat we\u2019ve done here is specify a new family called Ampersand and created a font stack for it with the user\u2019s locally installed copies of Baskerville, Palatino or Book Antiqua. We\u2019ve then limited it to a single character range \u2014 the ampersand. Of course, those don\u2019t need to be local fonts \u2014 they could be web font files, too. If you have a font with a really snazzy ampersand, go for your life.\n\nWe can then use that new family in a regular font stack.\n\nh1 {\n font-family: Ampersand, Arial, sans-serif;\n}\n\nWith this in place, any <h1> elements in our page will use the Ampersand family (Baskerville, Palatino or Book Antiqua) for ampersands, and Arial for all other characters. If the user doesn\u2019t have any of the Ampersand family fonts available, the ampersand will fall back to the next item in the font stack, Arial.\n\nYou didn\u2019t think it was that easy, did you?\n\nOh, if only it were so. The problem comes, as ever, with the issue of browser support. The unicode-range property has good support in WebKit browsers (like Safari and Chrome, and the browsers on most popular smartphone platforms) and in recent versions of Internet Explorer. The big stumbling block comes in the form of Firefox, which has no support at all.\n\nIf you\u2019re familiar with how CSS works when it comes to unsupported properties, you\u2019ll know that if a browser encounters a property it doesn\u2019t implement, it just skips that declaration and moves on to the next. That works perfectly for things like border-radius \u2014 if the browser can\u2019t round off the corners, the declaration is skipped and the user sees square corners instead. Perfect.\n\nLess perfect when it comes to unicode-range, because if no range is specified then the default is that the font is applied for all characters \u2014 the whole range. If you\u2019re using a fancy font for flamboyant ampersands, you probably don\u2019t want that applied to all your text if unicode-range isn\u2019t supported. That would be bad. Really bad.\n\nEnsuring good fallbacks\n\nAs ever, the trick is to make sure that there\u2019s a sensible fallback in place if a browser doesn\u2019t have support for whatever technology you\u2019re trying to use. This is where being a super nerd about understanding the spec you\u2019re working with really pays off.\n\nWe can make use of the rules of the CSS cascade to make sure that if unicode-range isn\u2019t supported we get a sensible fallback font. What would be ideal is if we were able to follow up the @font-face rule with a second rule to override it if Unicode ranges aren\u2019t implemented.\n\n@font-face {\n font-family: 'Ampersand';\n src: local('Baskerville'), local('Palatino'), local('Book Antiqua');\n unicode-range: U+26;\n}\n@font-face {\n font-family: 'Ampersand';\n src: local('Arial');\n}\n\nIn theory, this code should make sense for all browsers. For those that support unicode-range the two rules become cumulative. They specify different ranges for the same family, and in WebKit browsers this has the expected result of using Arial for most characters, but Baskerville and friends for the ampersand. For browsers that don\u2019t have support, the second rule should just supersede the first, setting the font to Arial. \n\nUnfortunately, this code causes current versions of Firefox to freak out and use the first rule, applying Baskerville to the entire range. That\u2019s both unexpected and unfortunate. Bad Firefox. On your rug.\n\nIf that doesn\u2019t work, what can we do? Well, we know that if given a unicode-range Firefox will ignore the range and apply the font to all characters. That\u2019s really what we\u2019re trying to achieve. So what if we specified a range for the fallback font, but made sure it only covers some obscure high-value Unicode character we\u2019re never going to use in our page? Then it wouldn\u2019t affect the outcome for browsers that do support ranges.\n\n@font-face {\n font-family: 'Ampersand';\n src: local('Baskerville'), local('Palatino'), local('Book Antiqua');\n unicode-range: U+26;\n}\n@font-face {\n /* Ampersand fallback font */\n font-family: 'Ampersand';\n src: local('Arial');\n unicode-range: U+270C;\n}\n\nBy specifying a range on the fallback font, Firefox appears to correctly override the first based on the cascade sort order. Browsers that do support ranges take the second rule in addition, and apply Arial for that obscure character we\u2019re not using in any of our pages \u2014 U+270C.\n\nSo we get our nice ampersands in browsers that support unicode-range and, thanks to our styling of an obscure Unicode character, the font falls back to a perfectly acceptable Arial in browsers that do not offer support. Perfect!\n\nThat obscure character, my friends, is what Unicode defines as the VICTORY HAND.\n\n\u270c\n\nSo, how can we use this?\n\nAmpersands are a neat trick, and it works well in browsers that support ranges, but that\u2019s not really the point of all this. Styling ampersands is fun, but they\u2019re only really scratching the surface. Consider more involved examples, such as substituting a different font for numerals, or symbols, or even caps. Things certainly begin to get a bit more interesting.\n\nHow do you know what the codes are for different characters? Richard Ishida has a handy online conversion tool available where you can type in the characters and get the Unicode code points out the other end.\n\nOf course, the fact remains that browser support for unicode-range is currently limited, so any application needs to have fallbacks that you\u2019re still happy for a significant proportion of your visitors to see. In some cases, such as dedicated pages for mobile devices in an HTML-based phone app, this is immediately useful as support in WebKit browsers is already very good. In other cases, you\u2019ll have to use your own best judgement based on your needs and audience.\n\nOne thing to keep in mind is that if you\u2019re using web fonts, the entire font will be downloaded even if only one character is used. That said, the font shouldn\u2019t be downloaded if none of the characters within the Unicode range are present in a given page.\n\nAs ever, there are pros and cons to using unicode-range as well as varied but increasing support in browsers. It remains a useful tool to understand and have in your toolkit for when the right moment comes along.", "year": "2011", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2011-12-01T00:00:00+00:00", "url": "https://24ways.org/2011/creating-custom-font-stacks-with-unicode-range/", "topic": "code"} {"rowid": 223, "title": "Calculating Color Contrast", "contents": "Some websites and services allow you to customize your profile by uploading pictures, changing the background color or other aspects of the design. As a customer, this personalization turns a web app into your little nest where you store your data. As a designer, letting your customers have free rein over the layout and design is a scary prospect. So what happens to all the stock text and images that are designed to work on nice white backgrounds? Even the Mac only lets you choose between two colors for the OS, blue or graphite! Opening up the ability to customize your site\u2019s color scheme can be a recipe for disaster unless you are flexible and understand how to find maximum color contrasts.\n\nIn this article I will walk you through two simple equations to determine if you should be using white or black text depending on the color of the background. The equations are both easy to implement and produce similar results. It isn\u2019t a matter of which is better, but more the fact that you are using one at all! That way, even with the craziest of Geocities color schemes that your customers choose, at least your text will still be readable.\n\nLet\u2019s have a look at a range of various possible colors. Maybe these are pre-made color schemes, corporate colors, or plucked from an image.\n\n\n\nNow that we have these potential background colors and their hex values, we need to find out whether the corresponding text should be in white or black, based on which has a higher contrast, therefore affording the best readability. This can be done at runtime with JavaScript or in the back-end before the HTML is served up.\n\nThere are two functions I want to compare. The first, I call \u201950%\u2019. It takes the hex value and compares it to the value halfway between pure black and pure white. If the hex value is less than half, meaning it is on the darker side of the spectrum, it returns white as the text color. If the result is greater than half, it\u2019s on the lighter side of the spectrum and returns black as the text value.\n\nIn PHP:\n\nfunction getContrast50($hexcolor){\n return (hexdec($hexcolor) > 0xffffff/2) ? 'black':'white';\n}\n\nIn JavaScript:\n\nfunction getContrast50(hexcolor){\n return (parseInt(hexcolor, 16) > 0xffffff/2) ? 'black':'white';\n}\n\nIt doesn\u2019t get much simpler than that! The function converts the six-character hex color into an integer and compares that to one half the integer value of pure white. The function is easy to remember, but is naive when it comes to understanding how we perceive parts of the spectrum. Different wavelengths have greater or lesser impact on the contrast.\n\nThe second equation is called \u2018YIQ\u2019 because it converts the RGB color space into YIQ, which takes into account the different impacts of its constituent parts. Again, the equation returns white or black and it\u2019s also very easy to implement.\n\nIn PHP:\n\nfunction getContrastYIQ($hexcolor){\n\t$r = hexdec(substr($hexcolor,0,2));\n\t$g = hexdec(substr($hexcolor,2,2));\n\t$b = hexdec(substr($hexcolor,4,2));\n\t$yiq = (($r*299)+($g*587)+($b*114))/1000;\n\treturn ($yiq >= 128) ? 'black' : 'white';\n}\n\nIn JavaScript:\n\nfunction getContrastYIQ(hexcolor){\n\tvar r = parseInt(hexcolor.substr(0,2),16);\n\tvar g = parseInt(hexcolor.substr(2,2),16);\n\tvar b = parseInt(hexcolor.substr(4,2),16);\n\tvar yiq = ((r*299)+(g*587)+(b*114))/1000;\n\treturn (yiq >= 128) ? 'black' : 'white';\n}\n\nYou\u2019ll notice first that we have broken down the hex value into separate RGB values. This is important because each of these channels is scaled in accordance to its visual impact. Once everything is scaled and normalized, it will be in a range between zero and 255. Much like the previous \u201950%\u2019 function, we now need to check if the input is above or below halfway. Depending on where that value is, we\u2019ll return the corresponding highest contrasting color.\n\nThat\u2019s it: two simple contrast equations which work really well to determine the best readability.\n\nIf you are interested in learning more, the W3C has a few documents about color contrast and how to determine if there is enough contrast between any two colors. This is important for accessibility to make sure there is enough contrast between your text and link colors and the background.\n\nThere is also a great article by Kevin Hale on Particletree about his experience with choosing light or dark themes. To round it out, Jonathan Snook created a color contrast picker which allows you to play with RGB sliders to get values for YIQ, contrast and others. That way you can quickly fiddle with the knobs to find the right balance.\n\nComparing results\n\nLet\u2019s revisit our color schemes and see which text color is recommended for maximum contrast based on these two equations.\n\n\n\nIf we use the simple \u201950%\u2019 contrast function, we can see that it recommends black against all the colors except the dark green and purple on the second row. In general, the equation feels the colors are light and that black is a better choice for the text.\n\n\n\nThe more complex \u2018YIQ\u2019 function, with its weighted colors, has slightly different suggestions. White text is still recommended for the very dark colors, but there are some surprises. The red and pink values show white text rather than black. This equation takes into account the weight of the red value and determines that the hue is dark enough for white text to show the most contrast.\n\nAs you can see, the two contrast algorithms agree most of the time. There are some instances where they conflict, but overall you can use the equation that you prefer. I don\u2019t think it is a major issue if some edge-case colors get one contrast over another, they are still very readable.\n\nNow let\u2019s look at some common colors and then see how the two functions compare. You can quickly see that they do pretty well across the whole spectrum.\n\n\n\nIn the first few shades of grey, the white and black contrasts make sense, but as we test other colors in the spectrum, we do get some unexpected deviation. Pure red #FF0000 has a flip-flop. This is due to how the \u2018YIQ\u2019 function weights the RGB parts. While you might have a personal preference for one style over another, both are justifiable.\n\n\n\nIn this second round of colors, we go deeper into the spectrum, off the beaten track. Again, most of the time the contrasting algorithms are in sync, but every once in a while they disagree. You can select which you prefer, neither of which is unreadable.\n\nConclusion\n\nContrast in color is important, especially if you cede all control and take a hands-off approach to the design. It is important to select smart defaults by making the contrast between colors as high as possible. This makes it easier for your customers to read, increases accessibility and is generally just easier on the eyes. \n\nSure, there are plenty of other equations out there to determine contrast; what is most important is that you pick one and implement it into your system.\n\nSo, go ahead and experiment with color in your design. You now know how easy it is to guarantee that your text will be the most readable in any circumstance.", "year": "2010", "author": "Brian Suda", "author_slug": "briansuda", "published": "2010-12-24T00:00:00+00:00", "url": "https://24ways.org/2010/calculating-color-contrast/", "topic": "code"} {"rowid": 238, "title": "Everything You Wanted To Know About Gradients (And a Few Things You Didn\u2019t)", "contents": "Hello. I am here to discuss CSS3 gradients. Because, let\u2019s face it, what the web really needed was more gradients.\n\nStill, despite their widespread use (or is it overuse?), the smartly applied gradient can be a valuable contributor to a designer\u2019s vocabulary. There\u2019s always been a tension between the inherently two-dimensional nature of our medium, and our desire for more intensity, more depth in our designs. And a gradient can evoke so much: the splay of light across your desk, the slow decrease in volume toward the end of your favorite song, the sunset after a long day. When properly applied, graded colors bring a much needed softness to our work.\n\nOf course, that whole \u2018proper application\u2019 thing is the tricky bit.\n\nBut given their place in our toolkit and their prominence online, it really is heartening to see we can create gradients directly with CSS. They\u2019re part of the draft images module, and implemented in two of the major rendering engines.\n\nStill, I\u2019ve always found CSS gradients to be one of the more confusing aspects of CSS3. So if you\u2019ll indulge me, let\u2019s take a quick look at how to create CSS gradients\u2014hopefully we can make them seem a bit more accessible, and bring a bit more art into the browser.\n\nGradient theory 101 (I hope that\u2019s not really a thing)\n\nRight. So before we dive into the code, let\u2019s cover a few basics. Every gradient, no matter how complex, shares a few common characteristics. Here\u2019s a straightforward one:\n\n I spent seconds hours designing this gradient. I hope you like it.\n\nAt either end of our image, we have a final color value, or color stop: on the left, our stop is white; on the right, black. And more color-rich gradients are no different:\n\n (Don\u2019t ever really do this. Please. I beg you.)\n\nIt\u2019s visually more intricate, sure. But at the heart of it, we have just seven color stops (red, orange, yellow, and so on), making for a fantastic gradient all the way.\n\nNow, color stops alone do not a gradient make. Between each is a transition point, the fail-over point between the two stops. Now, the transition point doesn\u2019t need to fall exactly between stops: it can be brought closer to one stop or the other, influencing the overall shape of the gradient.\n\nA tale of two syntaxes\n\nArmed with our new vocabulary, let\u2019s look at a CSS gradient in the wild. Behold, the simple input button:\n\n\n\nThere\u2019s a simple linear gradient applied vertically across the button, moving from a bright sunflowerish hue (#FAA51A, for you hex nuts in the audience) to a much richer orange (#F47A20). And here\u2019s the CSS that makes it happen:\n\ninput[type=submit] {\n\tbackground-color: #F47A20;\n\tbackground-image: -moz-linear-gradient(\n\t\t#FAA51A,\n\t\t#F47A20\n\t\t);\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%,\n\t\tcolor-stop(0, #FAA51A),\n\t\tcolor-stop(1, #F47A20)\n\t\t);\n}\n\nI\u2019ve borrowed David DeSandro\u2019s most excellent formatting suggestions for gradients to make this snippet a bit more legible but, still, the code above might have turned your stomach a bit. And that\u2019s perfectly understandable\u2014heck, it sort of turned mine. But let\u2019s step through the CSS slowly, and see if we can\u2019t make it a little less terrifying.\n\nVerbose WebKit is verbose\n\nHere\u2019s the syntax for our little gradient on WebKit:\n\nbackground-image: -webkit-gradient(linear, 0 0, 0 100%,\n\tcolor-stop(0, #FAA51A),\n\tcolor-stop(1, #F47A20)\n\t);\n\nWoof. Quite a mouthful, no? Well, here\u2019s what we\u2019re looking at:\n\n\n\tWebKit has a single -webkit-gradient property, which can be used to create either linear or radial gradients.\n\tThe next two values are the starting and ending positions for our gradient (0 0 and 0 100%, respectively). Linear gradients are simply drawn along the path between those two points, which allows us to change the direction of our gradient simply by altering its start and end points.\n\tAfterward, we specify our color stops with the oh-so-aptly named color-stop parameter, which takes the stop\u2019s position on the gradient (0 being the beginning, and 100% or 1 being the end) and the color itself.\n\n\nFor a simple two-color gradient like this, -webkit-gradient has a bit of shorthand notation to offer us:\n\nbackground-image: -webkit-gradient(linear, 0 0, 0 100%,\n\tfrom(#FAA51A),\n\tto(#FAA51A)\n\t);\n\nfrom(#FAA51A) is equivalent to writing color-stop(0, #FAA51A), and to(#FAA51A) is the same as color-stop(1, #FAA51A) or color-stop(100%, #FAA51A)\u2014in both cases, we\u2019re simply declaring the first and last color stops in our gradient.\n\nTerse Gecko is terse\n\nWebKit proposed its syntax back in 2008, heavily inspired by the way gradients are drawn in the canvas specification. However, a different, leaner syntax came to the fore, eventually appearing in a draft module specification in CSS3.\n\nNaturally, because nothing on the web was meant to be easy, this is the one that Mozilla has implemented.\n\nHere\u2019s how we get gradient-y in Gecko:\n\nbackground-image: -moz-linear-gradient(\n\t#FAA51A,\n\t#F47A20\n\t);\n\nWait, what? Done already? That\u2019s right. By default, -moz-linear-gradient assumes you\u2019re trying to create a vertical gradient, starting from the top of your element and moving to the bottom. And, if that\u2019s the case, then you simply need to specify your color stops, delimited with a few commas.\n\nI know: that was almost\u2026 painless. But the W3C/Mozilla syntax also affords us a fair amount of flexibility and control, by introducing features as we need them.\n\nWe can specify an origin point for our gradient:\n\nbackground-image: -moz-linear-gradient(50% 100%,\n\t#FAA51A,\n\t#F47A20\n\t);\n\nAs well as an angle, to give it a direction:\n\nbackground-image: -moz-linear-gradient(50% 100%, 45deg,\n\t#FAA51A,\n\t#F47A20\n\t);\n\nAnd we can specify multiple stops, simply by adding to our comma-delimited list:\n\nbackground-image: -moz-linear-gradient(50% 100%, 45deg,\n\t#FAA51A,\n\t#FCC,\n\t#F47A20\n\t);\n\nBy adding a percentage after a given color value, we can determine its position along the gradient path:\n\nbackground-image: -moz-linear-gradient(50% 100%, 45deg,\n\t#FAA51A,\n\t#FCC 20%,\n\t#F47A20\n\t);\n\nSo that\u2019s some of the flexibility implicit in the W3C/Mozilla-style syntax.\n\nNow, I should note that both syntaxes have their respective fans. I will say that the W3C/Mozilla-style syntax makes much more sense to me, and lines up with how I think about creating gradients. But I can totally understand why some might prefer WebKit\u2019s more verbose approach to the, well, looseness behind the -moz syntax. \u00c0 chacun son gradient syntax.\n\nStill, as the language gets refined by the W3C, I really hope some consensus is reached by the browser vendors. And with Opera signaling that it will support the W3C syntax, I suppose it falls on WebKit to do the same.\n\nReusing color stops for fun and profit\n\nBut CSS gradients aren\u2019t all simple colors and shapes and whatnot: by getting inventive with individual color stops, you can create some really complex, compelling effects.\n\nTim Van Damme, whose brain, I believe, should be posthumously donated to science, has a particularly clever application of gradients on The Box, a site dedicated to his occasional podcast series. Now, there are a fair number of gradients applied throughout the UI, but it\u2019s the feature image that really catches the eye.\n\nYou see, there\u2019s nothing that says you can\u2019t reuse color stops. And Tim\u2019s exploited that perfectly.\n\nHe\u2019s created a linear gradient, angled at forty-five degrees from the top left corner of the photo, starting with a fully transparent white (rgba(255, 255, 255, 0)). At the halfway mark, he\u2019s established another color stop at an only slightly more opaque white (rgba(255, 255, 255, 0.1)), making for that incredibly gradual brightening toward the middle of the photo.\n\n\n\nBut then he has set another color stop immediately on top of it, bringing it back down to rgba(255, 255, 255, 0) again. This creates that fantastically hard edge that diagonally bisects the photo, giving the image that subtle gloss.\n\n\n\nAnd his final color stop ends at the same fully transparent white, completing the effect. Hot? I do believe so.\n\nRocking the radials\n\nWe\u2019ve been looking at linear gradients pretty exclusively. But I\u2019d be remiss if I didn\u2019t at least mention radial gradients as a viable option, including a modest one as a link accent on a navigation bar:\n\n\n\nAnd here\u2019s the relevant CSS:\n\nbackground: -moz-radial-gradient(50% 100%, farthest-side,\n\trgb(204, 255, 255) 1%,\n\trgb(85, 85, 85) 15%,\n\trgba(85, 85, 85, 0)\n\t);\nbackground: -webkit-gradient(radial, 50% 100%, 0, 50% 100%, 15,\n\tfrom(rgb(204, 255, 255)),\n\tto(rgba(85, 85, 85, 0))\n\t);\n\nNow, the syntax builds on what we\u2019ve already learned about linear gradients, so much of it might be familiar to you, picking out color stops and transition points, as well as the two syntaxes\u2019 reliance on either a separate property (-moz-radial-gradient) or parameter (-webkit-gradient(radial, \u2026)) to shift into circular mode.\n\nMozilla introduces another stand-alone property (-moz-radial-gradient), and accepts a starting point (50% 100%) from which the circle radiates. There\u2019s also a size constant defined (farthest-side), which determines the reach and shape of our gradient.\n\nWebKit is again the more verbose of the two syntaxes, requiring both starting and ending points (50% 100% in both cases). Each also accepts a radius in pixels, allowing you to control the skew and breadth of the circle.\n\nAgain, this is a fairly modest little radial gradient. Time and article length (and, let\u2019s be honest, your author\u2019s completely inadequate grasp of geometry) prevent me from covering radial gradients in much more detail, because they are incredibly powerful. For those interested in learning more, I can\u2019t recommend the references at Mozilla and Apple strongly enough.\n\nLeave no browser behind\n\nBut no matter the kind of gradients you\u2019re working with, there is a large swathe of browsers that simply don\u2019t support gradients. Thankfully, it\u2019s fairly easy to declare a sensible fallback\u2014it just depends on the kind of fallback you\u2019d like. Essentially, gradient-blind browsers will disregard any properties containing references to either -moz-linear-gradient, -moz-radial-gradient, or -webkit-gradient, so you simply need to keep your fallback isolated from those properties.\n\nFor example: if you\u2019d like to fall back to a flat color, simply declare a separate background-color:\n\n.nav {\n\tbackground-color: #000;\n\tbackground-image: -moz-linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45));\n\tbackground-image: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.45)));\n}\n\nOr perhaps just create three separate background properties.\n\n.nav {\n\tbackground: #000;\n\tbackground: #000 -moz-linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45));\n\tbackground: #000 -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.45)));\n}\n\nWe can even build on this to fall back to a non-gradient image:\n\n.nav {\n\tbackground: #000 <strong>url(\"faux-gradient-lol.png\") repeat-x</strong>;\n\tbackground: #000 -moz-linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45));\n\tbackground: #000 -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.45)));\n}\n\nNo matter the approach you feel most appropriate to your design, it\u2019s really just a matter of keeping your fallback design quarantined from its CSS3-ified siblings.\n\n(If you\u2019re feeling especially masochistic, there\u2019s even a way to get simple linear gradients working in IE via Microsoft\u2019s proprietary filters. Of course, those come with considerable performance penalties that even Microsoft is quick to point out, so I\u2019d recommend avoiding those.\n\nAnd don\u2019t tell Andy Clarke I told you, or he\u2019ll probably unload his Derringer at me. Or something.)\n\nGo forth and, um, gradientify!\n\nIt\u2019s entirely possible your head\u2019s spinning. Heck, mine is, but that might be the effects of the \u2019nog. But maybe you\u2019re wondering why you should care about CSS gradients. After all, images are here right now, and work just fine. \n\nWell, there are some quick benefits that spring to mind: fewer HTTP requests are needed; CSS3 gradients are easily made scalable, making them ideal for variable widths and heights; and finally, they\u2019re easily modifiable by tweaking a few CSS properties. Because, let\u2019s face it, less time spent yelling at Photoshop is a very, very good thing.\n\nOf course, CSS-generated gradients are not without their drawbacks. The syntax can be confusing, and it\u2019s still under development at the W3C. As we\u2019ve seen, browser support is still very much in flux. And it\u2019s possible that gradients themselves have some real performance drawbacks\u2014so test thoroughly, and gradient carefully.\n\nBut still, as syntaxes converge, and support improves, I think generated gradients can make a compelling tool in our collective belts. The tasteful design is, of course, entirely up to you.\n\nSo have fun, and get gradientin\u2019.", "year": "2010", "author": "Ethan Marcotte", "author_slug": "ethanmarcotte", "published": "2010-12-22T00:00:00+00:00", "url": "https://24ways.org/2010/everything-you-wanted-to-know-about-gradients/", "topic": "code"} {"rowid": 231, "title": "Designing for iOS: Life Beyond Media Queries", "contents": "Although not a new phenomenon, media queries seem to be getting a lot attention online recently and for the right reasons too \u2013 it\u2019s great to be able to adapt a design with just a few lines of CSS \u2013 but many people are relying only on them to create an iPhone-specific version of their website. \n\nI was pleased to hear at FOWD NYC a few weeks ago that both myself and Aral Balkan share the same views on why media queries aren\u2019t always going to be the best solution for mobile. Both of us specialise in iPhone design ourselves and we opt for a different approach to media queries. The trouble is, regardless of what you have carefully selected to be display:none; in your CSS, the iPhone still loads everything in the background; all that large imagery for your full scale website also takes up valuable mobile bandwidth and time.\n\nYou can greatly increase the speed of your website by creating a specific site tailored to mobile users with just a few handy pointers \u2013 media queries, in some instances, might be perfectly suitable but, in others, here\u2019s what you can do.\n\nRedirect your iPhone/iPod Touch users\n\nTo detect whether someone is viewing your site on an iPhone or iPod Touch, you can either use JavaScript or PHP. \n\nThe JavaScript \n\nif((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) { \n if (document.cookie.indexOf(\"iphone_redirect=false\") == -1) window.location = \"http://mobile.yoursitehere.com\"; \n}\n\nThe PHP\n\nif(strstr($_SERVER['HTTP_USER_AGENT'],'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'],'iPod')) \n{\n header('Location: http://mobile.yoursitehere.com');\n exit();\n}\n\nBoth of these methods redirect the user to a site that you have made specifically for the iPhone. At this point, be sure to provide a link to the full version of the website, in case the user wishes to view this and not be thrown into an experience they didn\u2019t want, with no way back.\n\nTailoring your site\n\nSo, now you\u2019ve got 320\u2009\u00d7\u2009480 pixels of screen to play with \u2013 and to create a style sheet for, just as you would for any other site you build. There are a few other bits and pieces that you can add to your code to create a site that feels more like a fully immersive iPhone app rather than a website.\n\nRetina display\n\nWhen building your website specifically tailored to the iPhone, you might like to go one step further and create a specific style sheet for iPhone 4\u2019s Retina display. Because there are four times as many pixels on the iPhone 4 (640\u2009\u00d7\u2009960 pixels), you\u2019ll find specifics such as text shadows and borders will have to be increased. \n\n<link rel=\"stylesheet\" \n media=\"only screen and (-webkit-min-device-pixel-ratio: 2)\" \n type=\"text/css\" href=\"../iphone4.css\" />\n\n(Credit to Thomas Maier)\n\nPrevent user scaling\n\nThis declaration, added into the <head>, stops the user being able to pinch-zoom in and out of your design, which is perfect if you are designing to the exact pixel measurements of the iPhone screen. \n\n<meta name=\"viewport\" \n content=\"width=device-width; initial-scale=1.0; maximum-scale=1.0;\">\n\nDesigning for orientation \n\nAs iPhones aren\u2019t static devices, you\u2019ll also need to provide a style sheet for horizontal orientation. We can do this by inserting some JavaScript into the <head> as follows: \n\n<script type=\"text/javascript\">\nfunction orient() {\n switch(window.orientation) {\n case 0: \n document.getElementById(\"orient_css\").href = \"css/iphone_portrait.css\";\n break;\n case -90: \n document.getElementById(\"orient_css\").href = \"css/iphone_landscape.css\";\n break;\n case 90: \n document.getElementById(\"orient_css\").href = \"css/iphone_landscape.css\";\n break;\n }\n}\nwindow.onload = orient();\n</script>\n\nYou can also specify orientation styles using media queries. This is absolutely fine, as by this point you\u2019ll already be working with mobile-specific graphics and have little need to set a lot of things to display:none;\n\n<link rel=\"stylesheet\" \n media=\"only screen and (max-device-width: 480px)\" href=\"/iphone.css\">\n<link rel=\"stylesheet\" \n media=\"only screen and (orientation: portrait)\" href=\"/portrait.css\">\n<link rel=\"stylesheet\" \n media=\"only screen and (orientation: landscape)\u201d href=\"/landscape.css\">\n\nRemove the address and status bars, top and bottom\n\nTo give you more room on-screen and to make your site feel more like an immersive web app, you can place the following declaration into the <head> of your document\u2019s code to remove the address and status bars at the top and bottom of the screen. \n\n<meta name=\"apple-mobile-web-app-capable\" content=\"yes\" />\n\nMaking the most of inbuilt functions\n\nSimilar to mailto: e-mail links, the iPhone also supports another two handy URI schemes which are great for enhancing contact details. When tapped, the following links will automatically bring up the appropriate call or text interface:\n\n<a href=\"tel:01234567890\">Call us</a>\n<a href=\"sms:01234567890\">Text us</a>\n\niPhone-specific Web Clip icon\n\nAlthough I believe them to be fundamentally flawed, since they rely on the user bookmarking your site, iPhone Web Clip icons are still a nice touch. You need just two declarations, again in the <head> of your document:\n\n<link rel=\"apple-touch-icon\" href=\"icons/regular_icon.png\" />\n<link rel=\"apple-touch-icon\" sizes=\"114x114\" href=\"icons/retina_icon.png\" />\n\nFor iPhone 4 you\u2019ll need to create a 114\u2009\u00d7\u2009114 pixels icon; for a non-Retina display, a 57\u2009\u00d7\u200957 pixels icon will do the trick.\n\nPrecomposed \n\nApple adds its standard gloss \u2018moon\u2019 over the top of any icon. If you feel this might be too much for your particular icon and would prefer a matte finish, you can add precomposed to the end of the apple-touch-icon declaration to remove the standard gloss. \n\n<link rel=\"apple-touch-icon-precomposed\" href=\"/images/touch-icon.png\" />\n\nWrapping up\n\nMedia queries definitely have their uses. They make it easy to build a custom experience for your visitor, regardless of their browser\u2019s size. For more complex sites, however, or where you have lots of imagery and other content that isn\u2019t necessary on the mobile version, you can now use these other methods to help you out. Remember, they are purely for presentation and not optimisation; for busy people on the go, optimisation and faster-running mobile experiences can only be a good thing. \n\nHave a wonderful Christmas fellow Webbies!", "year": "2010", "author": "Sarah Parmenter", "author_slug": "sarahparmenter", "published": "2010-12-17T00:00:00+00:00", "url": "https://24ways.org/2010/life-beyond-media-queries/", "topic": "code"} {"rowid": 235, "title": "Real Animation Using JavaScript, CSS3, and HTML5 Video", "contents": "When I was in school to be a 3-D animator, I read a book called Timing for Animation. Though only 152 pages long, it\u2019s essentially the bible for anyone looking to be a great animator. In fact, Pixar chief creative officer John Lasseter used the first edition as a reference when he was an animator at Walt Disney Studios in the early 1980s.\n\nIn the book, authors John Halas and Harold Whitaker advise:\n\n\n\tTiming is the part of animation which gives meaning to movement. Movement can easily be achieved by drawing the same thing in two different positions and inserting a number of other drawings between the two. The result on the screen will be movement; but it will not be animation.\n\n\nBut that\u2019s exactly what we\u2019re doing with CSS3 and JavaScript: we\u2019re moving elements, not animating them. We\u2019re constantly specifying beginning and end states and allowing the technology to interpolate between the two. And yet, it\u2019s the nuances within those middle frames that create the sense of life we\u2019re looking for.\n\nAs bandwidth increases and browser rendering grows more consistent, we can create interactions in different ways than we\u2019ve been able to before. We\u2019re encountering motion more and more on sites we\u2019d generally label \u2018static.\u2019 However, this motion is mostly just movement, not animation. It\u2019s the manipulation of an element\u2019s properties, most commonly width, height, x- and y-coordinates, and opacity.\n\nSo how do we create real animation?\n\nThe metaphor\n\nIn my experience, animation is most believable when it simulates, exaggerates, or defies the real world. A bowling ball falls differently than a racquetball. They each have different weights and sizes, which affect the way they land, bounce, and impact other objects.\n\nThis is a major reason that JavaScript animation frequently feels mechanical; it doesn\u2019t complete a metaphor. Expanding and collapsing a <div> feels very different than a opening a door or unfolding a piece of paper, but it often shouldn\u2019t. The interaction itself should tie directly to the art direction of a page.\n\nPhysics\n\nUnderstanding the physics of a situation is key to creating convincing animation, even if your animation seeks to defy conventional physics. Isaac Newton\u2019s first law of motion\u2019s_laws_of_motion states, \u201cEvery body remains in a state of rest or uniform motion (constant velocity) unless it is acted upon by an external unbalanced force.\u201d Once a force acts upon an object, the object\u2019s shape can change accordingly, depending on the strength of the force and the mass of the object. Another nugget of wisdom from Halas and Whitaker:\n\n\n\tAll objects in nature have their own weight, construction, and degree of flexibility, and therefore each behaves in its own individual way when a force acts upon it. This behavior, a combination of position and timing, is the basis of animation. The basic question which an animator is continually asking himself is this: \u201cWhat will happen to this object when a force acts upon it?\u201d And the success of his animation largely depends on how well he answers this question.\n\n\nIn animating with CSS3 and JavaScript, keep physics in mind. How \u2018heavy\u2019 is the element you\u2019re interacting with? What kind of force created the action? A gentle nudge? A forceful shove? These subtleties will add a sense of realism to your animations and make them much more believable to your users.\n\nMisdirection\n\nMagicians often use misdirection to get their audience to focus on one thing rather than another. They fool us into thinking something happened that actually didn\u2019t.\n\nAnimation is the same, especially on a screen. By changing the arrangement of pixels on screen at a fast enough rate, your eyes fool your mind into thinking an object is actually in motion. \n\nAnother important component of misdirecting in animation is the use of multiple objects. Try to recall a cartoon where a character vanishes. More often, the character makes some sort of exaggerated motion (this is called anticipation) then disappears, and a puff a smoke follows. That smoke is an extra element, but it goes a long way into make you believe that character actually disappeared.\n\nVery rarely does a vanishing character\u2019s opacity simply go from one hundred per cent to zero. That\u2019s not believable. So why do we do it with <div>s?\n\nArmed with the ammunition of metaphors and misdirection, let\u2019s code an example.\n\nShake, rattle, and roll\n\n(These demos require at least a basic understanding of jQuery and CSS3. Run away if your\u2019re afraid, or brush up on CSS animation and resources for learning jQuery. Also, these demos use WebKit-specific features and are best viewed in the latest version of Safari, so performance in other browsers may vary.)\n\nWe often see the design pattern of clicking a link to reveal content. Our \u201cfirst demo\u201d:\u201d/examples/2010/real-animation/demo1/ shows us exactly that. It uses jQuery\u2019s \u201c slideDown()\u201d:http://api.jquery.com/slideDown/ method, as many instances do.\n\nBut what force acted on the <div> that caused it to open? Did pressing the button unlatch some imaginary hook? Did it activate an unlocking sequence with some gears?\n\nTake 2\n\nOur second demo is more explicit about what happens: the button fell on the <div> and shook its content loose. Here\u2019s how it\u2019s done. \n\nfunction clickHandler(){\n\t$('#button').addClass('animate');\n\treturn false;\n}\n\nClicking the link adds a class of animate to our button. That class has the following CSS associated with it:\n\n<style>\n\t.animate {\n\t\t-webkit-animation-name: ANIMATE;\n\t\t-webkit-animation-duration: 0.25s;\n\t\t-webkit-animation-iteration-count: 1;\n\t\t-webkit-animation-timing-function: ease-in;\n\t}\n\t@-webkit-keyframes ANIMATE {\n\t\tfrom {\n\t\ttop: 72px;\n\t\t}\n\t\tto {\n\t\t\ttop: 112px;\n\t\t}\n\t}\n</style>\n\nIn our keyframe definition, we\u2019ve specified from and to states. This is great, because we can be explicit about how an object starts and finishes moving. \n\nWhat\u2019s also extra handy is that these CSS keyframes broadcast events that you can react to with JavaScript. In this example, we\u2019re listening to the webkitAnimationEnd event and opening the <div> only when the sequence is complete. Here\u2019s that code.\n\nfunction attachAnimationEventHandlers(){\n\tvar wrap = document.getElementById('wrap');\n\twrap.addEventListener('webkitAnimationEnd', function($e) {\n\t\tswitch($e.animationName){\n\t\t\tcase \"ANIMATE\" :\n\t\t\topenMain();\n\t\t\tbreak;\n\t\t\tdefault:\n\t\t}\n\t}, false);\n}\nfunction openMain(){\n\t$('#main .inner').slideDown('slow');\n}\n\n(For more info on handling animation events, check out the documentation at the Safari Reference Library.)\n\nTake 3\n\nThe problem with the previous demo is that the subtleties of timing aren\u2019t evident. It still feels a bit choppy.\n\nFor our third demo, we\u2019ll use percentages instead of keywords so that we can insert as many points as we need to communicate more realistic timing. The percentages allow us to add the keys to well-timed animation: anticipation, hold, release, and reaction. \n\n<style>\n\t@-webkit-keyframes ANIMATE {\n\t\t0% {\n\t\t\ttop: 72px;\n\t\t}\n\t\t40% { /* anticipation */\n\t\t\ttop: 57px;\n\t\t}\n\t\t70% { /* hold */\n\t\t\ttop: 56px;\n\t\t}\n\t\t80% { /* release */\n\t\t\ttop: 112px;\n\t\t}\n\t\t100% { /* return */\n\t\t\ttop: 72px;\n\t\t}\n\t}\n</style>\n\nTake 4\n\nThe button animation is starting to feel much better, but the reaction of the <div> opening seems a bit slow.\n\nThis fourth demo uses jQuery\u2019s delay() method to time the opening precisely when we want it. Since we know the button\u2019s animation is one second long and its reaction starts at eighty per cent of that, that puts our delay at 800ms (eighty per cent of one second). However, here\u2019s a little pro tip: let\u2019s start the opening at 750ms instead. The extra fifty milliseconds makes it feel more like the opening is a reaction to the exact hit of the button. Instead of listening for the webkitAnimationEnd event, we can start the opening as soon as the button is clicked, and the movement plays on the specified delay.\n\nfunction clickHandler(){\n\t$('#button').addClass('animate');\n\topenMain();\n\treturn false;\n}\nfunction openMain(){\n\t$('#main .inner').delay(750).slideDown('slow');\n}\n\nTake 5\n\nWe can tweak the timing of that previous animation forever, but that\u2019s probably as close as we\u2019re going to get to realistic animation with CSS and JavaScript. However, for some extra sauce, we could relegate the whole animation in our final demo to a video sequence which includes more nuances and extra elements for misdirection.\n\nHere\u2019s the basis of video replacement. Add a <video> element to the page and adjust its opacity to zero. Once the button is clicked, fade the button out and start playing the video. Once the video is finished playing, fade it out and bring the button back.\n\nfunction clickHandler(){\n\tif($('#main .inner').is(':hidden')){\n\t\t$('#button').fadeTo(100, 0);\n\t\t$('#clickVideo').fadeTo(100, 1, function(){\n\t\t\tvar clickVideo = document.getElementById('clickVideo');\n\t\t\tclickVideo.play();\n\t\t\tsetTimeout(removeVideo, 2400);\n\t\t\topenMain();\n\t\t});\n\t}\n\treturn false;\n}\nfunction removeVideo(){\n\t$('#button').fadeTo(500, 1);\n\t$('#clickVideo').fadeOut('slow');\n}\nfunction openMain(){\n\t$('#main .inner').delay(1100).slideDown('slow');\n}\n\nWrapping up\n\nI\u2019m no JavaScript expert by any stretch. I\u2019m sure a lot of you scripting wizards out there could write much cleaner and more efficient code, but I hope this gives you an idea of the theory behind more realistic motion with the technology we\u2019re using most. This is just one model of creating more convincing animation, but you can create countless variations of this, including\u2026\n\n\n\tExporting <video> animations in 3-D animation tools or 2-D animation tools like Flash or After Effects\n\tUsing <canvas> or SVG instead of <video>\n\tEmploying specific JavaScript animation frameworks\n\tMaking use of all the powerful properties of CSS Transforms and CSS Animation\n\tTrying out emerging CSS3 animation tools like Sencha Animator\n\n\nIf it wasn\u2019t already apparent, these demos show an exaggerated example and probably aren\u2019t practical in a lot of environments. However, there are a handful of great sites out there that honor animation techniques\u2014metaphor, physics, and misdirection, among others\u2014like Benjamin De Cock\u2019s vCard, 20 Things I Learned About Browsers and the Web by Fantasy Interactive, and the Nike Snowboarding site by Ian Coyle and HEGA. They\u2019re wonderful testaments to what you can do to aid interaction for users.\n\nMy goal was to show you the \u2018why\u2019 and the \u2018how.\u2019 Your charge is to discern the \u2018where\u2019 and the \u2018when.\u2019 Happy animating!", "year": "2010", "author": "Dan Mall", "author_slug": "danmall", "published": "2010-12-15T00:00:00+00:00", "url": "https://24ways.org/2010/real-animation-using-javascript-css3-and-html5-video/", "topic": "code"} {"rowid": 234, "title": "An Introduction to CSS 3-D Transforms", "contents": "Ladies and gentlemen, it is the second decade of the third millennium and we are still kicking around the same 2-D interface we got three decades ago. Sure, Apple debuted a few apps for OSX 10.7 that have a couple more 3-D flourishes, and Microsoft has had that Flip 3D for a while. But c\u2019mon \u2013 2011 is right around the corner. That\u2019s Twenty Eleven, folks. Where is our 3-D virtual reality? By now, we should be zipping around the Metaverse on super-sonic motorbikes.\n\nGranted, the capability of rendering complex 3-D environments has been present for years. On the web, there are already several solutions: Flash; three.js in <canvas>; and, eventually, WebGL. Finally, we meagre front-end developers have our own three-dimensional jewel: CSS 3-D transforms!\n\nRationale\n\nLike a beautiful jewel, 3-D transforms can be dazzling, a true spectacle to behold. But before we start tacking 3-D diamonds and rubies to our compositions like Liberace\u2018s tailor, we owe it to our users to ask how they can benefit from this awesome feature. \n\nAn entire application should not take advantage of 3-D transforms. CSS was built to style documents, not generate explorable environments. I fail to find a benefit to completing a web form that can be accessed by swivelling my viewport to the Sign-Up Room (although there have been proposals to make the web just that). Nevertheless, there are plenty of opportunities to use 3-D transforms in between interactions with the interface, via transitions.\n\nTake, for instance, the Weather App on the iPhone. The application uses two views: a details view; and an options view. Switching between these two views is done with a 3-D flip transition. This informs the user that the interface has two \u2013 and only two \u2013 views, as they can exist only on either side of the same plane.\n\n Flipping from details view to options view via a 3-D transition\n\nAlso, consider slide shows. When you\u2019re looking at the last slide, what cues tip you off that advancing will restart the cycle at the first slide? A better paradigm might be achieved with a 3-D transform, placing the slides side-by-side in a circle (carousel) in three-dimensional space; in that arrangement, the last slide obviously comes before the first.\n\n3-D transforms are more than just eye candy. We can also use them to solve dilemmas and make our applications more intuitive. \n\nCurrent support\n\nThe CSS 3D Transforms module has been out in the wild for over a year now. Currently, only Safari supports the specification \u2013 which includes Safari on Mac OS X and Mobile Safari on iOS. \n\nThe support roadmap for other browsers varies. The Mozilla team has taken some initial steps towards implementing the module. Mike Taylor tells me that the Opera team is keeping a close eye on CSS transforms, and is waiting until the specification is fleshed out. And our best friend Internet Explorer still needs to catch up to 2-D transforms before we can talk about the 3-D variety.\n\nTo make matters more perplexing, Safari\u2019s WebKit cousin Chrome currently accepts 3-D transform declarations, but renders them in 2-D space. Chrome team member Paul Irish, says that 3-D transforms are on the horizon, perhaps in one of the next 8.0 releases.\n\nThis all adds up to a bit of a challenge for those of us excited by 3-D transforms. I\u2019ll give it to you straight: missing the dimension of depth can make degradation a bit ungraceful. Unless the transform is relatively simple and holds up in non-3D-supporting browsers, you\u2019ll most likely have to design another solution. But what\u2019s another hurdle in a steeplechase? We web folk have had our mettle tested for years. We\u2019re prepared to devise multiple solutions.\n\nHere\u2019s the part of the article where I mention Modernizr, and you brush over it because you\u2019ve read this part of an article hundreds of times before. But seriously, it\u2019s the best way to test for CSS 3-D transform support. Use it.\n\nEven with these difficulties mounting up, trying out 3-D transforms today is the right move. The CSS 3-D transforms module was developed by the same team at Apple that produced the CSS 2D Transforms and Animation modules. Both specifications have since been adopted by Mozilla and Opera. Transforming in three-dimensions now will guarantee you\u2019ll be ahead of the game when the other browsers catch up.\n\nThe choice is yours. You can make excuses and pooh-pooh 3-D transforms because they\u2019re too hard and only snobby Apple fans will see them today. Or, with a tip of the fedora to Mr Andy Clarke, you can get hard-boiled and start designing with the best features out there right this instant.\n\nSo, I bid you, in the words of the eternal Optimus Prime\u2026\n\n\n\tTransform and roll out.\n\n\nLet\u2019s get coding.\n\nPerspective\n\nTo activate 3-D space, an element needs perspective. This can be applied in two ways: using the transform property, with the perspective as a functional notation:\n\n-webkit-transform: perspective(600);\n\nor using the perspective property: \n\n-webkit-perspective: 600;\n\nSee example: Perspective 1.\n\n\n\n The red element on the left uses transform: perspective() functional notation; the blue element on the right uses the perspective property\n\n\n\nThese two formats both trigger a 3-D space, but there is a difference. The first, functional notation is convenient for directly applying a 3-D transform on a single element (in the previous example, I use it in conjunction with a rotateY transform). But when used on multiple elements, the transformed elements don\u2019t line up as expected. If you use the same transform across elements with different positions, each element will have its own vanishing point. To remedy this, use the perspective property on a parent element, so each child shares the same 3-D space.\n\nSee Example: Perspective 2.\n\n\n\n Each red box on the left has its own vanishing point within the parent container; the blue boxes on the right share the vanishing point of the parent container\n\n\n\nThe value of perspective determines the intensity of the 3-D effect. Think of it as a distance from the viewer to the object. The greater the value, the further the distance, so the less intense the visual effect. perspective: 2000; yields a subtle 3-D effect, as if we were viewing an object from far away. perspective: 100; produces a tremendous 3-D effect, like a tiny insect viewing a massive object.\n\nBy default, the vanishing point for a 3-D space is positioned at its centre. You can change the position of the vanishing point with perspective-origin property.\n\n-webkit-perspective-origin: 25% 75%;\n\nSee Example: Perspective 3.\n\n\n\n\n\n\n\n3-D transform functions\n\nAs a web designer, you\u2019re probably well acquainted with working in two dimensions, X and Y, positioning items horizontally and vertically. With a 3-D space initialised with perspective, we can now transform elements in all three glorious spatial dimensions, including the third Z dimension, depth. \n\n3-D transforms use the same transform property used for 2-D transforms. If you\u2019re familiar with 2-D transforms, you\u2019ll find the basic 3D transform functions fairly similar. \n\n\n\trotateX(angle)\n\trotateY(angle)\n\trotateZ(angle)\n\ttranslateZ(tz)\n\tscaleZ(sz)\n\n\nWhereas translateX() positions an element along the horizontal X-axis, translateZ() positions it along the Z-axis, which runs front to back in 3-D space. Positive values position the element closer to the viewer, negative values further away.\n\nThe rotate functions rotate the element around the corresponding axis. This is somewhat counter-intuitive at first, as you might imagine that rotateX will spin an object left to right. Instead, using rotateX(45deg) rotates an element around the horizontal X-axis, so the top of the element angles back and away, and the bottom gets closer to the viewer.\n\nSee Example: Transforms 1.\n\n\n\n3-D rotate() and translate() functions around each axis\n\n\n\nThere are also several shorthand transform functions that require values for all three dimensions:\n\n\n\ttranslate3d(tx,ty,tz)\n\tscale3d(sx,sy,sz)\n\trotate3d(rx,ry,rz,angle)\n\n\nPro-tip: These foo3d() transform functions also have the benefit of triggering hardware acceleration in Safari. Dean Jackson, CSS 3-D transform spec author and main WebKit dude, writes (to Thomas Fuchs):\n\n\n\tIn essence, any transform that has a 3D operation as one of its functions will trigger hardware compositing, even when the actual transform is 2D, or not doing anything at all (such as translate3d(0,0,0)). Note this is just current behaviour, and could change in the future (which is why we don\u2019t document or encourage it). But it is very helpful in some situations and can significantly improve redraw performance.\n\n\nFor the sake of simplicity, my demos will use the basic transform functions, but if you\u2019re writing production-ready CSS for iOS or Safari-only, make sure to use the foo3d() functions to get the best rendering performance.\n\nCard flip\n\nWe now have all the tools to start making 3-D objects. Let\u2019s get started with something simple: flipping a card.\n\nHere\u2019s the basic markup we\u2019ll need:\n\n<section class=\"container\">\n <div id=\"card\">\n <figure class=\"front\">1</figure>\n <figure class=\"back\">2</figure>\n </div>\n</section>\n\nThe .container will house the 3-D space. The #card acts as a wrapper for the 3-D object. Each face of the card has a separate element: .front; and .back. Even for such a simple object, I recommend using this same pattern for any 3-D transform. Keeping the 3-D space element and the object element(s) separate establishes a pattern that is simple to understand and easier to style.\n\nWe\u2019re ready for some 3-D stylin\u2019. First, apply the necessary perspective to the parent 3-D space, along with any size or positioning styles.\n\n.container { \n width: 200px;\n height: 260px;\n position: relative;\n -webkit-perspective: 800;\n}\n\nNow the #card element can be transformed in its parent\u2019s 3-D space. We\u2019re combining absolute and relative positioning so the 3-D object is removed from the flow of the document. We\u2019ll also add width: 100%; and height: 100%;. This ensures the object\u2019s transform-origin will occur in the centre of .container. More on transform-origin later. \n\nLet\u2019s add a CSS3 transition so users can see the transform take effect. \n\n#card {\n width: 100%;\n height: 100%;\n position: absolute;\n -webkit-transform-style: preserve-3d;\n -webkit-transition: -webkit-transform 1s;\n}\n\nThe .container\u2019s perspective only applies to direct descendant children, in this case #card. In order for subsequent children to inherit a parent\u2019s perspective, and live in the same 3-D space, the parent can pass along its perspective with transform-style: preserve-3d. Without 3-D transform-style, the faces of the card would be flattened with its parents and the back face\u2019s rotation would be nullified. \n\nTo position the faces in 3-D space, we\u2019ll need to reset their positions in 2-D with position: absolute. In order to hide the reverse sides of the faces when they are faced away from the viewer, we use backface-visibility: hidden. \n\n#card figure {\n display: block;\n position: absolute;\n width: 100%;\n height: 100%;\n -webkit-backface-visibility: hidden;\n}\n\nTo flip the .back face, we add a basic 3-D transform of rotateY(180deg). \n\n#card .front {\n background: red;\n}\n#card .back {\n background: blue;\n -webkit-transform: rotateY(180deg);\n}\n\nWith the faces in place, the #card requires a corresponding style for when it is flipped.\n\n#card.flipped {\n -webkit-transform: rotateY(180deg);\n}\n\nNow we have a working 3-D object. To flip the card, we can toggle the flipped class. When .flipped, the #card will rotate 180 degrees, thus exposing the .back face.\n\nSee Example: Card 1.\n\n\n\nFlipping a card in three dimensions\n\n\n\nSlide-flip\n\nTake another look at the Weather App 3-D transition. You\u2019ll notice that it\u2019s not quite the same effect as our previous demo. If you follow the right edge of the card, you\u2019ll find that its corners stay within the container. Instead of pivoting from the horizontal centre, it pivots on that right edge. But the transition is not just a rotation \u2013 the edge moves horizontally from right to left. We can reproduce this transition just by modifying a couple of lines of CSS from our original card flip demo.\n\nThe pivot point for the rotation occurs at the right side of the card. By default, the transform-origin of an element is at its horizontal and vertical centre (50% 50% or center center). Let\u2019s change it to the right side:\n\n#card { -webkit-transform-origin: right center; }\n\nThat flip now needs some horizontal movement with translateX. We\u2019ll set the rotation to -180deg so it flips right side out.\n\n#card.flipped {\n -webkit-transform: translateX(-100%) rotateY(-180deg);\n}\n\nSee Example: Card 2.\n\n\n\nCreating a slide-flip from the right edge of the card\n\n\n\nCube\n\nCreating 3-D card objects is a good way to get started with 3-D transforms. But once you\u2019ve mastered them, you\u2019ll be hungry to push it further and create some true 3-D objects: prisms. We\u2019ll start out by making a cube.\n\nThe markup for the cube is similar to the card. This time, however, we need six child elements for all six faces of the cube:\n\n<section class=\"container\">\n <div id=\"cube\">\n <figure class=\"front\">1</figure>\n <figure class=\"back\">2</figure>\n <figure class=\"right\">3</figure>\n <figure class=\"left\">4</figure>\n <figure class=\"top\">5</figure>\n <figure class=\"bottom\">6</figure>\n </div>\n</section>\n\nBasic position and size styles set the six faces on top of one another in the container.\n\n.container {\n width: 200px;\n height: 200px;\n position: relative;\n -webkit-perspective: 1000;\n}\n#cube {\n width: 100%;\n height: 100%;\n position: absolute;\n -webkit-transform-style: preserve-3d;\n}\n#cube figure {\n width: 196px;\n height: 196px;\n display: block;\n position: absolute;\n border: 2px solid black;\n}\n\nWith the card, we only had to rotate its back face. The cube, however, requires that five of the six faces to be rotated. Faces 1 and 2 will be the front and back. Faces 3 and 4 will be the sides. Faces 5 and 6 will be the top and bottom.\n\n#cube .front { -webkit-transform: rotateY(0deg); }\n#cube .back { -webkit-transform: rotateX(180deg); }\n#cube .right { -webkit-transform: rotateY(90deg); }\n#cube .left { -webkit-transform: rotateY(-90deg); }\n#cube .top { -webkit-transform: rotateX(90deg); }\n#cube .bottom { -webkit-transform: rotateX(-90deg); }\n\nWe could remove the first #cube .front style declaration, as this transform has no effect, but let\u2019s leave it in to keep our code consistent.\n\nNow each face is rotated, and only the front face is visible. The four side faces are all perpendicular to the viewer, so they appear invisible. To push them out to their appropriate sides, they need to be translated out from the centre of their positions. Each side of the cube is 200 pixels wide. From the cube\u2019s centre they\u2019ll need to be translated out half that distance, 100px.\n\n#cube .front { -webkit-transform: rotateY(0deg) translateZ(100px); }\n#cube .back { -webkit-transform: rotateX(180deg) translateZ(100px); }\n#cube .right { -webkit-transform: rotateY(90deg) translateZ(100px); }\n#cube .left { -webkit-transform: rotateY(-90deg) translateZ(100px); }\n#cube .top { -webkit-transform: rotateX(90deg) translateZ(100px); }\n#cube .bottom { -webkit-transform: rotateX(-90deg) translateZ(100px); }\n\nNote here that the translateZ function comes after the rotate. The order of transform functions is important. Take a moment and soak this up. Each face is first rotated towards its position, then translated outward in a separate vector.\n\nWe have a working cube, but we\u2019re not done yet.\n\nReturning to the Z-axis origin\n\nFor the sake of our users, our 3-D transforms should not distort the interface when the active panel is at its resting position. But once we start pushing elements off their Z-axis origin, distortion is inevitable. \n\nIn order to keep 3-D transforms snappy, Safari composites the element, then applies the transform. Consequently, anti-aliasing on text will remain whatever it was before the transform was applied. When transformed forward in 3-D space, significant pixelation can occur. \n\nSee Example: Transforms 2.\n\n\n\n\n\n\n\nLooking back at the Perspective 3 demo, note that no matter how small the perspective value is, or wherever the transform-origin may be, the panel number 1 always returns to its original position, as if all those funky 3-D transforms didn\u2019t even matter.\n\nTo resolve the distortion and restore pixel perfection to our #cube, we can push the 3-D object back, so that the front face will be positioned back to the Z-axis origin.\n\n#cube { -webkit-transform: translateZ(-100px); }\n\nSee Example: Cube 1.\n\n\n\nRestoring the front face to the original position on the Z-axis\n\n\n\nRotating the cube\n\nTo expose any face of the cube, we\u2019ll need a style that rotates the cube to expose any face. The transform values are the opposite of those for the corresponding face. We toggle the necessary class on the #box to apply the appropriate transform.\n\n#cube.show-front { -webkit-transform: translateZ(-100px) rotateY(0deg); }\n#cube.show-back { -webkit-transform: translateZ(-100px) rotateX(-180deg); }\n#cube.show-right { -webkit-transform: translateZ(-100px) rotateY(-90deg); }\n#cube.show-left { -webkit-transform: translateZ(-100px) rotateY(90deg); }\n#cube.show-top { -webkit-transform: translateZ(-100px) rotateX(-90deg); }\n#cube.show-bottom { -webkit-transform: translateZ(-100px) rotateX(90deg); }\n\nNotice how the order of the transform functions has reversed. First, we push the object back with translateZ, then we rotate it.\n\nFinishing up, we can add a transition to animate the rotation between states. \n\n#cube { -webkit-transition: -webkit-transform 1s; }\n\nSee Example: Cube 2.\n\n\n\nRotating the cube with a CSS transition\n\n\n\nRectangular prism\n\nCubes are easy enough to generate, as we only have to worry about one measurement. But how would we handle a non-regular rectangular prism? Let\u2019s try to make one that\u2019s 300 pixels wide, 200 pixels high, and 100 pixels deep. \n\nThe markup remains the same as the #cube, but we\u2019ll switch the cube id for #box. The container styles remain mostly the same:\n\n.container {\n width: 300px;\n height: 200px;\n position: relative;\n -webkit-perspective: 1000;\n}\n#box {\n width: 100%;\n height: 100%;\n position: absolute;\n -webkit-transform-style: preserve-3d;\n}\n\nNow to position the faces. Each set of faces will need their own sizes. The smaller faces (left, right, top and bottom) need to be positioned in the centre of the container, where they can be easily rotated and then shifted outward. The thinner left and right faces get positioned left: 100px ((300\u2009\u2212\u2009100)\u2009\u00f7\u20092), The stouter top and bottom faces get positioned top: 50px ((200\u2009\u2212\u2009100)\u2009\u00f7\u20092).\n\n#box figure {\n display: block;\n position: absolute;\n border: 2px solid black;\n}\n#box .front,\n#box .back {\n width: 296px;\n height: 196px;\n}\n#box .right,\n#box .left {\n width: 96px;\n height: 196px;\n left: 100px;\n}\n#box .top,\n#box .bottom {\n width: 296px;\n height: 96px;\n top: 50px;\n}\n\nThe rotate values can all remain the same as the cube example, but for this rectangular prism, the translate values do differ. The front and back faces are each shifted out 50 pixels since the #box is 100 pixels deep. The translate value for the left and right faces is 150 pixels for their 300 pixels width. Top and bottom panels take 100 pixels for their 200 pixels height:\n\n#box .front { -webkit-transform: rotateY(0deg) translateZ(50px); }\n#box .back { -webkit-transform: rotateX(180deg) translateZ(50px); }\n#box .right { -webkit-transform: rotateY(90deg) translateZ(150px); }\n#box .left { -webkit-transform: rotateY(-90deg) translateZ(150px); }\n#box .top { -webkit-transform: rotateX(90deg) translateZ(100px); }\n#box .bottom { -webkit-transform: rotateX(-90deg) translateZ(100px); }\n\nSee Example: Box 1.\n\n\n\n\n\n\n\nJust like the cube example, to expose a face, the #box needs to have a style to reverse that face\u2019s transform. Both the translateZ and rotate values are the opposites of the corresponding face.\n\n#box.show-front { -webkit-transform: translateZ(-50px) rotateY(0deg); }\n#box.show-back { -webkit-transform: translateZ(-50px) rotateX(-180deg); }\n#box.show-right { -webkit-transform: translateZ(-150px) rotateY(-90deg); }\n#box.show-left { -webkit-transform: translateZ(-150px) rotateY(90deg); }\n#box.show-top { -webkit-transform: translateZ(-100px) rotateX(-90deg); }\n#box.show-bottom { -webkit-transform: translateZ(-100px) rotateX(90deg); }\n\nSee Example: Box 2.\n\n\n\nRotating the rectangular box with a CSS transition\n\n\n\nCarousel\n\nFront-end developers have a myriad of choices when it comes to content carousels. Now that we have 3-D capabilities in our browsers, why not take a shot at creating an actual 3-D carousel?\n\nThe markup for this demo takes the same form as the box, cube and card. Let\u2019s make it interesting and have a carousel with nine panels.\n\n<div class=\"container\">\n <div id=\"carousel\">\n <figure>1</figure>\n <figure>2</figure>\n <figure>3</figure>\n <figure>4</figure>\n <figure>5</figure>\n <figure>6</figure>\n <figure>7</figure>\n <figure>8</figure>\n <figure>9</figure>\n </div>\n</div>\n\nNow, apply basic layout styles. Let\u2019s give each panel of the #carousel 20 pixel gaps between one another, done here with left: 10px; and top: 10px;. The effective width of each panel is 210 pixels.\n\n.container {\n width: 210px;\n height: 140px;\n position: relative;\n -webkit-perspective: 1000;\n}\n#carousel {\n width: 100%;\n height: 100%;\n position: absolute;\n -webkit-transform-style: preserve-3d;\n}\n#carousel figure {\n display: block;\n position: absolute;\n width: 186px;\n height: 116px;\n left: 10px;\n top: 10px;\n border: 2px solid black;\n}\n\nNext up: rotating the faces. This #carousel has nine panels. If each panel gets an equal distribution on the carousel, each panel would be rotated forty degrees from its neighbour (360\u2009\u00f7\u20099).\n\n#carousel figure:nth-child(1) { -webkit-transform: rotateY(0deg); }\n#carousel figure:nth-child(2) { -webkit-transform: rotateY(40deg); }\n#carousel figure:nth-child(3) { -webkit-transform: rotateY(80deg); }\n#carousel figure:nth-child(4) { -webkit-transform: rotateY(120deg); }\n#carousel figure:nth-child(5) { -webkit-transform: rotateY(160deg); }\n#carousel figure:nth-child(6) { -webkit-transform: rotateY(200deg); }\n#carousel figure:nth-child(7) { -webkit-transform: rotateY(240deg); }\n#carousel figure:nth-child(8) { -webkit-transform: rotateY(280deg); }\n#carousel figure:nth-child(9) { -webkit-transform: rotateY(320deg); }\n\nNow, the outward shift. Back when we were creating the cube and box, the translate value was simple to calculate, as it was equal to one half the width, height or depth of the object. With this carousel, there is no size we can automatically use as a reference. We\u2019ll have to calculate the distance of the shift by other means.\n\n\n\nDrawing a diagram of the carousel, we can see that we know only two things: the width of each panel is 210 pixels; and the each panel is rotated forty degrees from the next. If we split one of these segments down its centre, we get a right-angled triangle, perfect for some trigonometry.\n\nWe can determine the length of r in this diagram with a basic tangent equation:\n\n\n\nThere you have it: the panels need to be translated 288 pixels in 3-D space. \n\n#carousel figure:nth-child(1) { -webkit-transform: rotateY(0deg) translateZ(288px); }\n#carousel figure:nth-child(2) { -webkit-transform: rotateY(40deg) translateZ(288px); }\n#carousel figure:nth-child(3) { -webkit-transform: rotateY(80deg) translateZ(288px); }\n#carousel figure:nth-child(4) { -webkit-transform: rotateY(120deg) translateZ(288px); }\n#carousel figure:nth-child(5) { -webkit-transform: rotateY(160deg) translateZ(288px); }\n#carousel figure:nth-child(6) { -webkit-transform: rotateY(200deg) translateZ(288px); }\n#carousel figure:nth-child(7) { -webkit-transform: rotateY(240deg) translateZ(288px); }\n#carousel figure:nth-child(8) { -webkit-transform: rotateY(280deg) translateZ(288px); }\n#carousel figure:nth-child(9) { -webkit-transform: rotateY(320deg) translateZ(288px); }\n\nIf we decide to change the width of the panel or the number of panels, we only need to plug in those two variables into our equation to get the appropriate translateZ value. In JavaScript terms, that equation would be:\n\nvar tz = Math.round( ( panelSize / 2 ) / \n Math.tan( ( ( Math.PI * 2 ) / numberOfPanels ) / 2 ) );\n// or simplified to\nvar tz = Math.round( ( panelSize / 2 ) / \n Math.tan( Math.PI / numberOfPanels ) );\n\nJust like our previous 3-D objects, to show any one panel we need only apply the reverse transform on the carousel. Here\u2019s the style to show the fifth panel:\n\n-webkit-transform: translateZ(-288px) rotateY(-160deg);\n\nSee Example: Carousel 1.\n\n\n\n\n\n\n\nBy now, you probably have two thoughts: \n\n\n\tRewriting transform styles for each panel looks tedious.\n\tWhy bother doing high school maths? Aren\u2019t robots supposed to be doing all this work for us?\n\n\nAnd you\u2019re absolutely right. The repetitive nature of 3-D objects lends itself to scripting. We can offload all the monotonous transform styles to our dynamic script, which, if done correctly, will be more flexible than the hard-coded version.\n\nSee Example: Carousel 2.\n\nConclusion\n\n3-D transforms change the way we think about the blank canvas of web design. Better yet, they change the canvas itself, trading in the flat surface for voluminous depth.\n\nMy hope is that you took at least one peak at a demo and were intrigued. We web designers, who have rejoiced for border-radius, box-shadow and background gradients, now have an incredible tool at our disposal in 3-D transforms. They deserve just the same enthusiasm, research and experimentation we have seen on other CSS3 features. Now is the perfect time to take the plunge and start thinking about how to use three dimensions to elevate our craft. I\u2019m breathless waiting for what\u2019s to come. \n\nSee you on the flip side.", "year": "2010", "author": "David DeSandro", "author_slug": "daviddesandro", "published": "2010-12-14T00:00:00+00:00", "url": "https://24ways.org/2010/intro-to-css-3d-transforms/", "topic": "code"} {"rowid": 221, "title": "\u201cProbably, Maybe, No\u201d: The State of HTML5 Audio", "contents": "With the hype around HTML5 and CSS3 exceeding levels not seen since 2005\u2019s Ajax era, it\u2019s worth noting that the excitement comes with good reason: the two specifications render many years of feature hacks redundant by replacing them with native features. For fun, consider how many CSS2-based rounded corners hacks you\u2019ve probably glossed over, looking for a magic solution. These days, with CSS3, the magic is border-radius (and perhaps some vendor prefixes) followed by a coffee break.\n\nCSS3\u2019s border-radius, box-shadow, text-shadow and gradients, and HTML5\u2019s <canvas>, <audio> and <video> are some of the most anticipated features we\u2019ll see put to creative (ab)use as adoption of the \u2018new shiny\u2019 grows. Developers jumping on the cutting edge are using subsets of these features to little detriment, in most cases. The more popular CSS features are design flourishes that can degrade nicely, but the current audio and video implementations in particular suffer from a number of annoyances.\n\nThe new shiny: how we got here\n\nSound involves one of the five senses, a key part of daily life for most \u2013 and yet it has been strangely absent from HTML and much of the web by default. From a simplistic perspective, it seems odd that HTML did not include support for the full multimedia experience earlier, despite the CD-ROM-based craze of the early 1990s. In truth, standards like HTML can take much longer to bake, but eventually deliver the promise of a lowered barrier to entry, consistent implementations and shiny new features now possible \u2018for free\u2019 just about everywhere.\n\n<img> was introduced early and naturally to HTML, despite having some opponents at the time. Perhaps <audio> and <video> were avoided, given the added technical complexity of decoding various multi-frame formats, plus the hardware and bandwidth limitations of the era. Perhaps there were quarrels about choosing a standard format or \u2013 more simply \u2013 maybe these elements just weren\u2019t considered to be applicable to the HTML-based web at the time. In any event, browser plugins from programs like RealPlayer and QuickTime eventually helped to fill the in-page audio/video gap, handling <object> and <embed> markup which pointed to .wav, .avi, .rm or .mov files. Suffice it to say, the experience was inconsistent at best and, on the standards side of the fence right now, so is HTML5 in terms of audio and video.\n\n: the theory\n\nAs far as HTML goes, the code for <audio> is simple and logical. Just as with <img>, a src attribute specifies the file to load. Pretty straightforward \u2013 sounds easy, right?\n\n<audio src=\"mysong.ogg\" controls>\n\t<!-- alternate content for unsupported case -->\n\tDownload <a href=\"mysong.ogg\">mysong.ogg</a>;\n</audio>\n\nAh, if only it were that simple. The first problem is that the OGG audio format, while \u2018free\u2019, is not supported by some browsers. Conversely, nor is MP3, despite being a de facto standard used in all kinds of desktop software (and hardware). In fact, as of November 2010, no single audio format is commonly supported across all major HTML5-enabled browsers.\n\nWhat you end up writing, then, is something like this:\n\n<audio controls>\n\t<source src=\"mysong.mp3\" />\n\t<source src=\"mysong.ogg\" />\n\t<!-- alternate content for unsupported case, maybe Flash, etc. -->\n\tDownload <a href=\"mysong.ogg\">mysong.ogg</a> or <a href=\"mysong.mp3\">mysong.mp3</a>\n</audio>\n\nKeep in mind, this is only a \u2018first class\u2019 experience for the HTML5 case; also, for non-supported browsers, you may want to look at another inline player (object/embed, or a JavaScript plus Flash API) to have inline audio. You can imagine the added code complexity in the case of supporting \u2018first class\u2019 experiences for older browsers, too.\n\n: the caveats\n\nWith <img>, you typically don\u2019t have to worry about format support \u2013 it just works \u2013 and that\u2019s part of what makes a standard wonderful. JPEG, PNG, BMP, GIF, even TIFF images all render just fine if for no better reason, perhaps, than being implemented during the \u2018wild west\u2019 days of the web. The situation with <audio> today reflects a very different \u2013 read: business-aware \u2013 environment in 2010. (Further subtext: There\u2019s a lot of [potential] money involved.) Regrettably, this is a collision of free and commercial interests, where the casualty is ultimately the user. Second up in the casualty list is you, the developer, who has to write additional code around this fragmented support.\n\nThe HTML5 audio API as implemented in JavaScript has one of the most un-computer-like responses I\u2019ve ever seen, and inspired the title of this post. Calling new Audio().canPlayType('audio/mp3'), which queries the system for format support according to a MIME type, is supposed to return one of \u201cprobably\u201d, \u201cmaybe\u201d, or \u201cno\u201d. Sometimes, you\u2019ll just get a null or empty string, which is also fun. A \u201cmaybe\u201d response does not guarantee that a format will be supported; sometimes audio/mp3 gives \u201cmaybe,\u201d but then audio/mpeg; codecs=\"mp3\" will give a more-solid \u201cprobably\u201d response. This can vary by browser or platform, too, depending on native support \u2013 and finally, the user may also be able to install codecs, extending support to include other formats. (Are you excited yet?)\n\nDamn you, warring formats!\n\nNew market and business opportunities go hand-in-hand with technology developments. What we have here is certainly not failure to communicate; rather, we have competing parties shouting loudly in public in attempts to influence mindshare towards a de facto standard for audio and video. Unfortunately, the current situation means that at least two formats are effectively required to serve the majority of users correctly.\n\nAs it currently stands, we have the free and open source software camp of OGG Vorbis/WebM and its proponents (notably, Mozilla, Google and Opera in terms of browser makers), up against the non-free, proprietary and \u2018closed\u2019 camp of MP3 and MPEG4/HE-AAC/H.264 \u2013 which is where you\u2019ll find commitments from Apple and Microsoft, among others. Apple is likely in with H.264 for the long haul, given its use of the format for its iTunes music store and video offerings.\n\nIt is generally held that H.264 is a technically superior format in terms of file size versus quality, but it involves intellectual property and, in many use cases, requires licensing fees. To be fair, there is a business model with H.264 and much has been invested in its development, but this approach is not often the kind that wins over the web. On that front, OGG/WebM may eventually win for being a \u2018free\u2019 format that does not involve a licensing scheme.\n\nClosed software and tools ideologically clash with the open nature of the web, which exists largely thanks to free and open technology. Because of philosophical and business reasons, support for audio and video is fragmented across browsers adopting HTML5 features. It does not help that a large amount of audio and video currently exists in non-free MP3 and MPEG-4 formats. Adoption of <audio> and <video> may be slowed, since it is more complex than <img> and may feel \u2018broken\u2019 to developers when edge cases are encountered. Furthermore, the HTML5 spec does not mandate a single required format. The end result is that, as a developer, you must currently provide at least both MP3 and OGG, for example, to serve most existing HTML5-based user agents.\n\nTransitioning to \n\n\n\nThere will be some growing pains as developers start to pick up the new HTML5 shiny, while balancing the needs of current and older agents that don\u2019t support either <audio> or the preferred format you may choose (for example, MP3). In either event, Flash or other plugins can be used as done traditionally within HTML4 documents to embed and play the relevant audio.\n\n\n\nThe SoundManager 2 page player demo in action.\n\n\n\nIdeally, HTML5 audio should be used whenever possible with Flash as the backup option. A few JavaScript/Flash-based audio player projects exist which balance the two; in attempting to tackle this problem, I develop and maintain SoundManager 2, a JavaScript sound API which transparently uses HTML5 Audio() and, if needed, Flash for playing audio files. The internals can get somewhat ugly, but the transition between HTML4 and HTML5 is going to be just that \u2013 and even with HTML5, you will need some form of format fall-back in addition to graceful degradation.\n\nIt may be safest to fall back to MP3/MP4 formats for inline playback at this time, given wide support via Flash, some HTML5-based browsers and mobile devices. Considering the amount of MP3/MP4 media currently available, it is wiser to try these before falling through to a traditional file download process.\n\nEarly findings\n\nHere is a brief list of behavioural notes, annoyances, bugs, quirks and general weirdness I have found while playing with HTML5-based audio at time of writing (November 2010):\n\nApple iPad/iPhone (iOS 4, iPad 3.2+)\n\n\n\tOnly one sound can be played at a time. If a second sound starts, the first is stopped.\n\tNo auto-play allowed. Sounds follow the pop-up window security model and can only be started from within a user event handler such as onclick/touch, and so on. Otherwise, playback attempts silently fail.\n\tOnce started, a sequence of sounds can be created or played via the \u2018finish\u2019 event of the previous sound (for example, advancing through a playlist without interaction after first track starts).\n\tiPad, iOS 3.2: Occasional \u2018infinite loop\u2019 bug seen where audio does not complete and stop at a sound\u2019s logical end \u2013 instead, it plays again from the beginning. Might be specific to example file format (HE-AAC) encoded from iTunes.\n\n\nApple Safari, OS X Snow Leopard 10.6.5\n\n\n\tCritical bug: Safari 4 and 5 intermittently fail to load or play HTML5 audio on Snow Leopard due to bug(s) in QuickTime X and/or other underlying frameworks. Known Apple \u2018radar\u2019 bug: bugs.webkit.org #32159 (see also, test case.) Amusing side note: Safari on Windows is fine.\n\n\nApple Safari, Windows\n\n\n\tFood for thought: if you download \u201cSafari\u201d alone on Windows, you will not get HTML5 audio/video support (tested in WinXP). You need to download \u201cSafari + QuickTime\u201d to get HTML5 audio/video support within Safari. (As far as I\u2019m aware, Chrome, Firefox and Opera either include decoders or use system libraries accordingly. Presumably IE 9 will use OS-level APIs.)\n\n\nGeneral Quirks\n\n\n\tSeeking and loading, \u2018progress\u2019 events, and calculating bytes loaded versus bytes total should not be expected to be linear, as users can arbitrarily seek within a sound. It appears that some support for HTTP ranges exists, which adds a bit of logic to UI code. Browsers seem to vary slightly in their current implementations of these features.\n\tThe onload event of a sound may be of little relevance, if non-linear loading is involved (see above note re: seeking).\n\tInterestingly (perhaps I missed it), the current spec does not seem to specify a panning or left/right channel mix option.\n\tThe preload attribute values may vary slightly between browsers at this time.\n\n\nUpcoming shiny: HTML5 Audio Data API\n\n\n\n\n\tWith access to audio data, you can incorporate waveform and spectrum elements that make your designs react to music.\n\n\n\nThe HTML5 audio spec does a good job covering the basics of playback, but did not initially get into manipulation or generation of audio on-the-fly, something Flash has had for a number of years now. What if JavaScript could create, monitor and change audio dynamically, like a sort of audio <canvas> element? With that kind of capability, many dynamic audio processing features become feasible and, when combined with other media, can make for some impressive demos.\n\nWhat started as a small idea among a small group of audio and programming enthusiasts grew to inspire a W3C audio incubator group, and continued to establish the Mozilla Audio Data API. Contributors wrote a patch for Firefox which was reviewed and revised, and is now slated to be in the public release of Firefox 4. Some background and demos are also detailed in an article from the BBC R&D blog.\n\nThere are plenty of live demos to see, which give an impression of the new creative ideas this API enables. Many concepts are not new in themselves, but it is exciting to see this sort of thing happening within the native browser context.\n\nMozilla is not alone in this effort; the WebKit folks are also working on a JavaScriptAudioNode interface, which implements similar audio buffering and sample elements.\n\nThe future?\n\nIt is my hope that we\u2019ll see a common format emerge in terms of support across the major browsers for both audio and video; otherwise, support will continue to be fragmented and mildly frustrating to develop for, and that can impede growth of the feature. It\u2019s a big call, but if <img> had lacked a common format back in the wild west era, I doubt the web would have grown to where it is today.\n\nComplaints and nitpicks aside, HTML5 brings excellent progress on the browser multimedia front, and the first signs of native support are a welcome improvement given all audio and video previously relied on plugins. There is good reason to be excited. While there is room for more, support could certainly be much worse \u2013 and as tends to happen with specifications, the implementations targeting them should improve over time.\n\nNote: Thanks to Nate Koechley, who suggested the Audio().canPlayType() response be part of the article title.", "year": "2010", "author": "Scott Schiller", "author_slug": "scottschiller", "published": "2010-12-08T00:00:00+00:00", "url": "https://24ways.org/2010/the-state-of-html5-audio/", "topic": "code"} {"rowid": 233, "title": "Wrapping Things Nicely with HTML5 Local Storage", "contents": "HTML5 is here to turn the web from a web of hacks into a web of applications \u2013 and we are well on the way to this goal. The coming year will be totally and utterly awesome if you are excited about web technologies.\n\nThis year the HTML5 revolution started and there is no stopping it. For the first time all the browser vendors are rallying together to make a technology work. The new browser war is fought over implementation of the HTML5 standard and not over random additions. We live in exciting times.\n\nStarting with a bang\n\nAs with every revolution there is a lot of noise with bangs and explosions, and that\u2019s the stage we\u2019re at right now. HTML5 showcases are often CSS3 showcases, web font playgrounds, or video and canvas examples.\n\nThis is great, as it gets people excited and it gives the media something to show. There is much more to HTML5, though. Let\u2019s take a look at one of the less sexy, but amazingly useful features of HTML5 (it was in the HTML5 specs, but grew at such an alarming rate that it warranted its own spec): storing information on the client-side.\n\nWhy store data on the client-side?\n\nStoring information in people\u2019s browsers affords us a few options that every application should have:\n\n\n\tYou can retain the state of an application \u2013 when the user comes back after closing the browser, everything will be as she left it. That\u2019s how \u2018real\u2019 applications work and this is how the web ones should, too.\n\tYou can cache data \u2013 if something doesn\u2019t change then there is no point in loading it over the Internet if local access is so much faster\n\tYou can store user preferences \u2013 without needing to keep that data on your server at all.\n\n\nIn the past, storing local data wasn\u2019t much fun.\n\nThe pain of hacky browser solutions\n\nIn the past, all we had were cookies. I don\u2019t mean the yummy things you get with your coffee, endorsed by the blue, furry junkie in Sesame Street, but the other, digital ones. Cookies suck \u2013 it isn\u2019t fun to have an unencrypted HTTP overhead on every server request for storing four kilobytes of data in a cryptic format. It was OK for 1994, but really neither an easy nor a beautiful solution for the task of storing data on the client.\n\nThen came a plethora of solutions by different vendors \u2013 from Microsoft\u2019s userdata to Flash\u2019s LSO, and from Silverlight isolated storage to Google\u2019s Gears. If you want to know just how many crazy and convoluted ways there are to store a bit of information, check out Samy\u2019s evercookie.\n\nClearly, we needed an easier and standardised way of storing local data.\n\nKeeping it simple \u2013 local storage\n\nAnd, lo and behold, we have one. The local storage API (or session storage, with the only difference being that session data is lost when the window is closed) is ridiculously easy to use. All you do is call a few methods on the window.localStorage object \u2013 or even just set the properties directly using the square bracket notation:\n\nif('localStorage' in window && window['localStorage'] !== null){\n\tvar store = window.localStorage;\n\n\t// valid, API way\n\t\tstore.setItem(\u2018cow\u2019,\u2018moo\u2019);\n\t\tconsole.log(\n\t\tstore.getItem(\u2018cow\u2019)\n\t); // => \u2018moo\u2019\n\n\t// shorthand, breaks at keys with spaces\n\t\tstore.sheep = \u2018baa\u2019 \n\t\tconsole.log(\n\t\tstore.sheep \n\t); // \u2018baa\u2019\n\n\t// shorthand for all\n\t\tstore[\u2018dog\u2019] = \u2018bark\u2019\n\t\tconsole.log(\n\t\tstore[\u2018dog\u2019]\n\t); // => \u2018bark\u2019\n\n}\n\nBrowser support is actually pretty good: Chrome 4+; Firefox 3.5+; IE8+; Opera 10.5+; Safari 4+; plus iPhone 2.0+; and Android 2.0+. That should cover most of your needs. Of course, you should check for support first (or use a wrapper library like YUI Storage Utility or YUI Storage Lite).\n\nThe data is stored on a per domain basis and you can store up to five megabytes of data in localStorage for each domain.\n\nStrings attached\n\nBy default, localStorage only supports strings as storage formats. You can\u2019t store results of JavaScript computations that are arrays or objects, and every number is stored as a string. This means that long, floating point numbers eat into the available memory much more quickly than if they were stored as numbers.\n\nvar cowdesc = \"the cow is of the bovine ilk, \"+\n\t\t\"one end is for the moo, the \"+\n\t\t\"other for the milk\";\n\nvar cowdef = {\n\tilk\u201cbovine\u201d,\n\tlegs,\n\tudders,\n\tpurposes\n\t\tfront\u201cmoo\u201d,\n\t\tend\u201cmilk\u201d\n\t}\n};\n\nwindow.localStorage.setItem(\u2018describecow\u2019,cowdesc);\nconsole.log(\n\twindow.localStorage.getItem(\u2018describecow\u2019)\n); // => the cow is of the bovine\u2026 \n\nwindow.localStorage.setItem(\u2018definecow\u2019,cowdef);\nconsole.log(\n\twindow.localStorage.getItem(\u2018definecow\u2019)\n); // => [object Object] = bad!\n\nThis limits what you can store quite heavily, which is why it makes sense to use JSON to encode and decode the data you store:\n\nvar cowdef = {\n\t\"ilk\":\"bovine\",\n\t\"legs\":4,\n\t\"udders\":4,\n\t\"purposes\":{\n\t\"front\":\"moo\",\n\t\"end\":\"milk\"\n\t}\n};\n\nwindow.localStorage.setItem(\u2018describecow\u2019,JSON.stringify(cowdef));\nconsole.log(\n\tJSON.parse(\n\t\twindow.localStorage.getItem(\u2018describecow\u2019)\n\t)\n); // => Object { ilk=\u201cbovine\u201d, more\u2026}\n\nYou can also come up with your own formatting solutions like CSV, or pipe | or tilde ~ separated formats, but JSON is very terse and has native browser support.\n\nSome use case examples\n\nThe simplest use of localStorage is, of course, storing some data: the current state of a game; how far through a multi-form sign-up process a user is; and other things we traditionally stored in cookies. Using JSON, though, we can do cooler things.\n\nSpeeding up web service use and avoiding exceeding the quota\n\nA lot of web services only allow you a certain amount of hits per hour or day, and can be very slow. By using localStorage with a time stamp, you can cache results of web services locally and only access them after a certain time to refresh the data.\n\nI used this technique in my An Event Apart 10K entry, World Info, to only load the massive dataset of all the world information once, and allow for much faster subsequent visits to the site. The following screencast shows the difference:\n\n\n\nFor use with YQL (remember last year\u2019s 24 ways entry?), I\u2019ve built a small script called YQL localcache that wraps localStorage around the YQL data call. An example would be the following:\n\nyqlcache.get({\n\tyql: 'select * from flickr.photos.search where text=\"santa\"',\n\tid: 'myphotos',\n\tcacheage: ( 60*60*1000 ),\n\tcallback: function(data) {\n\t\tconsole.log(data);\n\t}\n});\n\nThis loads photos of Santa from Flickr and stores them for an hour in the key myphotos of localStorage. If you call the function at various times, you receive an object back with the YQL results in a data property and a type property which defines where the data came from \u2013 live is live data, cached means it comes from cache, and freshcache indicates that it was called for the first time and a new cache was primed. The cache will work for an hour (60\u00d760\u00d71,000 milliseconds) and then be refreshed. So, instead of hitting the YQL endpoint over and over again, you hit it once per hour.\n\nCaching a full interface\n\nAnother use case I found was to retain the state of a whole interface of an application by caching the innerHTML once it has been rendered. I use this in the Yahoo Firehose search interface, and you can get the full story about local storage and how it is used in this screencast:\n\n\n\nThe stripped down code is incredibly simple (JavaScript with PHP embed):\n\n// test for localStorage support\nif(('localStorage' in window) && window['localStorage'] !== null){\n\nvar f = document.getElementById(\u2018mainform\u2019);\n// test with PHP if the form was sent (the submit button has the name \u201csent\u201d)\n\n\n\t// get the HTML of the form and cache it in the property \u201cstate\u201d\n\tlocalStorage.setItem(\u2018state\u2019,f.innerHTML);\n\n// if the form hasn\u2019t been sent\u2026\n\n\n\t// check if a state property exists and write back the HTML cache\n\tif(\u2018state\u2019 in localStorage){\n\t\tf.innerHTML = localStorage.getItem(\u2018state\u2019); \n\t}\n\n\t\n\n}\n\nOther ideas\n\nIn essence, you can use local storage every time you need to speed up access. For example, you could store image sprites in base-64 encoded datasets instead of loading them from a server. Or you could store CSS and JavaScript libraries on the client. Anything goes \u2013 have a play.\n\nIssues with local and session storage\n\nOf course, not all is rainbows and unicorns with the localStorage API. There are a few niggles that need ironing out. As with anything, this needs people to use the technology and raise issues. Here are some of the problems:\n\n\n\tInadequate information about storage quota \u2013 if you try to add more content to an already full store, you get a QUOTA_EXCEEDED_ERR and that\u2019s it. There\u2019s a great explanation and test suite for localStorage quota available.\n\tLack of automatically expiring storage \u2013 a feature that cookies came with. Pamela Fox has a solution (also available as a demo and source code)\n\tLack of encrypted storage \u2013 right now, everything is stored in readable strings in the browser.\n\n\nBigger, better, faster, more!\n\nAs cool as the local and session storage APIs are, they are not quite ready for extensive adoption \u2013 the storage limits might get in your way, and if you really want to go to town with accessing, filtering and sorting data, real databases are what you\u2019ll need. And, as we live in a world of client-side development, people are moving from heavy server-side databases like MySQL to NoSQL environments.\n\nOn the web, there is also a lot of work going on, with Ian Hickson of Google proposing the Web SQL database, and Nikunj Mehta, Jonas Sicking (Mozilla), Eliot Graff (Microsoft) and Andrei Popescu (Google) taking the idea beyond simply replicating MySQL and instead offering Indexed DB as an even faster alternative.\n\nOn the mobile front, a really important feature is to be able to store data to use when you are offline (mobile coverage and roaming data plans anybody?) and you can use the Offline Webapps API for that.\n\nAs I mentioned at the beginning, we have a very exciting time ahead \u2013 let\u2019s make this web work faster and more reliably by using what browsers offer us. For more on local storage, check out the chapter on Dive into HTML5.", "year": "2010", "author": "Christian Heilmann", "author_slug": "chrisheilmann", "published": "2010-12-06T00:00:00+00:00", "url": "https://24ways.org/2010/html5-local-storage/", "topic": "code"} {"rowid": 240, "title": "My CSS Wish List", "contents": "I love Christmas. I love walking around the streets of London, looking at the beautifully decorated windows, seeing the shiny lights that hang above Oxford Street and listening to Christmas songs.\n\nI\u2019m not going to lie though. Not only do I like buying presents, I love receiving them too. I remember making long lists that I would send to Father Christmas with all of the Lego sets I wanted to get. I knew I could only get one a year, but I would spend days writing the perfect list.\n\nThe years have gone by, but I still enjoy making wish lists. And I\u2019ll tell you a little secret: my mum still asks me to send her my Christmas list every year.\n\nThis time I\u2019ve made my CSS wish list. As before, I\u2019d be happy with just one present.\n\nBefore I begin\u2026\n\n\u2026 this list includes:\n\n\n\tthings that don\u2019t exist in the CSS specification (if they do, please let me know in the comments \u2013 I may have missed them);\n\tothers that are in the spec, but it\u2019s incomplete or lacks use cases and examples (which usually means that properties haven\u2019t been implemented by even the most recent browsers).\n\n\nLike with any other wish list, the further down I go, the more unrealistic my expectations \u2013 but that doesn\u2019t mean I can\u2019t wish. Some of the things we wouldn\u2019t have thought possible a few years ago have been implemented and our wishes fulfilled (think multiple backgrounds, gradients and transformations, for example).\n\nThe list\n\nCross-browser implementation of font-size-adjust\n\nWhen one of the fall-back fonts from your font stack is used, rather than the preferred (first) one, you can retain the aspect ratio by using this very useful property. It is incredibly helpful when the fall-back fonts are smaller or larger than the initial one, which can make layouts look less polished.\n\nWhat font-size-adjust does is divide the original font-size of the fall-back fonts by the font-size-adjust value. This preserves the x-height of the preferred font in the fall-back fonts. Here\u2019s a simple example:\n\np {\n font-family: Calibri, \"Lucida Sans\", Verdana, sans-serif;\n font-size-adjust: 0.47;\n}\n\nIn this case, if the user doesn\u2019t have Calibri installed, both Lucida Sans and Verdana will keep Calibri\u2019s aspect ratio, based on the font\u2019s x-height. This property is a personal favourite and one I keep pointing to.\n\nFirefox supported this property from version three. So far, it\u2019s the only browser that does. Fontdeck provides the font-size-adjust value along with its fonts, and has a handy tool for calculating it.\n\nMore control over overflowing text\n\nThe text-overflow property lets you control text that overflows its container. The most common use for it is to show an ellipsis to indicate that there is more text than what is shown. To be able to use it, the container should have overflow set to something other than visible, and white-space: nowrap:\n\ndiv {\n white-space: nowrap;\n width: 100%;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nThis, however, only works for blocks of text on a single line. In the wish list of many CSS authors (and in mine) is a way of defining text-overflow: ellipsis on a block of multiple text lines. Opera has taken the first step and added support for the -o-ellipsis-lastline property, which can be used instead of ellipsis. This property is not part of the CSS3 spec, but we could certainly make good use of it if it were\u2026\n\nWebKit has -webkit-line-clamp to specify how many lines to show before cutting with an ellipsis, but support is patchy at best and there is no control over where the ellipsis shows in the text. Many people have spent time wrangling JavaScript to do this for us, but the methods used are very processor intensive, and introduce a JavaScript dependency.\n\nIndentation and hanging punctuation properties\n\nYou might notice a trend here: almost half of the items in this list relate to typography. The lack of fine-grained control over typographical detail is a general concern among designers and CSS authors. Indentation and hanging punctuation fall into this category.\n\nThe CSS3 specification introduces two new possible values for the text-indent property: each-line; and hanging. each-line would indent the first line of the block container and each line after a forced line break; hanging would invert which lines are affected by the indentation.\n\nThe proposed hanging-punctuation property would allow us to specify whether opening and closing brackets and quotes should hang outside the edge of the first and last lines. The specification is still incomplete, though, and asks for more examples and use cases.\n\nText alignment and hyphenation properties\n\nFollowing the typographic trend of this list, I\u2019d like to add better control over text alignment and hyphenation properties. The CSS3 module on Generated Content for Paged Media already specifies five new hyphenation-related properties (namely: hyphenate-dictionary; hyphenate-before and hyphenate-after; hyphenate-lines; and hyphenate-character), but it is still being developed and lacks examples.\n\nIn the text alignment realm, the new text-align-last property allows you to define how the last line of a block (or a line just before a forced break) is aligned, if your text is set to justify. Its value can be: start; end; left; right; center; and justify. The text-justify property should also allow you to have more control over text set to text-align: justify but, for now, only Internet Explorer supports this.\n\ncalc()\n\nThis is probably my favourite item in the list: the calc() function. This function is part of the CSS3 Values and Units module, but it has only been implemented by Firefox (4.0). To take advantage of it now you need to use the Mozilla vendor code, -moz-calc().\n\nImagine you have a fluid two-column layout where the sidebar column has a fixed width of 240 pixels, and the main content area fills the rest of the width available. This is how you could create that using -moz-calc():\n\n#main {\n width: -moz-calc(100% - 240px);\n}\n\nCan you imagine how many hacks and headaches we could avoid were this function available in more browsers? Transitions and animations are really nice and lovely but, for me, it\u2019s the ability to do the things that calc() allows you to that deserves the spotlight and to be pushed for implementation.\n\nSelector grouping with -moz-any()\n\nThe -moz-any() selector grouping has been introduced by Mozilla but it\u2019s not part of any CSS specification (yet?); it\u2019s currently only available on Firefox 4.\n\nThis would be especially useful with the way HTML5 outlines documents, where we can have any number of variations of several levels of headings within numerous types of containers (think sections within articles within sections\u2026).\n\nHere is a quick example (copied from the Mozilla blog post about the article) of how -moz-any() works. Instead of writing:\n\nsection section h1, section article h1, section aside h1,\nsection nav h1, article section h1, article article h1,\narticle aside h1, article nav h1, aside section h1,\naside article h1, aside aside h1, aside nav h1, nav section h1,\nnav article h1, nav aside h1, nav nav h1, {\n font-size: 24px;\n}\n\nYou could simply write:\n\n-moz-any(section, article, aside, nav)\n-moz-any(section, article, aside, nav) h1 {\n font-size: 24px;\n}\n\nNice, huh?\n\nMore control over styling form elements\n\nSome are of the opinion that form elements shouldn\u2019t be styled at all, since a user might not recognise them as such if they don\u2019t match the operating system\u2019s controls. I partially agree: I\u2019d rather put the choice in the hands of designers and expect them to be capable of deciding whether their particular design hampers or improves usability.\n\nI would say the same idea applies to font-face: while some fear designers might go crazy and litter their web pages with dozens of different fonts, most welcome the freedom to use something other than Arial or Verdana.\n\nThere will always be someone who will take this freedom too far, but it would be useful if we could, for example, style the default Opera date picker:\n\n<input type=\"date\" />\n\n\n\nor Safari\u2019s slider control (think star movie ratings, for example):\n\n<input type=\"range\" min=\"0\" max=\"5\" step=\"1\" value=\"3\" />\n\n\n\nParent selector\n\nI don\u2019t think there is one CSS author out there who has never come across a case where he or she wished there was a parent selector. There have been many suggestions as to how this could work, but a variation of the child selector is usually the most popular:\n\narticle < h1 {\n\u2026\n}\n\nOne can dream\u2026\n\nFlexible box layout\n\nThe Flexible Box Layout Module sounds a bit like magic: it introduces a new box model to CSS, allowing you to distribute and order boxes inside other boxes, and determine how the available space is shared.\n\nTwo of my favourite features of this new box model are:\n\n\n\tthe ability to redistribute boxes in a different order from the markup\n\tthe ability to create flexible layouts, where boxes shrink (or expand) to fill the available space\n\n\nLet\u2019s take a quick look at the second case. Imagine you have a three-column layout, where the first column takes up twice as much horizontal space as the other two:\n\n<body>\n <section id=\"main\">\n </section>\n <section id=\"links\">\n </section>\n <aside>\n </aside>\n</body>\n\nWith the flexible box model, you could specify it like this:\n\nbody {\n display: box;\n box-orient: horizontal;\n}\n#main {\n box-flex: 2;\n}\n#links {\n box-flex: 1;\n}\naside {\n box-flex: 1;\n}\n\nIf you decide to add a fourth column to this layout, there is no need to recalculate units or percentages, it\u2019s as easy as that.\n\nBrowser support for this property is still in its early stages (Firefox and WebKit need their vendor prefixes), but we should start to see it being gradually introduced as more attention is drawn to it (I\u2019m looking at you\u2026). You can read a more comprehensive write-up about this property on the Mozilla developer blog.\n\nIt\u2019s easy to understand why it\u2019s harder to start playing with this module than with things like animations or other more decorative properties, which don\u2019t really break your layouts when users don\u2019t see them. But it\u2019s important that we do, even if only in very experimental projects.\n\nNested selectors\n\nAnyone who has never wished they could do something like the following in CSS, cast the first stone:\n\narticle {\n h1 { font-size: 1.2em; }\n ul { margin-bottom: 1.2em; }\n}\n\nEven though it can easily turn into a specificity nightmare and promote redundancy in your style sheets (if you abuse it), it\u2019s easy to see how nested selectors could be useful. CSS compilers such as Less or Sass let you do this already, but not everyone wants or can use these compilers in their projects.\n\nEvery wish list has an item that could easily be dropped. In my case, I would say this is one that I would ditch first \u2013 it\u2019s the least useful, and also the one that could cause more maintenance problems. But it could be nice.\n\nImplementation of the ::marker pseudo-element\n\nThe CSS Lists module introduces the ::marker pseudo-element, that allows you to create custom list item markers. When an element\u2019s display property is set to list-item, this pseudo-element is created.\n\nUsing the ::marker pseudo-element you could create something like the following:\n\nFootnote 1: Both John Locke and his father, Anthony Cooper, are\nnamed after 17th- and 18th-century English philosophers; the real\nAnthony Cooper was educated as a boy by the real John Locke.\nFootnote 2: Parts of the plane were used as percussion instruments\nand can be heard in the soundtrack.\n\nwhere the footnote marker is generated by the following CSS:\n\nli::marker {\n content: \"Footnote \" counter(notes) \":\";\n text-align: left;\n width: 12em;\n}\nli {\n counter-increment: notes;\n}\n\nYou can read more about how to use counters in CSS in my article from last year.\n\nBear in mind that the CSS Lists module is still a Working Draft and is listed as \u201cLow priority\u201d. I did say this wish list would start to grow more unrealistic closer to the end\u2026\n\nVariables\n\nThe sight of the word \u2018variables\u2019 may make some web designers shy away, but when you think of them applied to things such as repeated colours in your stylesheets, it\u2019s easy to see how having variables available in CSS could be useful.\n\nThink of a website where the main brand colour is applied to elements like the main text, headings, section backgrounds, borders, and so on. In a particularly large website, where the colour is repeated countless times in the CSS and where it\u2019s important to keep the colour consistent, using variables would be ideal (some big websites are already doing this by using server-side technology).\n\nAgain, Less and Sass allow you to use variables in your CSS but, again, not everyone can (or wants to) use these.\n\nIf you are using Less, you could, for instance, set the font-family value in one variable, and simply call that variable later in the code, instead of repeating the complete font stack, like so:\n\n@fontFamily: Calibri, \"Lucida Grande\", \"Lucida Sans Unicode\", Helvetica, Arial, sans-serif;\nbody {\n font-family: @fontFamily;\n}\n\nOther features of these CSS compilers might also be useful, like the ability to \u2018call\u2019 a property value from another selector (accessors):\n\nheader {\n background: #000000;\n}\nfooter {\n background: header['background'];\n}\n\nor the ability to define functions (with arguments), saving you from writing large blocks of code when you need to write something like, for example, a CSS gradient:\n\n.gradient (@start:\"\", @end:\"\") {\n background: -webkit-gradient(linear, left top, left bottom, from(@start), to(@end));\n background: -moz-linear-gradient(-90deg,@start,@end);\n}\nbutton {\n .gradient(#D0D0D0,#9F9F9F);\n}\n\nStandardised comments\n\nEach CSS author has his or her own style for commenting their style sheets. While this isn\u2019t a massive problem on smaller projects, where maybe only one person will edit the CSS, in larger scale projects, where dozens of hands touch the code, it would be nice to start seeing a more standardised way of commenting.\n\nOne attempt at creating a standard for CSS comments is CSSDOC, an adaptation of Javadoc (a documentation generator that extracts comments from Java source code into HTML). CSSDOC uses \u2018DocBlocks\u2019, a term borrowed from the phpDocumentor Project. A DocBlock is a human- and machine-readable block of data which has the following structure:\n\n/**\n * Short description\n *\n * Long description (this can have multiple lines and contain <p> tags\n *\n * @tags (optional)\n */\n\nCSSDOC includes a standard for documenting bug fixes and hacks, colours, versioning and copyright information, amongst other important bits of data.\n\nI know this isn\u2019t a CSS feature request per se; rather, it\u2019s just me pointing you at something that is usually overlooked but that could contribute towards keeping style sheets easier to maintain and to hand over to new developers.\n\nFinal notes\n\nI understand that if even some of these were implemented in browsers now, it would be a long time until all vendors were up to speed. But if we don\u2019t talk about them and experiment with what\u2019s available, then it will definitely never happen.\n\nWhy haven\u2019t I mentioned better browser support for existing CSS3 properties? Because that would be the same as adding chocolate to your Christmas wish list \u2013 you don\u2019t need to ask, everyone knows you want it.\n\nThe list could go on. There are dozens of other things I would love to see integrated in CSS or further developed. These are my personal favourites: some might be less useful than others, but I\u2019ve wished for all of them at some point.\n\nPart of the research I did while writing this article was asking some friends what they would add to their lists; other than a couple of items I already had in mine, everything else was different. I\u2019m sure your list would be different too. So tell me, what\u2019s on your CSS wish list?", "year": "2010", "author": "Inayaili de Le\u00f3n Persson", "author_slug": "inayailideleon", "published": "2010-12-03T00:00:00+00:00", "url": "https://24ways.org/2010/my-css-wish-list/", "topic": "code"} {"rowid": 239, "title": "Using the WebFont Loader to Make Browsers Behave the Same", "contents": "Web fonts give us designers a whole new typographic palette with which to work. However, browsers handle the loading of web fonts in different ways, and this can lead to inconsistent user experiences.\n\nSafari, Chrome and Internet Explorer leave a blank space in place of the styled text while the web font is loading. Opera and Firefox show text with the default font which switches over when the web font has loaded, resulting in the so-called Flash of Unstyled Text (aka FOUT). Some people prefer Safari\u2019s approach as it eliminates FOUT, others think the Firefox way is more appropriate as content can be read whilst fonts download. Whatever your preference, the WebFont Loader can make all browsers behave the same way.\n\nThe WebFont Loader is a JavaScript library that gives you extra control over font loading. It was co-developed by Google and Typekit, and released as open source. The WebFont Loader works with most web font services as well as with self-hosted fonts.\n\nThe WebFont Loader tells you when the following events happen as a browser downloads web fonts (or loads them from cache):\n\n\n\twhen fonts start to download (\u2018loading\u2019)\n\twhen fonts finish loading (\u2018active\u2019)\n\tif fonts fail to load (\u2018inactive\u2019)\n\n\nIf your web page requires more than one font, the WebFont Loader will trigger events for individual fonts, and for all the fonts as a whole. This means you can find out when any single font has loaded, and when all the fonts have loaded (or failed to do so).\n\nThe WebFont Loader notifies you of these events in two ways: by applying special CSS classes when each event happens; and by firing JavaScript events. For our purposes, we\u2019ll be using just the CSS classes.\n\nImplementing the WebFont Loader\n\nAs stated above, the WebFont Loader works with most web font services as well as with self-hosted fonts.\n\nSelf-hosted fonts\n\nTo use the WebFont Loader when you are hosting the font files on your own server, paste the following code into your web page:\n\n<script type=\"text/javascript\">\nWebFontConfig = {\n\tcustom: { families: ['Font Family Name', 'Another Font Family'],\n\turls: [ 'http://yourwebsite.com/styles.css' ] }\n};\n(function() {\n\tvar wf = document.createElement('script');\n\twf.src = ('https:' == document.location.protocol ? 'https' : 'http') + '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';\n\twf.type = 'text/javascript';\n\twf.async = 'true';\n\tvar s = document.getElementsByTagName('script')[0];\n\ts.parentNode.insertBefore(wf, s);\n})();\n</script>\n\nReplace Font Family Name and Another Font Family with a comma-separated list of the font families you want to check against, and replace http://yourwebsite.com/styles.css with the URL of the style sheet where your @font-face rules reside.\n\nFontdeck\n\nAssuming you have added some fonts to a website project in Fontdeck, use the afore-mentioned code for self-hosted solutions and replace http://yourwebsite.com/styles.css with the URL of the <link> tag in your Fontdeck website settings page. It will look something like http://f.fontdeck.com/s/css/xxxx/domain/nnnn.css.\n\nTypekit\n\nTypekit\u2019s JavaScript-based implementation incorporates the WebFont Loader events by default, so you won\u2019t need to include any WebFont Loader code.\n\nMaking all browsers behave like Safari\n\nTo make Firefox and Opera work in the same way as WebKit browsers (Safari, Chrome, etc.) and Internet Explorer, and thus minimise FOUT, you need to hide the text while the fonts are loading.\n\nWhile fonts are loading, the WebFont Loader adds a class of wf-loading to the <html> element. Once the fonts have loaded, the wf-loading class is removed and replaced with a class of wf-active (or wf-inactive if all of the fonts failed to load). This means you can style elements on the page while the fonts are loading and then style them differently when the fonts have finished loading.\n\nSo, let\u2019s say the text you need to hide while fonts are loading is contained in all paragraphs and top-level headings. By writing the following style rule into your CSS, you can hide the text while the fonts are loading:\n\n.wf-loading h1, .wf-loading p {\n\tvisibility:hidden;\n}\n\nBecause the wf-loading class is removed once the the fonts have loaded, the visibility:hidden rule will stop being applied, and the text revealed. You can see this in action on this simple example page.\n\nThat works nicely across the board, but the situation is slightly more complicated. WebKit doesn\u2019t wait for all fonts to load before displaying text: it displays text elements as soon as the relevant font is loaded. \n\nTo emulate WebKit more accurately, we need to know when individual fonts have loaded, and apply styles accordingly. Fortunately, as mentioned earlier, the WebFont Loader has events for individual fonts too.\n\nWhen a specific font is loading, a class of the form wf-fontfamilyname-n4-loading is applied. Assuming headings and paragraphs are styled in different fonts, we can make our CSS more specific as follows:\n\n.wf-fontfamilyname-n4-loading h1, \n.wf-anotherfontfamily-n4-loading p {\n\tvisibility:hidden;\n}\n\nNote that the font family name is transformed to lower case, with all spaces removed. The n4 is a shorthand for the weight and style of the font family. In most circumstances you\u2019ll use n4 but refer to the WebFont Loader documentation for exceptions.\n\nYou can see it in action on this Safari example page (you\u2019ll probably need to disable your cache to see any change occur).\n\nMaking all browsers behave like Firefox\n\nTo make WebKit browsers and Internet Explorer work like Firefox and Opera, you need to explicitly show text while the fonts are loading. In order to make this happen, you need to specify a font family which is not a web font while the fonts load, like this:\n\n.wf-fontfamilyname-n4-loading h1 { \n font-family: 'arial narrow', sans-serif; \n}\n.wf-anotherfontfamily-n4-loading p { \n font-family: arial, sans-serif; \n}\n\nYou can see this in action on the Firefox example page (again you\u2019ll probably need to disable your cache to see any change occur).\n\nAnd there\u2019s more\n\nThat\u2019s just the start of what can be done with the WebFont Loader. More areas to explore would be tweaking font sizes to reduce the impact of reflowing text and to better cater for very narrow fonts. By using the JavaScript events much more can be achieved too, such as fading in text as the fonts load.", "year": "2010", "author": "Richard Rutter", "author_slug": "richardrutter", "published": "2010-12-02T00:00:00+00:00", "url": "https://24ways.org/2010/using-the-webfont-loader-to-make-browsers-behave-the-same/", "topic": "code"} {"rowid": 220, "title": "Finding Your Way with Static Maps", "contents": "Since the introduction of the Google Maps service in 2005, online maps have taken off in a way not really possible before the invention of slippy map interaction. Although quickly followed by a plethora of similar services from both commercial and non-commercial parties, Google\u2019s first-mover advantage, and easy-to-use developer API saw Google Maps become pretty much the de facto mapping service.\n\n\n\nIt\u2019s now so easy to add a map to a web page, there\u2019s no reason not to. Dropping an iframe map into your page is as simple as embedding a YouTube video.\n\nBut there\u2019s one crucial drawback to both the solution Google provides for you to drop into your page and the code developers typically implement themselves \u2013 they don\u2019t work without JavaScript.\n\nA bit about JavaScript\n\nBack in October of this year, The Yahoo! Developer Network blog ran some tests to measure how many visitors to the Yahoo! home page didn\u2019t have JavaScript available or enabled in their browser. It\u2019s an interesting test when you consider that the audience for the Yahoo! home page (one of the most visited pages on the web) represents about as mainstream a sample as you\u2019ll find. If there\u2019s any such thing as an \u2018average Web user\u2019 then this is them.\n\nThe results surprised me. It varied from region to region, but at most just two per cent of visitors didn\u2019t have JavaScript running. To be honest, I was expecting it to be higher, but this quote from the article caught my attention:\n\n\n\tWhile the percentage of visitors with JavaScript disabled seems like a low number, keep in mind that small percentages of big numbers are also big numbers.\n\n\nThat\u2019s right, of course, and it got me thinking about what that two per cent means. For many sites, two per cent is the number of visitors using the Opera web browser, using IE6, or using Mobile Safari. \n\nSo, although a small percentage of the total, users without JavaScript can\u2019t just be forgotten about, and catering for them is at the very heart of how the web is supposed to work.\n\nStarting with content in HTML, we layer on presentation with CSS and then enhance interactivity with JavaScript. If anything fails along the way or the network craps out, or a browser just doesn\u2019t support one of the technologies, the user still gets something they can work with. \n\nIt\u2019s progressive enhancement \u2013 also known as doing our jobs properly.\n\nSorry, wasn\u2019t this about maps?\n\nAs I was saying, the default code Google provides, and the example code it gives to developers (which typically just gets followed \u2018as is\u2019) doesn\u2019t account for users without JavaScript. No JavaScript, no content.\n\nWhen adding the ability to publish maps to our small content management system Perch, I didn\u2019t want to provide a solution that only worked with JavaScript. I had to go looking for a way to provide maps without JavaScript, too.\n\nThere\u2019s a simple solution, fortunately, in the form of static map tiles. All the various slippy map services use a JavaScript interface on top of what are basically rendered map image tiles. Dragging the map loads in more image tiles in the direction you want to view. If you\u2019ve used a slippy map on a slow connection, you\u2019ll be familiar with seeing these tiles load in one by one.\n\nThe Static Map API\n\nThe good news is that these tiles (or tiles just like them) can be used as regular images on your site. Google has a Static Map API which not only gives you a handy interface to retrieve a tile for the exact area you need, but also allows you to place pins, and zoom and centre the tile so that the image looks just so. \n\nThis means that you can create a static, non-JavaScript version of your slippy map\u2019s initial (or ideal) state to load into your page as a regular image, and then have the JavaScript map hijack the image and make it slippy.\n\nClearly, that\u2019s not going to be a perfect solution for every map\u2019s requirements. It doesn\u2019t allow for panning, zooming or interrogation without JavaScript. However, for the majority of straightforward map uses online, a static map makes a great alternative for those visitors without JavaScript.\n\n\n\nHere\u2019s the how\n\nRetrieving a static map tile is staggeringly easy \u2013 it\u2019s just a case of forming a URL with the correct arguments and then using that as the src of an image tag.\n\n<img src=\"http://maps.google.com/maps/api/staticmap\n\t?center=Bethlehem+Israel\n\t&zoom=5\n\t&size=540x280\n\t&maptype=satellite\n\t&markers=color:red|31.4211,35.1144\n\t&sensor=false\" \n\twidth=\"540\" height=\"280\" alt=\"Map of Bethlehem, Israel\" />\n\nAs you can see, there are a few key options that we pass along to the base URL. All of these should be familiar to anyone who\u2019s worked with the JavaScript API.\n\n\n\tcenter determines the point on which the map is centred. This can be latitude and longitude values, or simply an address which is then geocoded.\n\tzoom sets the zoom level.\n\tsize is the pixel dimensions of the image you require.\n\tmaptype can be roadmap, satellite, terrain or hybrid.\n\tmarkers sets one or more pin locations. Markers can be labelled, have different colours, and so on \u2013 there\u2019s quite a lot of control available.\n\tsensor states whether you are using a sensor to determine the user\u2019s location. When just embedding a map in a web page, set this to false.\n\n\nThere are many options, including plotting paths and setting the image format, which can all be found in the straightforward documentation.\n\nAdding to your page\n\nIf you\u2019ve worked with the JavaScript API, you\u2019ll know that it needs a container element which you inject the map into:\n\n<div id=\"map\"></div>\n\nAll you need to do is put your static image inside that container:\n\n<div id=\"map\">\n <img src=\"http://maps.google.com/maps/api/staticmap[...]\" />\n </div>\n\nAnd then, in your JavaScript, find the image and remove it. For example, with jQuery you\u2019d simply use:\n\n$('#map img').remove();\n\nWhy not use a <noscript> element around the image? You could, and that would certainly work fine for browsers that do not support JavaScript. What that won\u2019t cover, however, is the situation where the browser has JavaScript support but, for whatever reason, the JavaScript doesn\u2019t run. This could be due to network issues, an aggressive corporate firewall, or even just a bug in your code. So for that reason, we put the image in for all browsers that show images, and then remove it when the JavaScript is successfully running.\n\nSee an example in action\n\nAbout rate limits\n\nThe Google Static Map API limits the requests per site viewer \u2013 currently at one thousand distinct maps per day per viewer. So, for most sites you really don\u2019t need to worry about the rate limit. Requests for the same tile aren\u2019t normally counted, as the tile has already been generated and is cached. You can embed the images direct from Google and let it worry about the distribution and caching.\n\nIn conclusion\n\nAs you can see, adding a static map alongside your dynamic map for those users without JavaScript is very easy indeed. There may not be a huge percentage of web visitors browsing without JavaScript but, as we\u2019ve seen, a small percentage of a big number is still a big number. When it\u2019s so easy to add a static map, can you really justify not doing it?", "year": "2010", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2010-12-01T00:00:00+00:00", "url": "https://24ways.org/2010/finding-your-way-with-static-maps/", "topic": "code"} {"rowid": 192, "title": "Cleaner Code with CSS3 Selectors", "contents": "The parts of CSS3 that seem to grab the most column inches on blogs and in articles are the shiny bits. Rounded corners, text shadow and new ways to achieve CSS layouts are all exciting and bring with them all kinds of possibilities for web design. However what really gets me, as a developer, excited is a bit more mundane. \n\nIn this article I\u2019m going to take a look at some of the ways our front and back-end code will be simplified by CSS3, by looking at the ways we achieve certain visual effects now in comparison to how we will achieve them in a glorious, CSS3-supported future. I\u2019m also going to demonstrate how we can use these selectors now with a little help from JavaScript \u2013 which can work out very useful if you find yourself in a situation where you can\u2019t change markup that is being output by some server-side code.\n\nThe wonder of nth-child\n\nSo why does nth-child get me so excited? Here is a really common situation, the designer would like the tables in the application to look like this:\n\n\n\nSetting every other table row to a different colour is a common way to enhance readability of long rows. The tried and tested way to implement this is by adding a class to every other row. If you are writing the markup for your table by hand this is a bit of a nuisance, and if you stick a row in the middle you have to change the rows the class is applied to. If your markup is generated by your content management system then you need to get the server-side code to add that class \u2013 if you have access to that code.\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\t \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title>Striping every other row - using classes</title>\n<style type=\"text/css\">\n\tbody {\n\t\tpadding: 40px;\n\t\tmargin: 0;\n\t\tfont: 0.9em Arial, Helvetica, sans-serif;\n\t}\n\ttable {\n\t\tborder-collapse: collapse;\n\t\tborder: 1px solid #124412;\n\t\twidth: 600px;\n\t}\n\tth {\n\t\tborder: 1px solid #124412;\n\t\tbackground-color: #334f33;\n\t\tcolor: #fff;\n\t\tpadding: 0.4em;\n\t\ttext-align: left;\n\t}\n\ttd {\n\t\tpadding: 0.4em;\n\t}\n\ttr.odd td {\n\t\tbackground-color: #86B486;\n\t}\n</style>\n</head>\n<body>\n\t<table>\n\t\t<tr>\n\t\t\t<th>Name</th>\n\t\t\t<th>Cards sent</th>\n\t\t\t<th>Cards received</th>\n\t\t\t<th>Cards written but not sent</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>Ann</td>\n\t\t\t<td>40</td>\n\t\t\t<td>28</td>\n\t\t\t<td>4</td>\n\t\t</tr>\n\t\t<tr class=\"odd\">\n\t\t\t<td>Joe</td>\n\t\t\t<td>2</td>\n\t\t\t<td>27</td>\n\t\t\t<td>29</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>Paul</td>\n\t\t\t<td>5</td>\n\t\t\t<td>35</td>\n\t\t\t<td>2</td>\n\t\t</tr>\n\t\t<tr class=\"odd\">\n\t\t\t<td>Louise</td>\n\t\t\t<td>65</td>\n\t\t\t<td>65</td>\n\t\t\t<td>0</td>\n\t\t</tr>\n\t</table>\n</body>\n</html>\n\nView Example 1\n\nThis situation is something I deal with on almost every project, and apart from being an extra thing to do, it just isn\u2019t ideal having the server-side code squirt classes into the markup for purely presentational reasons. This is where the nth-child pseudo-class selector comes in. The server-side code creates a valid HTML table for the data, and the CSS then selects the odd rows with the following selector:\n\ntr:nth-child(odd) td {\n\tbackground-color: #86B486;\n}\n\nView Example 2\n\nThe odd and even keywords are very handy in this situation \u2013 however you can also use a multiplier here. 2n would be equivalent to the keyword \u2018odd\u2019 3n would select every third row and so on.\n\nBrowser support\n\nSadly, nth-child has pretty poor browser support. It is not supported in Internet Explorer 8 and has somewhat buggy support in some other browsers. Firefox 3.5 does have support. In some situations however, you might want to consider using JavaScript to add this support to browsers that don\u2019t have it. This can be very useful if you are dealing with a Content Management System where you have no ability to change the server-side code to add classes into the markup.\n\nI\u2019m going to use jQuery in these examples as it is very simple to use the same CSS selector used in the CSS to target elements with jQuery \u2013 however you could use any library or write your own function to do the same job. In the CSS I have added the original class selector to the nth-child selector:\n\ntr:nth-child(odd) td, tr.odd td {\n\tbackground-color: #86B486;\n}\n\nThen I am adding some jQuery to add a class to the markup once the document has loaded \u2013 using the very same nth-child selector that works for browsers that support it. \n\n<script src=\"http://code.jquery.com/jquery-latest.js\"></script> \n <script>\n $(document).ready(function(){\n\t$(\"tr:nth-child(odd)\").addClass(\"odd\");\n });\n </script>\n\nView Example 3\n\nWe could just add a background colour to the element using jQuery, however I prefer not to mix that information into the JavaScript as if we change the colour on our table rows I would need to remember to change it both in the CSS and in the JavaScript.\n\nDoing something different with the last element\n\nSo here\u2019s another thing that we often deal with. You have a list of items all floated left with a right hand margin on each element constrained within a fixed width layout. If each element has the right margin applied the margin on the final element will cause the set to become too wide forcing that last item down to the next row as shown in the below example where I have used a grey border to indicate the fixed width.\n\n\n\nCurrently we have two ways to deal with this. We can put a negative right margin on the list, the same width as the space between the elements. This means that the extra margin on the final element fills that space and the item doesn\u2019t drop down. \n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\t \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title>The last item is different</title>\n<style type=\"text/css\">\n\tbody {\n\t\tpadding: 40px;\n\t\tmargin: 0;\n\t\tfont: 0.9em Arial, Helvetica, sans-serif;\n\t}\n\tdiv#wrapper {\n\t\twidth: 740px;\n\t\tfloat: left;\n\t\tborder: 5px solid #ccc;\n\t}\n\tul.gallery {\n\t\tmargin: 0 -10px 0 0;\n\t\tpadding: 0;\n\t\tlist-style: none;\n\t}\n\tul.gallery li {\n\t\tfloat: left;\n\t\twidth: 240px;\n\t\tmargin: 0 10px 10px 0;\n\t}\n</style>\n</head>\n<body>\n\t<div id=\"wrapper\">\n\t\t<ul class=\"gallery\">\n\t\t\t<li><img src=\"xmas1.jpg\" alt=\"baubles\" /></li>\n\t\t\t<li><img src=\"xmas2.jpg\" alt=\"star\" /></li>\n\t\t\t<li><img src=\"xmas3.jpg\" alt=\"wreath\" /></li>\n\t\t</ul>\n\t</div>\n</body>\n</html>\n\nView Example 4\n\nThe other solution will be to put a class on the final element and in the CSS remove the margin for this class. \n\nul.gallery li.last {\n\tmargin-right: 0;\n}\n\nThis second solution may not be easy if the content is generated from server-side code that you don\u2019t have access to change.\n\nIt could all be so different. In CSS3 we have marvellously common-sense selectors such as last-child, meaning that we can simply add rules for the last list item. \n\nul.gallery li:last-child {\n\tmargin-right: 0;\n}\n\nView Example 5\n\nThis removed the margin on the li which is the last-child of the ul with a class of gallery. No messing about sticking classes on the last item, or pushing the width of the item out wit a negative margin.\n\nIf this list of items repeated ad infinitum then you could also use nth-child for this task. Creating a rule that makes every 3rd element margin-less.\n\nul.gallery li:nth-child(3n) {\n\tmargin-right: 0;\n}\n\nView Example 6\n\n\n\nA similar example is where the designer has added borders to the bottom of each element \u2013 but the last item does not have a border or is in some other way different. Again, only a class added to the last element will save you here if you cannot rely on using the last-child selector.\n\nBrowser support for last-child\n\nThe situation for last-child is similar to that of nth-child, in that there is no support in Internet Explorer 8. However, once again it is very simple to replicate the functionality using jQuery. Adding our .last class to the last list item.\n\n$(\"ul.gallery li:last-child\").addClass(\"last\");\n\nWe could also use the nth-child selector to add the .last class to every third list item.\n\n$(\"ul.gallery li:nth-child(3n)\").addClass(\"last\");\n\nView Example 7\n\nFun with forms\n\nStyling forms can be a bit of a trial, made difficult by the fact that any CSS applied to the input element will effect text fields, submit buttons, checkboxes and radio buttons. As developers we are left adding classes to our form fields to differentiate them. In most builds all of my text fields have a simple class of text whereas I wouldn\u2019t dream of adding a class of para to every paragraph element in a document.\n\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<title>Syling form fields</title>\n<style type=\"text/css\">\n\tbody {\n\t\tpadding: 40px;\n\t\tmargin: 0;\n\t\tfont: 0.9em Arial, Helvetica, sans-serif;\n\t}\n\tform div {\n\t\tclear: left;\n\t\tpadding: 0 0 0.8em 0;\n\t}\n\tform label {\n\t\tfloat: left;\n\t\twidth: 120px;\n\t}\n\tform .text, form textarea {\n\t\tborder:1px solid #333;\n\t\tpadding: 0.2em;\n\t\twidth: 400px;\n\t}\n\tform .button {\n\t\tborder: 1px solid #333;\n\t\tbackground-color: #eee;\n\t\tcolor: #000;\n\t\tpadding: 0.1em;\n\t} \n\t</style>\n</head>\n<body>\n\t<h1>Send your Christmas list to Santa</h1>\n\t<form method=\"post\" action=\"\" id=\"christmas-list\">\n\t\t<div><label for=\"fName\">Name</label>\n\t\t<input type=\"text\" name=\"fName\" id=\"fName\" class=\"text\" /></div>\n\t\t<div><label for=\"fEmail\">Email address</label>\n\t\t<input type=\"text\" name=\"fEmail\" id=\"fEmail\" class=\"text\" /></div>\n\t\t<div><label for=\"fList\">Your list</label>\n\t\t<textarea name=\"fList\" id=\"fList\" rows=\"10\" cols=\"30\"></textarea></div>\n\t\t<div><input type=\"submit\" name=\"btnSubmit\" id=\"btnSubmit\" value=\"Submit\" class=\"button\" ></div>\n\t</form>\n</body>\n</html>\n\nView Example 8\n\nAttribute selectors provide a way of targeting elements by looking at the attributes of those elements. Unlike the other examples in this article which are CSS3 selectors, the attribute selector is actually a CSS2.1 selector \u2013 it just doesn\u2019t get much use because of lack of support in Internet Explorer 6. Using attribute selectors we can write rules for text inputs and form buttons without needing to add any classes to the markup. For example after removing the text and button classes from my text and submit button input elements I can use the following rules to target them:\n\nform input[type=\"text\"] {\n border: 1px solid #333;\n padding: 0.2em;\n width: 400px;\n}\nform input[type=\"submit\"]{\n border: 1px solid #333;\n background-color: #eee;\n color: #000;\n padding: 0.1em;\n} \n\nView Example 9\n\nAnother problem that I encounter with forms is where I am using CSS to position my labels and form elements by floating the labels. This works fine as long as I want all of my labels to be floated, however sometimes we get a set of radio buttons or a checkbox, and I don\u2019t want the label field to be floated. As you can see in the below example the label for the checkbox is squashed up into the space used for the other labels, yet it makes more sense for the checkbox to display after the text.\n\n\n\nI could use a class on this label element however CSS3 lets me to target the label attribute directly by looking at the value of the for attribute.\n\nlabel[for=\"fOptIn\"] {\n float: none;\n width: auto;\n}\n\n\n\nBeing able to precisely target attributes in this way is incredibly useful, and once IE6 is no longer an issue this will really help to clean up our markup and save us from having to create all kinds of special cases when generating this markup on the server-side.\n\nBrowser support\n\nThe news for attribute selectors is actually pretty good with Internet Explorer 7+, Firefox 2+ and all other modern browsers all having support. As I have already mentioned this is a CSS2.1 selector and so we really should expect to be able to use it as we head into 2010! Internet Explorer 7 has slightly buggy support and will fail on the label example shown above however I discovered a workaround in the Sitepoint CSS reference comments. Adding the selector label[htmlFor=\"fOptIn\"] to the correct selector will create a match for IE7.\n\nIE6 does not support these selector but, once again, you can use jQuery to plug the holes in IE6 support. The following jQuery will add the text and button classes to your fields and also add a checks class to the label for the checkbox, which you can use to remove the float and width for this element.\n\n$('form input[type=\"submit\"]').addClass(\"button\");\n$('form input[type=\"text\"]').addClass(\"text\");\n$('label[for=\"fOptIn\"]').addClass(\"checks\");\n\nView Example 10\n\nThe selectors I\u2019ve used in this article are easy to overlook as we do have ways to achieve these things currently. As developers \u2013 especially when we have frameworks and existing code that cope with these situations \u2013 it is easy to carry on as we always have done. \n\nI think that the time has come to start to clean up our front and backend code and replace our reliance on classes with these more advanced selectors. With the help of a little JavaScript almost all users will still get the full effect and, where we are dealing with purely visual effects, there is definitely a case to be made for not worrying about the very small percentage of people with old browsers and no JavaScript. They will still receive a readable website, it may just be missing some of the finesse offered to the modern browsing experience.", "year": "2009", "author": "Rachel Andrew", "author_slug": "rachelandrew", "published": "2009-12-20T00:00:00+00:00", "url": "https://24ways.org/2009/cleaner-code-with-css3-selectors/", "topic": "code"} {"rowid": 184, "title": "Spruce It Up", "contents": "The landscape of web typography is changing quickly these days. We\u2019ve gone from the wild west days of sIFR to Cuf\u00f3n to finally seeing font embedding seeing wide spread adoption by browser developers (and soon web designers) with @font-face. For those who\u2019ve felt limited by the typographic possibilities before, this has been a good year.\n\nAs Mark Boulton has so eloquently elucidated, @font-face embedding doesn\u2019t come without its drawbacks. Font files can be quite large and FOUT\u2014that nasty flash of unstyled text\u2014can be a distraction for users.\n\nData URIs\n\nWe can battle FOUT by using Data URIs. A Data URI allows the font to be encoded right into the CSS file. When the font comes with the CSS, the flash of unstyled text is mitigated. No extra HTTP requests are required. \n\nDon\u2019t be a grinch, though. Sending hundreds of kilobytes down the pipe still isn\u2019t great. Sometimes, all we want to do is spruce up our site with a little typographic sugar. \n\nBe Selective\n\nDan Cederholm\u2019s SimpleBits is an attractive site. \n\n\n\nTake a look at the ampersand within the header of his site. It\u2019s the lovely (and free) Goudy Bookletter 1911 available from The League of Movable Type. The Opentype format is a respectable 28KB. Nothing too crazy but hold on here. Mr. Cederholm is only using the ampersand! Ouch. That\u2019s a lot of bandwidth just for one character.\n\nCan we optimize a font like we can an image? Yes. Image optimization essentially works by removing unnecessary image data such as colour data, hidden comments or using compression algorithms. How do you remove unnecessary information from a font? Subsetting. \n\nIf you\u2019re the adventurous type, grab a copy of FontForge, which is an open source font editing tool. You can open the font, view and edit any of the glyphs and then re-generate the font. The interface is a little clunky but you\u2019ll be able to select any character you don\u2019t want and then cut the glyphs. Re-generate your font and you\u2019ve now got a smaller file. \n\n\n\nThere are certainly more optimizations that can also be made such as removing hinting and kerning information. Keep in mind that removing this information may affect how well the type renders.\n\nAt this time of year, though, I\u2019m sure you\u2019re quite busy. Save yourself some time and head on over to the Font Squirrel Font Generator.\n\n\n\nThe Font Generator is extremely handy and allows for a number of optimizations and cross-platform options to be generated instantly. Select the font from your local system\u2014make sure that you are only using properly licensed fonts! \n\nIn this particular case, we only want the ampersand. Click on Subset Fonts which will open up a new menu. Unselect any preselected sets and enter the ampersand into the Single Characters text box. \n\nGenerate your font and what are you left with? 3KB. \n\n\n\nThe Font Generator even generates a base64 encoded data URI stylesheet to be imported easily into your project.\n\nCheck out the Demo page. (This demo won\u2019t work in Internet Explorer as we\u2019re only demonstrating the Data URI font embedding and not using the EOT file format that IE requires.) \n\nNo Unnecessary Additives\n\nIf you peeked under the hood of that demo, did you notice something interesting? There\u2019s no <span> around the ampersand. The great thing about this is that we can take advantage of the font stack\u2019s natural ability to switch to a fallback font when a character isn\u2019t available.\n\nJust like that, we\u2019ve managed to spruce up our page with a little typographic sugar without having to put on too much weight.", "year": "2009", "author": "Jonathan Snook", "author_slug": "jonathansnook", "published": "2009-12-19T00:00:00+00:00", "url": "https://24ways.org/2009/spruce-it-up/", "topic": "code"} {"rowid": 186, "title": "The Web Is Your CMS", "contents": "It is amazing what you can do these days with the services offered on the web. Flickr stores terabytes of photos for us and converts them automatically to all kind of sizes, finds people in them and even allows us to edit them online. YouTube does almost the same complete job with videos, LinkedIn allows us to maintain our CV, Delicious our bookmarks and so on.\n\nWe don\u2019t have to do these tasks ourselves any more, as all of these systems also come with ways to use the data in the form of Application Programming Interfaces, or APIs for short. APIs give us raw data when we send requests telling the system what we want to get back.\n\nThe problem is that every API has a different idea of what is a simple way of accessing this data and in which format to give it back.\n\nMaking it easier to access APIs\n\nWhat we need is a way to abstract the pains of different data formats and authentication formats away from the developer \u2014 and this is the purpose of the Yahoo Query Language, or YQL for short. \n\nLibraries like jQuery and YUI make it easy and reliable to use JavaScript in browsers (yes, even IE6) and YQL allows us to access web services and even the data embedded in web documents in a simple fashion \u2013 SQL style.\n\nSelect * from the web and filter it the way I want\n\nYQL is a web service that takes a few inputs itself:\n\n\n\tA query that tells it what to get, update or access\n\tAn output format \u2013 XML, JSON, JSON-P or JSON-P-X\n\tA callback function (if you defined JSON-P or JSON-P-X)\n\n\nYou can try it out yourself \u2013 check out this link to get back Flickr photos for the search term \u2018santa\u2019*%20from%20flickr.photos.search%20where%20text%3D%22santa%22&format=xml in XML format. The YQL query for this is \n\nselect * from flickr.photos.search where text=\"santa\"\n\nThe easiest way to take your first steps with YQL is to look at the console. There you get sample queries, access to all the data sources available to you and you can easily put together complex queries. In this article, however, let\u2019s use PHP to put together a web page that pulls in Flickr photos, blog posts, Videos from YouTube and latest bookmarks from Delicious.\n\nCheck out the demo and get the source code on GitHub.\n\n<?php\n /* YouTube RSS */\n $query = 'select description from rss(5) where url=\"http://gdata.youtube.com/feeds/base/users/chrisheilmann/uploads?alt=rss&v=2&orderby=published&client=ytapi-youtube-profile\";';\n /* Flickr search by user id */\n $query .= 'select farm,id,owner,secret,server,title from flickr.photos.search where user_id=\"11414938@N00\";';\n /* Delicious RSS */\n $query .= 'select title,link from rss where url=\"http://feeds.delicious.com/v2/rss/codepo8?count=10\";';\n /* Blog RSS */\n $query .= 'select title,link from rss where url=\"http://feeds.feedburner.com/wait-till-i/gwZf\"';\n /* The YQL web service root with JSON as the output */\n $root = 'http://query.yahooapis.com/v1/public/yql?format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys';\n /* Assemble the query */\n $query = \"select * from query.multi where queries='\".$query.\"'\";\n $url = $root . '&q=' . urlencode($query);\n /* Do the curl call (access the data just like a browser would) */\n $ch = curl_init(); \n curl_setopt($ch, CURLOPT_URL, $url); \n curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); \n curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\n curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);\n $output = curl_exec($ch); \n curl_close($ch);\n $data = json_decode($output);\n $results = $data->query->results->results;\n /* YouTube output */\n $youtube = '<ul id=\"youtube\">';\n foreach($results[0]->item as $r){\n\t$cleanHTML = undoYouTubeMarkupCrimes($r->description);\n\t$youtube .= '<li>'.$cleanHTML.'</li>';\n }\n $youtube .= '</ul>';\n /* Flickr output */\n $flickr = '<ul id=\"flickr\">';\n foreach($results[1]->photo as $r){\n\t$flickr .= '<li>'.\n\t\t\t '<a href=\"http://www.flickr.com/photos/codepo8/'.$r->id.'/\">'.\n\t\t\t '<img src=\"http://farm' .$r->farm . '.static.flickr.com/'.\n\t\t\t $r->server . '/' . $r->id . '_' . $r->secret . \n\t\t\t '_s.jpg\" alt=\"'.$r->title.'\"></a></li>';\n }\n $flickr .= '</ul>';\n /* Delicious output */\n $delicious = '<ul id=\"delicious\">';\n foreach($results[2]->item as $r){\n\t$delicious .= '<li><a href=\"'.$r->link.'\">'.$r->title.'</a></li>';\n }\n $delicious .= '</ul>';\n /* Blog output */\n $blog = '<ul id=\"blog\">';\n foreach($results[3]->item as $r){\n\t$blog .= '<li><a href=\"'.$r->link.'\">'.$r->title.'</a></li>';\n }\n $blog .= '</ul>';\n function undoYouTubeMarkupCrimes($str){\n\t$cleaner = preg_replace('/555px/','100%',$str);\n\t$cleaner = preg_replace('/width=\"[^\"]+\"/','',$cleaner);\n\t$cleaner = preg_replace('/<tbody>/','<colgroup><col width=\"20%\"><col width=\"50%\"><col width=\"30%\"></colgroup><tbody>',$cleaner);\n\treturn $cleaner;\n }\n?>\n\nWhat we are doing here is create a few different YQL statements and queue them together with the query.multi table. Each of these can be run inside YQL itself. Check out the YouTube, Flickr, Delicious and Blog example in the console if you don\u2019t believe me. The benefit of using this table is that we don\u2019t make individual requests for each query but we get all the data in one single request \u2013 which means a much better performing solution as the YQL server farm is faster on the web than our servers.\n\nWe point the query to the YQL web service end point and get the resulting data using cURL. All that we need to do then is to convert the returned data to HTML lists that can be printed out inside an HTML template.\n\nMixing, matching and using HTML as a data source\n\nThis was a simple example of what YQL can do for you. Where it gets really powerful however is by mixing and matching different APIs. YQL is also a good tool to get information from HTML documents. By using the html table you can load the content of an HTML document (which gets fixed automatically by HTMLTidy) and use XPATH to filter down results to what you need. Take the following example which takes headlines from the news.bbc.co.uk homepage and runs the results through Yahoo\u2019s Term Extractor API to give you a list of currently hot topics.\n\nselect * from search.termextract where context in (\n select content from html where url=\"http://news.bbc.co.uk\" and xpath=\"//table[@width=800]//a\"\n)\n\nTry it out in the console or see the results here. In English, this means:\n\n\n\tGo to http://news.bbc.co.uk and get me the HTML\n\tRun it through HTML Tidy to clean it up.\n\tGet me only the links inside the table with an attribute of width and the value 800\n\tGet only the content of the link and for each of the links\n\t\n\t\tTake the content and send it as context to the Yahoo Term Extractor API\n\t\n\t\n\nIf we choose JSON-P as the output format we can use the outcome directly in JavaScript (see this demo or see its source):\n\n<ul id=\"hottopics\"></ul>\n<script type=\"text/javascript\">\nfunction hottopics(o){\n var res = o.query.results.Result,\n\t all = res.length,\n\t topics = {},\n\t out = [],\n\t html = '',\n\t i=0;\n /* create hash from topics to prevent repetition */\t \n for(i=0;i<all;i++){\n\ttopics[res[i]] = res[i];\n };\n for(i in topics){\n\tout.push(i);\n };\n html = '<li>' + out.join('</li><li>') + '</li>';\n document.getElementById('hottopics').innerHTML = html;\n};\n</script>\n<script type=\"text/javascript\" src=\"http://query.yahooapis.com/v1/public/yql?q=select%20content%20from%20search.termextract%20where %20context%20in%20(select%20content%20from%20html%20where%20url%3D%22http%3A%2F%2Fnews.bbc.co.uk%22%20and%20xpath%3D%22%2F%2Ftable%5B%40width%3D800%5D%2F%2Fa%22)&format=json&callback=hottopics\"></script>\n\nUsing JSON, we can also use PHP which means the demo works for everybody \u2013 not only those with JavaScript enabled (see this demo or see its source):\n\n<ul id=\"hottopics\"><li>\n<?php\n$url = 'http://query.yahooapis.com/v1/public/yql?q=select%20content'.\n\t '%20from%20search.termextract%20where%20context%20in'.\n\t '%20(select%20content%20from%20html%20where%20url%3D%22'.\n\t 'http%3A%2F%2Fnews.bbc.co.uk%22%20and%20xpath%3D%22%2F%2F'.\n\t 'table%5B%40width%3D800%5D%2F%2Fa%22)&format=json';\n$ch = curl_init(); \ncurl_setopt($ch, CURLOPT_URL, $url); \ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); \ncurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);\ncurl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);\n$output = curl_exec($ch); \ncurl_close($ch);\n$data = json_decode($output);\n$topics = array_unique($data->query->results->Result);\necho join('</li><li>',$topics);\n?>\n</li></ul>\n\nSummary\n\nThis article could only scratch the surface of YQL. You have not only read access to the web but you can also write to web services. For example you can update Twitter, post to your WordPress blog or shorten a URL with bit.ly. Using Open Tables you can add any web service to the YQL interface and you can even run server-side JavaScript which is for example useful to return Flickr photos as HTML or get the HTML content from a document that needs POST data.\n\nThe web of data is already here, and using YQL you don\u2019t have to be a web services expert to use it and be part of it.", "year": "2009", "author": "Christian Heilmann", "author_slug": "chrisheilmann", "published": "2009-12-17T00:00:00+00:00", "url": "https://24ways.org/2009/the-web-is-your-cms/", "topic": "code"} {"rowid": 191, "title": "CSS Animations", "contents": "Friend: You should learn how to write CSS!\nMe: \u2026\nFriend: CSS; Cascading Style Sheets. If you\u2019re serious about web design, that\u2019s the next thing you should learn.\nMe: What\u2019s wrong with <font> tags?\n\nThat was 8 years ago. Thanks to the hard work of Jeffrey, Andy, Andy, Cameron, Colly, Dan and many others, learning how to decently markup a website and write lightweight stylesheets was surprisingly easy. They made it so easy even a complete idiot (OH HAI) was able to quickly master it.\n\nAnd then\u2026 nothing. For a long time, it seemed like there wasn\u2019t happening anything in the land of CSS, time stood still. Once you knew the basics, there wasn\u2019t anything new to keep up with. It looked like a great band split, but people just kept re-releasing their music in various \u201cBest Of!\u201d or \u201cRemastered!\u201d albums.\n\nFast forward a couple of years to late 2006. On the official WebKit blog Surfin\u2019 Safari, there\u2019s an article about something called CSS animations. Great new stuff to play with, but only supported by nightly builds (read: very, very beta) of WebKit. In the following months, they release other goodies, like CSS gradients, CSS reflections, CSS masks, and even more CSS animation sexiness. Whoa, looks like the band got back together, found their second youth, and went into overdrive! The problem was that if you wanted to listen to their new albums, you had to own some kind of new high-tech player no one on earth (besides some early adopters) owned.\n\nBack in the time machine. It is now late 2009, close to Christmas. Things have changed. Browsers supporting these new toys are widely available left and right. Even non-techies are using these advanced browsers to surf the web on a daily basis!\n\nEpic win? Almost, but at least this gives us enough reason to start learning how we could use all this new CSS voodoo. On Monday, Natalie Downe showed you a good tutorial on Going Nuts with CSS Transitions. Today, I\u2019m taking it one step further\u2026\n\nHowto: A basic spinner\n\nNo matter how fast internet tubes or servers are, we\u2019ll always need spinners to indicate something\u2019s happening behind the scenes. Up until now, people would go to some site, pick one of the available templates, customize their foreground and background colors, and download a beautiful GIF image.\n\nThere are some downsides to this though:\n\n\n\tIt\u2019s only _semi_-transparent: If you change your mind and pick a slightly different background color, you need to go back to the site, set all the parameters again, and replace your current image. There isn\u2019t even a way to pick an image or gradient as background.\n\tLimited number of frames, probable to keep the file-size as small as possible (don\u2019t forget this thing needs to be loaded before whatever process is finished in the background), and you don\u2019t have that 24 frames per second smoothness.\n\tThis is just too fucking easy. As a front-end code geek, there must be a \u201ccooler\u201d way to do this!\n\n\nWhat do we need to make a spinner with CSS animations? One image, and one element on our webpage we can hook on to. Yes, that\u2019s it. I created a simple transparent PNG that looks it might be a spinner, and for the element on the page, I wrote this piece of genius HTML:\n\n<p id=\"spinner\">Please wait while we do what we do best.</p>\n\nLooks semantic enough to me! Here\u2019s the basic HTML I\u2019m using to position the element in the center of the screen, and make the text inside it disappear:\n\n#spinner {\n\tposition: absolute;\n\ttop: 50%;\n\tleft: 50%;\n\tmargin: -100px 0 0 -100px;\n\theight: 200px;\n\twidth: 200px;\n\ttext-indent: 250px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n}\n\nCool, but now we don\u2019t see anything. Let\u2019s pull rabbit number one out of the hat: -webkit-mask-image (accompanied by the previously mentioned transparent PNG image):\n\n#spinner {\n\t...\n\t-webkit-mask-image: url(../img/spinner.png);\n}\n\nBy now you should be feeling like a magician already. Oh, wait, we still have a blank screen, looks like we left something in the hat (tip: not rabbit droppings):\n\n#spinner {\n\t...\n\t-webkit-mask-image: url(../img/spinner.png);\n\tbackground-color: #000;\n}\n\nNice! What we\u2019ve done right here is telling the element to clip onto the PNG. It\u2019s a lot like clipping layers in Photoshop. So, spinners, they move, right? Into the hat again, and look what we pull out this time: CSS animations!\n\n#spinner {\n\t...\n\t-webkit-mask-image: url(../img/spinner.png);\n\tbackground-color: #000;\n\t-webkit-animation-name: spinnerRotate;\n\t-webkit-animation-duration: 2s;\n\t-webkit-animation-iteration-count: infinite;\n\t-webkit-animation-timing-function: linear;\n}\n\nSome explanation:\n\n\n\t-webkit-animation-name: Name of the animation we\u2019ll be defining later.\n\t-webkit-animation-duration: The timespan of the animation.\n\t-webkit-animation-iteration-count: Repeat once, a defined number of times or infinitely?\n\t-webkit-animation-timing-function: Linear is the one you\u2019ll be using mostly. Other options are ease-in, ease-out, ease-in-out\u2026\n\n\nLet\u2019s define spinnerRotate:\n\n@-webkit-keyframes spinnerRotate {\n\tfrom {\n\t\t-webkit-transform:rotate(0deg);\n\t}\n\tto {\n\t\t-webkit-transform:rotate(360deg);\n\t}\n}\n\nEn Anglais: Rotate #spinner starting at 0 degrees, ending at 360 degrees, over a timespan of 2 seconds, at a constant speed, and keep repeating this animation forever.\n\nThat\u2019s it! See it in action on the demo page.\n\nNote: these examples only work when you\u2019re using a WebKit-based browser like Safari, Mobile Safari or Google Chrome. I\u2019m confident though that Mozilla and Opera will try their very best catching up with all this new CSS goodness soon.\n\nWhen looking at this example, you see the possibilities are endless. Another advantage is you can change the look of it entirely by only changing a couple of lines of CSS, instead of re-creating and re-downloading the image from some website smelling like web 2.0 gone bad. I made another demo that shows how great it is to be able to change background and foreground colors (even on the fly!).\n\nSo there you have it, a smoothly animated, fully transparent and completely customizable spinner. Cool? I think so. (Ladies?)\n\nBut you can do a lot more with CSS animations than just create pretty spinners. Since I was fooling around with it anyway, I decided to test how far you can push this, space is the final limit, right?\n\nConclusion\n\nCSS has never been more exciting than it is right now. I\u2019m even prepared to say CSS is \u201ccool\u201d again, both for the more experienced front-end developers as for the new designers discovering CSS every day now.\n\nBut\u2026\n\nRemember when Javascript became popular? Remember when Flash became popular? Every time we\u2019re been given new toys, some people aren\u2019t ashamed to use it in a way you can barely call constructive. I\u2019m thinking of Geocities websites, loaded with glowing blocks of text, moving images, bad color usage\u2026 In the wise words of Stan Lee: With great power there must also come great responsibility! A sprinkle of CSS animations is better than a bucket load. Apply with care.", "year": "2009", "author": "Tim Van Damme", "author_slug": "timvandamme", "published": "2009-12-15T00:00:00+00:00", "url": "https://24ways.org/2009/css-animations/", "topic": "code"} {"rowid": 180, "title": "Going Nuts with CSS Transitions", "contents": "I\u2019m going to show you how CSS 3 transforms and WebKit transitions can add zing to the way you present images on your site.\n\nLaying the foundations\n\nFirst we are going to make our images look like mini polaroids with captions. Here\u2019s the markup:\n\n<div class=\"polaroid pull-right\">\n\t<img src=\"../img/seal.jpg\" alt=\"\">\n\t<p class=\"caption\">Found this little cutie on a walk in New Zealand!</p>\n</div>\n\nYou\u2019ll notice we\u2019re using a somewhat presentational class of pull-right here. This means the logic is kept separate from the code that applies the polaroid effect. The polaroid class has no positioning, which allows it to be used generically anywhere that the effect is required. The pull classes set a float and add appropriate margins\u2014they can be used for things like blockquotes as well.\n\n.polaroid {\n\twidth: 150px;\n\tpadding: 10px 10px 20px 10px;\n\tborder: 1px solid #BFBFBF;\n\tbackground-color: white;\n\t-webkit-box-shadow: 2px 2px 3px rgba(135, 139, 144, 0.4);\n\t-moz-box-shadow: 2px 2px 3px rgba(135, 139, 144, 0.4);\n\tbox-shadow: 2px 2px 3px rgba(135, 139, 144, 0.4);\n}\n\nThe actual polaroid effect itself is simply applied using padding, a border and a background colour. We also apply a nice subtle box shadow, using a property that is supported by modern WebKit browsers and Firefox 3.5+. We include the box-shadow property last to ensure that future browsers that support the eventual CSS3 specified version natively will use that implementation over the legacy browser specific version.\n\nThe box-shadow property takes four values: three lengths and a colour. The first is the horizontal offset of the shadow\u2014positive values place the shadow on the right, while negative values place it to the left. The second is the vertical offset, positive meaning below. If both of these are set to 0, the shadow is positioned equally on all four sides. The last length value sets the blur radius\u2014the larger the number, the blurrier the shadow (therefore the darker you need to make the colour to have an effect).\n\nThe colour value can be given in any format recognised by CSS. Here, we\u2019re using rgba as explained by Drew behind the first door of this year\u2019s calendar.\n\nRotation\n\nFor browsers that understand it (currently our old favourites WebKit and FF3.5+) we can add some visual flair by rotating the image, using the transform CSS 3 property.\n\n-webkit-transform: rotate(9deg);\n-moz-transform: rotate(9deg);\ntransform: rotate(9deg);\n\nRotations can be specified in degrees, radians (rads) or grads. WebKit also supports turns unfortunately Firefox doesn\u2019t just yet.\n\nFor our example, we want any polaroid images on the left hand side to be rotated in the opposite direction, using a negative degree value:\n\n.pull-left.polaroid {\n\t-webkit-transform: rotate(-9deg);\n\t-moz-transform: rotate(-9deg);\n\ttransform: rotate(-9deg);\n}\n\nMultiple class selectors don\u2019t work in IE6 but as luck would have it, the transform property doesn\u2019t work in any current IE version either. The above code is a good example of progressive enrichment: browsers that don\u2019t support box-shadow or transform will still see the image and basic polaroid effect.\n\n\n\nAnimation\n\nWebKit is unique amongst browser rendering engines in that it allows animation to be specified in pure CSS. Although this may never actually make it in to the CSS 3 specification, it degrades nicely and more importantly is an awful lot of fun!\n\nLet\u2019s go nuts.\n\nIn the next demo, the image is contained within a link and mousing over that link causes the polaroid to animate from being angled to being straight.\n\nHere\u2019s our new markup:\n\n<a href=\"http://www.flickr.com/photos/nataliedowne/2340993237/\" class=\"polaroid\">\n\t<img src=\"../img/raft.jpg\" alt=\"\">\n\tWhite water rafting in Queenstown\n</a>\n\nAnd here are the relevant lines of CSS:\n\na.polaroid {\n\t/* ... */\n -webkit-transform: rotate(10deg);\n -webkit-transition: -webkit-transform 0.5s ease-in;\n}\na.polaroid:hover,\na.polaroid:focus,\na.polaroid:active {\n\t/* ... */\n\t-webkit-transform: rotate(0deg);\n}\n\nThe @-webkit-transition@ property is the magic wand that sets up the animation. It takes three values: the property to be animated, the duration of the animation and a \u2018timing function\u2019 (which affects the animation\u2019s acceleration, for a smoother effect).\n\n-webkit-transition only takes affect when the specified property changes. In pure CSS, this is done using dynamic pseudo-classes. You can also change the properties using JavaScript, but that\u2019s a story for another time.\n\nThrowing polaroids at a table\n\nImagine there are lots of differently sized polaroid photos scattered on a table. That\u2019s the effect we are aiming for with our next demo.\n\n\n\nAs an aside: we are using absolute positioning to arrange the images inside a flexible width container (with a minimum and maximum width specified in pixels). As some are positioned from the left and some from the right when you resize the browser they shuffle underneath each other. This is an effect used on the UX London site.\n\nThis demo uses a darker colour shadow with more transparency than before. The grey shadow in the previous example worked fine, but it was against a solid background. Since the images are now overlapping each other, the more opaque shadow looked fake.\n\n-webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);\n-moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);\nbox-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);\n\nOn hover, as well as our previous trick of animating the image rotation back to straight, we are also making the shadow darker and setting the z-index to be higher than the other images so that it appears on top.\n\nAnd Finally\u2026\n\nFinally, for a bit more fun, we\u2019re going to simulate the images coming towards you and lifting off the page. We\u2019ll achieve this by making them grow larger and by offsetting the shadow & making it longer.\n\n\n\n\nScreenshot 1 shows the default state, while 2 shows our previous hover effect. Screenshot 3 is the effect we are aiming for, illustrated by demo 4.\n\na.polaroid {\n\t/* ... */\n\tz-index: 2;\n\t-webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);\n\t-moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);\n\tbox-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);\n\t-webkit-transform: rotate(10deg);\n\t-moz-transform: rotate(10deg);\n\ttransform: rotate(10deg);\n\t-webkit-transition: all 0.5s ease-in;\n}\na.polaroid:hover,\na.polaroid:focus,\na.polaroid:active {\n\tz-index: 999;\n\tborder-color: #6A6A6A;\n\t-webkit-box-shadow: 15px 15px 20px rgba(0,0, 0, 0.4);\n\t-moz-box-shadow: 15px 15px 20px rgba(0,0, 0, 0.4);\n\tbox-shadow: 15px 15px 20px rgba(0,0, 0, 0.4);\n\t-webkit-transform: rotate(0deg) scale(1.05);\n\t-moz-transform: rotate(0deg) scale(1.05);\n\ttransform: rotate(0deg) scale(1.05);\n}\n\nYou\u2019ll notice we are now giving the transform property another transform function: scale, which takes increases the size by the specified factor. Other things you can do with transform include skewing, translating or you can go mad creating your own transforms with a matrix.\n\nThe box-shadow has both its offset and blur radius increased dramatically, and is darkened using the alpha channel of the rgba colour.\n\nAnd because we want the effects to all animate smoothly, we pass a value of all to the -webkit-transition property, ensuring that any changed property on that link will be animated.\n\nDemo 5 is the finished example, bringing everything nicely together.\n\nCSS transitions and transforms are a great example of progressive enrichment, which means improving the experience for a portion of the audience without negatively affecting other users. They are also a lot of fun to play with!\n\nFurther reading\n\n\n\t-moz-transform \u2013 the mozilla developer center has a comprehensive explanation of transform that also applies to -webkit-transform and transform.\n\tCSS: Animation Using CSS Transforms \u2013 this is a good, more indepth tutorial on animations.\n\tCSS Animation \u2013 the Safari blog explains the usage of -webkit-transform.\n\tDinky pocketbooks with transform \u2013 another use for transforms, create your own printable pocketbook.\n\tA while back, Simon wrote a little bookmarklet to spin the entire page\u2026 warning: this will spin the entire page.", "year": "2009", "author": "Natalie Downe", "author_slug": "nataliedowne", "published": "2009-12-14T00:00:00+00:00", "url": "https://24ways.org/2009/going-nuts-with-css-transitions/", "topic": "code"} {"rowid": 171, "title": "Rock Solid HTML Emails", "contents": "At some stage in your career, it\u2019s likely you\u2019ll be asked by a client to design a HTML email. Before you rush to explain that all the cool kids are using social media, keep in mind that when done correctly, email is still one of the best ways to promote you and your clients online. In fact, a recent survey showed that every dollar spent on email marketing this year generated more than $40 in return. That\u2019s more than any other marketing channel, including the cool ones.\n\nThere are a whole host of ingredients that contribute to a good email marketing campaign. Permission, relevance, timeliness and engaging content are all important. Even so, the biggest challenge for designers still remains building an email that renders well across all the popular email clients.\n\nSame same, but different\n\nBefore getting into the details, there are some uncomfortable facts that those new to HTML email should be aware of. Building an email is not like building for the web. While web browsers continue their onward march towards standards, many email clients have stubbornly stayed put. Some have even gone backwards. In 2007, Microsoft switched the Outlook rendering engine from Internet Explorer to Word. Yes, as in the word processor. Add to this the quirks of the major web-based email clients like Gmail and Hotmail, sprinkle in a little Lotus Notes and you\u2019ll soon realize how different the email game is.\n\nWhile it\u2019s not without its challenges, rest assured it can be done. In my experience the key is to focus on three things. First, you should keep it simple. The more complex your email design, the more likely is it to choke on one of the popular clients with poor standards support. Second, you need to take your coding skills back a good decade. That often means nesting tables, bringing CSS inline and following the coding guidelines I\u2019ll outline below. Finally, you need to test your designs regularly. Just because a template looks nice in Hotmail now, doesn\u2019t mean it will next week.\n\nSetting your lowest common denominator\n\nTo maintain your sanity, it\u2019s a good idea to decide exactly which email clients you plan on supporting when building a HTML email. While general research is helpful, the email clients your subscribers are using can vary significantly from list to list. If you have the time there are a number of tools that can tell you specifically which email clients your subscribers are using. Trust me, if the testing shows almost none of them are using a client like Lotus Notes, save yourself some frustration and ignore it altogether. \n\nKnowing which email clients you\u2019re targeting not only makes the building process easier, it can save you lots of time in the testing phase too. For the purpose of this article, I\u2019ll be sharing techniques that give the best results across all of the popular clients, including the notorious ones like Gmail, Lotus Notes 6 and Outlook 2007. Just remember that pixel perfection in all email clients is a pipe dream.\n\nLet\u2019s get started.\n\nUse tables for layout\n\nBecause clients like Gmail and Outlook 2007 have poor support for float, margin and padding, you\u2019ll need to use tables as the framework of your email. While nested tables are widely supported, consistent treatment of width, margin and padding within table cells is not. For the best results, keep the following in mind when coding your table structure.\n\nSet the width in each cell, not the table\n\nWhen you combine table widths, td widths, td padding and CSS padding into an email, the final result is different in almost every email client. The most reliable way to set the width of your table is to set a width for each cell, not for the table itself.\n\n<table cellspacing=\"0\" cellpadding=\"10\" border=\"0\">\n\t<tr>\n\t\t<td width=\"80\"></td>\n\t\t<td width=\"280\"></td>\n\t</tr>\n</table>\n\nNever assume that if you don\u2019t specify a cell width the email client will figure it out. It won\u2019t. Also avoid using percentage based widths. Clients like Outlook 2007 don\u2019t respect them, especially for nested tables. Stick to pixels. If you want to add padding to each cell, use either the cellpadding attribute of the table or CSS padding for each cell, but never combine the two.\n\nErr toward nesting\n\nTable nesting is far more reliable than setting left and right margins or padding for table cells. If you can achieve the same effect by table nesting, that will always give you the best result across the buggier email clients.\n\nUse a container table for body background colors\n\nMany email clients ignore background colors specified in your CSS or the <body> tag. To work around this, wrap your entire email with a 100% width table and give that a background color.\n\n<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" width=\"100%\">\n\t<tr>\n\t\t<td bgcolor=\u201d#000000\u201d>\n\t\t\tYour email code goes here.\n\t\t</td>\n\t</tr>\n</table>\n\nYou can use the same approach for background images too. Just remember that some email clients don\u2019t support them, so always provide a fallback color.\n\nAvoid unnecessary whitespace in table cells\n\nWhere possible, avoid whitespace between your <td> tags. Some email clients (ahem, Yahoo! and Hotmail) can add additional padding above or below the cell contents in some scenarios, breaking your design for no apparent reason.\n\nCSS and general font formatting\n\nWhile some email designers do their best to avoid CSS altogether and rely on the dreaded <font> tag, the truth is many CSS properties are well supported by most email clients. See this comprehensive list of CSS support across the major clients for a good idea of the safe properties and those that should be avoided. \n\nAlways move your CSS inline\n\nGmail is the culprit for this one. By stripping the CSS from the <head> and <body> of any email, we\u2019re left with no choice but to move all CSS inline. The good news is this is something you can almost completely automate. Free services like Premailer will move all CSS inline with the click of a button. I recommend leaving this step to the end of your build process so you can utilize all the benefits of CSS.\n\nAvoid shorthand for fonts and hex notation\n\nA number of email clients reject CSS shorthand for the font property. For example, never set your font styles like this.\n\np {\n\tfont:bold 1em/1.2em georgia,times,serif;\n}\n\nInstead, declare the properties individually like this.\n\np {\n\tfont-weight: bold;\n\tfont-size: 1em;\n\tline-height: 1.2em;\n\tfont-family: georgia,times,serif;\n}\n\nWhile we\u2019re on the topic of fonts, I recently tested every conceivable variation of @font-face across the major email clients. The results were dismal, so unfortunately it\u2019s web-safe fonts in email for the foreseeable future.\n\nWhen declaring the color property in your CSS, some email clients don\u2019t support shorthand hexadecimal colors like color:#f60; instead of color:#ff6600;. Stick to the longhand approach for the best results.\n\nParagraphs\n\nJust like table cell spacing, paragraph spacing can be tricky to get a consistent result across the board. I\u2019ve seen many designers revert to using double <br /> or DIVs with inline CSS margins to work around these shortfalls, but recent testing showed that paragraph support is now reliable enough to use in most cases (there was a time when Yahoo! didn\u2019t support the paragraph tag at all).\n\nThe best approach is to set the margin inline via CSS for every paragraph in your email, like so:\n\np {\n\tmargin: 0 0 1.6em 0;\n}\n\nAgain, do this via CSS in the head when building your email, then use Premailer to bring it inline for each paragraph later.\n\nIf part of your design is height-sensitive and calls for pixel perfection, I recommend avoiding paragraphs altogether and setting the text formatting inline in the table cell. You might need to use table nesting or cellpadding / CSS to get the desired result. Here\u2019s an example:\n\n<td width=\"200\" style=\"font-weight:bold; font-size:1em; line-height:1.2em; font-family:georgia,'times',serif;\">your height sensitive text</td>\n\nLinks\n\nSome email clients will overwrite your link colors with their defaults, and you can avoid this by taking two steps. First, set a default color for each link inline like so:\n\n<a href=\"http://somesite.com/\" style=\"color:#ff00ff\">this is a link</a>\n\nNext, add a redundant span inside the a tag.\n\n<a href=\"http://somesite.com/\" style=\"color:#ff00ff\"><span style=\"color:#ff00ff\">this is a link</span></a>\n\nTo some this may be overkill, but if link color is important to your design then a superfluous span is the best way to achieve consistency.\n\nImages in HTML emails\n\nThe most important thing to remember about images in email is that they won\u2019t be visible by default for many subscribers. If you start your design with that assumption, it forces you to keep things simple and ensure no important content is suppressed by image blocking.\n\nWith this in mind, here are the essentials to remember when using images in HTML email:\n\nAvoid spacer images\n\nWhile the combination of spacer images and nested tables was popular on the web ten years ago, image blocking in many email clients has ruled it out as a reliable technique today. Most clients replace images with an empty placeholder in the same dimensions, others strip the image altogether. Given image blocking is on by default in most email clients, this can lead to a poor first impression for many of your subscribers. Stick to fixed cell widths to keep your formatting in place with or without images.\n\nAlways include the dimensions of your image\n\nIf you forget to set the dimensions for each image, a number of clients will invent their own sizes when images are blocked and break your layout. Also, ensure that any images are correctly sized before adding them to your email. Some email clients will ignore the dimensions specified in code and rely on the true dimensions of your image. \n\nAvoid PNGs\n\nLotus Notes 6 and 7 don\u2019t support 8-bit or 24-bit PNG images, so stick with the GIF or JPG formats for all images, even if it means some additional file size.\n\nProvide fallback colors for background images\n\nOutlook 2007 has no support for background images (aside from this hack to get full page background images working). If you want to use a background image in your design, always provide a background color the email client can fall back on. This solves both the image blocking and Outlook 2007 problem simultaneously.\n\nDon\u2019t forget alt text\n\nLack of standards support means email clients have long destroyed the chances of a semantic and accessible HTML email. Even still, providing alt text is important from an image blocking perspective. Even with images suppressed by default, many email clients will display the provided alt text instead. Just remember that some email clients like Outlook 2007, Hotmail and Apple Mail don\u2019t support alt text at all when images are blocked.\n\nUse the display hack for Hotmail\n\nFor some inexplicable reason, Windows Live Hotmail adds a few pixels of additional padding below images. A workaround is to set the display property like so.\n\nimg {display:block;}\n\nThis removes the padding in Hotmail and still gives you the predicable result in other email clients.\n\nDon\u2019t use floats\n\nBoth Outlook 2007 and earlier versions of Notes offer no support for the float property. Instead, use the align attribute of the img tag to float images in your email.\n\n<img src=\"image.jpg\" align=\"right\">\n\nIf you\u2019re seeing strange image behavior in Yahoo! Mail, adding align=\u201ctop\u201d to your images can often solve this problem.\n\nVideo in email\n\nWith no support for JavaScript or the object tag, video in email (if you can call it that) has long been limited to animated gifs. However, some recent research I did into the HTML5 video tag in email showed some promising results.\n\nTurns out HTML5 video does work in many email clients right now, including Apple Mail, Entourage 2008, MobileMe and the iPhone. The real benefit of this approach is that if the video isn\u2019t supported, you can provide reliable fallback content such as an animated GIF or a clickable image linking to the video in the browser.\n\nOf course, the question of whether you should add video to email is another issue altogether. If you lean toward the \u201cyes\u201d side check out the technique with code samples.\n\nWhat about mobile email?\n\nThe mobile email landscape was a huge mess until recently. With the advent of the iPhone, Android and big improvements from Palm and RIM, it\u2019s becoming less important to think of mobile as a different email platform altogether.\n\nThat said, there are a few key pointers to keep in mind when coding your emails to get a decent result for your more mobile subscribers.\n\nKeep the width less than 600 pixels\n\nBecause of email client preview panes, this rule was important long before mobile email clients came of age. In truth, the iPhone and Pre have a viewport of 320 pixels, the Droid 480 pixels and the Blackberry models hover around 360 pixels. Sticking to a maximum of 600 pixels wide ensures your design should still be readable when scaled down for each device. This width also gives good results in desktop and web-based preview panes.\n\nBe aware of automatic text resizing\n\nIn what is almost always a good feature, email clients using webkit (such as the iPhone, Pre and Android) can automatically adjust font sizes to increase readability. If testing shows this feature is doing more harm than good to your design, you can always disable it with the following CSS rule:\n\n-webkit-text-size-adjust: none;\n\nDon\u2019t forget to test\n\nWhile standards support in email clients hasn\u2019t made much progress in the last few years, there has been continual change (for better or worse) in some email clients. Web-based providers like Yahoo!, Hotmail and Gmail are notorious for this. On countless occasions I\u2019ve seen a proven design suddenly stop working without explanation.\n\nFor this reason alone it\u2019s important to retest your email designs on a regular basis. I find a quick test every month or so does the trick, especially in the web-based clients. The good news is that after designing and testing a few HTML email campaigns, you will find that order will emerge from the chaos. Many of these pitfalls will become quite predictable and your inbox-friendly designs will take shape with them in mind.\n\nLooking ahead\n\nDesigning HTML email can be a tough pill for new designers and standardistas to swallow, especially given the fickle and retrospective nature of email clients today. With HTML5 just around the corner we are entering a new, uncertain phase. Will email client developers take the opportunity to repent on past mistakes and bring email clients into the present? The aim of groups such as the Email Standards Project is to make much of the above advice as redundant as the long-forgotten <blink> and <marquee> tags, however, only time will tell if this is to become a reality.\n\nAlthough not the most compliant (or fashionable) medium, the results speak for themselves \u2013 email is, and will continue to be one of the most successful and targeted marketing channels available to you. As a designer with HTML email design skills in your arsenal, you have the opportunity to not only broaden your service offering, but gain a unique appreciation of how vital standards are.\n\nNext steps\n\nReady to get started? There are a number of HTML email design galleries to provide ideas and inspiration for your own designs. \n\n\n\thttp://www.campaignmonitor.com/gallery/\n\thttp://htmlemailgallery.com/\n\thttp://inboxaward.com/\n\n\nEnjoy!", "year": "2009", "author": "David Greiner", "author_slug": "davidgreiner", "published": "2009-12-13T00:00:00+00:00", "url": "https://24ways.org/2009/rock-solid-html-emails/", "topic": "code"} {"rowid": 169, "title": "Incite A Riot", "contents": "Given its relatively limited scope, HTML can be remarkably expressive. With a bit of lateral thinking, we can mark up content such as tag clouds and progress meters, even when we don\u2019t have explicit HTML elements for those patterns.\n\nSuppose we want to mark up a short conversation:\n\n \n Alice: I think Eve is watching. \n\n Bob: This isn\u2019t a cryptography tutorial \u2026we\u2019re in the wrong example!\n \n\n\nA note in the the HTML 4.01 spec says it\u2019s okay to use a definition list:\n\n\n\tAnother application of DL, for example, is for marking up dialogues, with each DT naming a speaker, and each DD containing his or her words.\n\n\nThat would give us:\n\n<dl>\n\t<dt>Alice</dt>: <dd>I think Eve is watching.</dd>\n\t<dt>Bob</dt>: <dd>This isn't a cryptography tutorial ...we're in the wrong example!</dd>\n</dl>\n\nThis usage of a definition list is proof that writing W3C specifications and smoking crack are not mutually exclusive activities. \u201cI think Eve is watching\u201d is not a definition of \u201cAlice.\u201d If you (ab)use a definition list in this way, Norm will hunt you down.\n\nThe conversation problem was revisited in HTML5. What if dt and dd didn\u2019t always mean \u201cdefinition title\u201d and \u201cdefinition description\u201d? A new element was forged: dialog. Now the the \u201cd\u201d in dt and dd doesn\u2019t stand for \u201cdefinition\u201d, it stands for \u201cdialog\u201d (or \u201cdialogue\u201d if you can spell):\n\n<dialog>\n\t<dt>Alice</dt>: <dd>I think Eve is watching.</dd>\n\t<dt>Bob</dt>: <dd>This isn't a cryptography tutorial ...we're in the wrong example!</dd>\n</dialog>\n\nProblem solved \u2026except that dialog is no longer in the HTML5 spec. Hixie further expanded the meaning of dt and dd so that they could be used inside details (which makes sense\u2014it starts with a \u201cd\u201d) and figure (\u2026um). At the same time as the content model of details and figure were being updated, the completely-unrelated dialog element was dropped.\n\nBack to the drawing board, or in this case, the HTML 4.01 specification. The spec defines the cite element thusly:\n\n\n\tContains a citation or a reference to other sources.\n\n\nPerfect! There\u2019s even an example showing how this can applied when attributing quotes to people:\n\nAs <CITE>Harry S. Truman</CITE> said,\n<Q lang=\"en-us\">The buck stops here.</Q>\n\nFor longer quotes, the blockquote element might be more appropriate. In a conversation, where the order matters, I think an ordered list would make a good containing element for this pattern:\n\n<ol>\n\t<li><cite>Alice</cite>: <q>I think Eve is watching.</q></li>\n\t<li><cite>Bob</cite>: <q>This isn't a cryptography tutorial ...we're in the wrong example!</q></li>\n</ol>\n\nProblem solved \u2026except that the cite element has been redefined in the HTML5 spec:\n\n\n\tThe cite element represents the title of a work \u2026 A person\u2019s name is not the title of a work \u2026 and the element must therefore not be used to mark up people\u2019s names.\n\n\nHTML5 is supposed to be backwards compatible with previous versions of HTML, yet here we have a semantic pattern already defined in HTML 4.01 that is now non-conforming in HTML5. The entire justification for the change boils down to this line of reasoning:\n\n\n\tGiven that: titles of works are often italicised and\n\tgiven that: people\u2019s names are not often italicised and\n\tgiven that: most browsers italicise the contents of the cite element,\n\ttherefore: the cite element should not be used to mark up people\u2019s names.\n\n\nIn other words, the default browser styling is now dictating semantic meaning. The tail is wagging the dog.\n\nNot to worry, the HTML5 spec tells us how we can mark up names in conversations without using the cite element:\n\n\n\tIn some cases, the b element might be appropriate for names\n\n\nI believe the colloquial response to this is a combination of the letters W, T and F, followed by a question mark.\n\nThe non-normative note continues:\n\n\n\tIn other cases, if an element is really needed, the span element can be used.\n\n\nThis is not a joke. We are seriously being told to use semantically meaningless elements to mark up content that is semantically meaningful.\n\nWe don\u2019t have to take it.\n\nFirstly, any conformance checker\u2014that\u2019s the new politically correct term for \u201cvalidator\u201d\u2014cannot possibly check every instance of the cite element to see if it\u2019s really the title of a work and not the name of a person. So we can disobey the specification without fear of invalidating our documents.\n\nSecondly, Hixie has repeatedly stated that browser makers have a powerful voice in deciding what goes into the HTML5 spec; if a browser maker refuses to implement a feature, then that feature should come out of the spec because otherwise, the spec is fiction. Well, one of the design principles of HTML5 is the Priority of Constituencies:\n\n\n\tIn case of conflict, consider users over authors over implementors over specifiers over theoretical purity.\n\n\nThat places us\u2014authors\u2014above browser makers. If we resolutely refuse to implement part of the HTML5 spec, then the spec becomes fiction.\n\nJoin me in a campaign of civil disobedience against the unnecessarily restrictive, backwards-incompatible change to the cite element. Start using HTML5 but start using it sensibly. Let\u2019s ensure that bad advice remains fictitious.\n\nTantek has set up a page on the WHATWG wiki to document usage of the cite element for conversations. Please contribute to it.", "year": "2009", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2009-12-11T00:00:00+00:00", "url": "https://24ways.org/2009/incite-a-riot/", "topic": "code"} {"rowid": 188, "title": "Don't Lose Your :focus", "contents": "For many web designers, accessibility conjures up images of blind users with screenreaders, and the difficulties in making sites accessible to this particular audience. Of course, accessibility covers a wide range of situations that go beyond the extreme example of screenreader users. And while it\u2019s true that making a complex site accessible can often be a daunting prospect, there are also many small things that don\u2019t take anything more than a bit of judicious planning, are very easy to test (without having to buy expensive assistive technology), and can make all the difference to certain user groups.\n\nIn this short article we\u2019ll focus on keyboard accessibility and how careless use of CSS can potentially make your sites completely unusable.\n\nKeyboard Access\n\nUsers who for whatever reason can\u2019t use a mouse will employ a keyboard (or keyboard-like custom interface) to navigate around web pages. By default, they will use TAB and SHIFT + TAB to move from one focusable element (links, form controls and area) of a page to the next.\n\nNote: in OS X, you\u2019ll first need to turn on full keyboard access under System Preferences > Keyboard and Mouse > Keyboard Shortcuts. Safari under Windows needs to have the option Press Tab to highlight each item on a webpage in Preferences > Advanced enabled. Opera is the odd one out, as it has a variety of keyboard navigation options \u2013 the most relevant here being spatial navigation via Shift+Down, Shift+Up, Shift+Left, and Shift+Right).\n\nBut I Don\u2019t Like Your Dotted Lines\u2026\n\nTo show users where they are within a page, browsers place an outline around the element that currently has focus. The \u201cproblem\u201d with these default outlines is that some browsers (Internet Explorer and Firefox) also display them when a user clicks on a focusable element with the mouse. Particularly on sites that make extensive use of image replacement on links with \u201coff left\u201d techniques this can create very unsightly outlines that stretch from the replaced element all the way to the left edge of the browser.\n\n Outline bleeding off to the left (image-replacement example from carsonified.com)\n\nThere is a trivial workaround to prevent outlines from \u201cspilling over\u201d by adding a simple overflow:hidden, which keeps the outline in check around the clickable portion of the image-replaced element itself.\n\n Outline tamed with overflow:hidden\n\nBut for many designers, even this is not enough. As a final solution, many actively suppress outlines altogether in their stylesheets. Controversially, even Eric Meyer\u2019s popular reset.css \u2013 an otherwise excellent set of styles that levels the playing field of varying browser defaults \u2013 suppresses outlines.\n\nhtml, body, div, span, applet, object, iframe ... {\n\t...\n\toutline: 0;\n\t...\n}\n/* remember to define focus styles! */\n:focus {\n\toutline: 0;\n}\n\nYes, in his explanation (and in the CSS itself) Eric does remind designers to define relevant styles for :focus\u2026 but judging by the number of sites that seem to ignore this (and often remove the related comment from the stylesheet altogether), the message doesn\u2019t seem to have sunk in.\n\nAnyway\u2026 hurrah! No more unsightly dotted lines on our lovely design. But what about keyboard users? Although technically they can still TAB from one element to the next, they now get no default cue as to where they are within the page (one notable exception here is Opera, where the outline is displayed regardless of stylesheets)\u2026 and if they\u2019re Safari users, they won\u2019t even get an indication of a link\u2019s target in the status bar, like they would if they hovered over it with the mouse.\n\nOnly Suppress outline For Mouse Users\n\nIs there a way to allow users navigating with the keyboard to retain the standard outline behaviour they\u2019ve come to expect from their browser, while also ensuring that it doesn\u2019t show display for mouse users?\n\n Testing some convoluted style combinations\n\nAfter playing with various approaches (see Better CSS outline suppression for more details), the most elegant solution also seemed to be the simplest: don\u2019t remove the outline on :focus, do it on :active instead \u2013 after all, :active is the dynamic pseudo-class that deals explicitly with the styles that should be applied when a focusable element is clicked or otherwise activated.\n\na:active { outline: none; }\n\nThe only minor issues with this method: if a user activates a link and then uses the browser\u2019s back button, the outline becomes visible. Oh, and old versions of Internet Explorer notoriously get confused by the exact meaning of :focus, :hover and :active, so this method fails in IE6 and below. Personally, I can live with both of these.\n\nNote: at the last minute before submitting this article, I discovered a fatal flaw in my test. It appears that outline still manages to appear in the time between activating a link and the link target loading (which in hindsight is logical \u2013 after activation, the link does indeed receive focus). As my test page only used in-page links, this issue never came up before. The slightly less elegant solution is to also suppress the outline on :hover.\n\na:hover, a:active { outline: none; }\n\nIn Conclusion\n\nOf course, many web designers may argue that they know what\u2019s best, even for their keyboard-using audience. Maybe they\u2019ve removed the default outline and are instead providing some carefully designed :focus styles. If they know for sure that these custom styles are indeed a reliable alternative for their users, more power to them\u2026 but, at the risk of sounding like Jakob \u201cblue underlined links\u201d Nielsen, I\u2019d still argue that sometimes the default browser behaviours are best left alone. Complemented, yes (and if you\u2019re already defining some fancy styles for :hover, by all means feel free to also make them display on :focus)\u2026 but not suppressed.", "year": "2009", "author": "Patrick Lauke", "author_slug": "patricklauke", "published": "2009-12-09T00:00:00+00:00", "url": "https://24ways.org/2009/dont-lose-your-focus/", "topic": "code"} {"rowid": 175, "title": "Front-End Code Reusability with CSS and JavaScript", "contents": "Most web standards-based developers are more than familiar with creating their sites with semantic HTML with lots and lots of CSS. With each new page in a design, the CSS tends to grow and grow and more elements and styles are added. But CSS can be used to better effect.\n\nThe idea of object-oriented CSS isn\u2019t new. Nicole Sullivan has written a presentation on the subject and outlines two main concepts: separate structure and visual design; and separate container and content. Jeff Croft talks about Applying OOP Concepts to CSS:\n\n\n\tI can make a class of .box that defines some basic layout structure, and another class of .rounded that provides rounded corners, and classes of .wide and .narrow that define some widths, and then easily create boxes of varying widths and styles by assigning multiple classes to an element, without having to duplicate code in my CSS.\n\n\nThis concept helps reduce CSS file size, allows for great flexibility, rapid building of similar content areas and means greater consistency throughout the entire design. You can also take this concept one step further and apply it to site behaviour with JavaScript.\n\nBuild a versatile slideshow\n\nI will show you how to build multiple slideshows using jQuery, allowing varying levels of functionality which you may find on one site design. The code will be flexible enough to allow you to add previous/next links, image pagination and the ability to change the animation type. More importantly, it will allow you to apply any combination of these features.\n\nImage galleries are simply a list of images, so the obvious choice of marking the content up is to use a <ul>. Many designs, however, do not cater to non-JavaScript versions of the website, and thus don\u2019t take in to account large multiple images. You could also simply hide all the other images in the list, apart from the first image. This method can waste bandwidth because the other images might be downloaded when they are never going to be seen.\n\nTaking this second concept \u2014 only showing one image \u2014 the only code you need to start your slideshow is an <img> tag. The other images can be loaded dynamically via either a per-page JavaScript array or via AJAX.\n\nThe slideshow concept is built upon the very versatile Cycle jQuery Plugin and is structured in to another reusable jQuery plugin. Below is the HTML and JavaScript snippet needed to run every different type of slideshow I have mentioned above.\n\n<img src=\"path/to/image.jpg\" alt=\"About the image\" title=\"\" height=\"250\" width=\"400\" class=\"slideshow\">\n<script type=\"text/javascript\">\n\tjQuery().ready(function($) {\n\t\t$('img.slideshow').slideShow({\n\t\t\timages: ['1.jpg', '2.jpg', '3.jpg']\n\t\t});\n\t});\n</script>\n\nSlideshow plugin\n\nIf you\u2019re not familiar with jQuery or how to write and author your own plugin there are plenty of articles to help you out.\n\njQuery has a chainable interface and this is something your plugin must implement. This is easy to achieve, so your plugin simply returns the collection it is using:\n\nreturn this.each(\n\tfunction () {}\n};\n\nLocal Variables\n\nTo keep the JavaScript clean and avoid any conflicts, you must set up any variables which are local to the plugin and should be used on each collection item. Defining all your variables at the top under one statement makes adding more and finding which variables are used easier. For other tips, conventions and improvements check out JSLint, the \u201cJavaScript Code Quality Tool\u201d.\n\nvar $$, $div, $images, $arrows, $pager,\n\tid, selector, path, o, options,\n\theight, width,\n\tlist = [], li = 0,\n\tparts = [], pi = 0,\n\tarrows = ['Previous', 'Next'];\n\nCache jQuery Objects\n\nIt is good practice to cache any calls made to jQuery. This reduces wasted DOM calls, can improve the speed of your JavaScript code and makes code more reusable.\n\nThe following code snippet caches the current selected DOM element as a jQuery object using the variable name $$. Secondly, the plugin makes its settings available to the Metadata plugin\u2021 which is best practice within jQuery plugins.\n\nFor each slideshow the plugin generates a <div> with a class of slideshow and a unique id. This is used to wrap the slideshow images, pagination and controls.\n\nThe base path which is used for all the images in the slideshow is calculated based on the existing image which appears on the page. For example, if the path to the image on the page was /img/flowers/1.jpg the plugin would use the path /img/flowers/ to load the other images.\n\n$$ = $(this);\no = $.metadata ? $.extend({}, settings, $$.metadata()) : settings;\nid = 'slideshow-' + (i++ + 1);\n$div = $('<div />').addClass('slideshow').attr('id', id);\nselector = '#' + id + ' ';\npath = $$.attr('src').replace(/[0-9]\\.jpg/g, '');\noptions = {};\nheight = $$.height();\nwidth = $$.width();\n\nNote: the plugin uses conventions such as folder structure and numeric filenames. These conventions help with the reusable aspect of plugins and best practices.\n\nBuild the Images\n\nThe cycle plugin uses a list of images to create the slideshow. Because we chose to start with one image we must now build the list programmatically. This is a case of looping through the images which were added via the plugin options, building the appropriate HTML and appending the resulting <ul> to the DOM.\n\n$.each(o.images, function () {\n\tlist[li++] = '<li>';\n\tlist[li++] = '<img src=\"' + path + this + '\" height=\"' + height + '\" width=\"' + width + '\">';\n\tlist[li++] = '</li>';\n});\n$images = $('<ul />').addClass('cycle-images');\n$images.append(list.join('')).appendTo($div);\n\nAlthough jQuery provides the append method it is much faster to create one really long string and append it to the DOM at the end.\n\nUpdate the Options\n\nHere are some of the options we\u2019re making available by simply adding classes to the <img>. You can change the slideshow effect from the default fade to the sliding effect. By adding the class of stopped the slideshow will not auto-play and must be controlled via pagination or previous and next links.\n\n// different effect\nif ($$.is('.slide')) {\n\toptions.fx = 'scrollHorz';\n}\n// don't move by default\nif ($$.is('.stopped')) {\n\toptions.timeout = 0;\n}\n\nIf you are using the same set of images throughout a website you may wish to start on a different image on each page or section. This can be easily achieved by simply adding the appropriate starting class to the <img>.\n\n// based on the class name on the image\nif ($$.is('[class*=start-]')) {\n\toptions.startingSlide = parseInt($$.attr('class').replace(/.*start-([0-9]+).*/g, \"$1\"), 10) - 1;\n}\n\nFor example:\n\n<img src=\"/img/slideshow/3.jpg\" alt=\"About the image\" title=\"\" height=\"250\" width=\"400\" class=\"slideshow start-3\">\n\nBy default, and without JavaScript, the third image in this slideshow is shown. When the JavaScript is applied to the page the slideshow must know to start from the correct place, this is why the start class is required.\n\nYou could capture the default image name and parse it to get the position, but only the default image needs to be numeric to work with this plugin (and could easily be changed in future). Therefore, this extra specifically defined option means the plugin is more tolerant.\n\nPrevious/Next Links\n\nA common feature of slideshows is previous and next links enabling the user to manually progress the images. The Cycle plugin supports this functionality, but you must generate the markup yourself. Most people add these directly in the HTML but normally only support their behaviour when JavaScript is enabled. This goes against progressive enhancement. To keep with the best practice progress enhancement method the previous/next links should be generated with JavaScript.\n\nThe follow snippet checks whether the slideshow requires the previous/next links, via the arrows class. It restricts the Cycle plugin to the specific slideshow using the selector we created at the top of the plugin. This means multiple slideshows can run on one page without conflicting each other.\n\nThe code creates a <ul> using the arrows array we defined at the top of the plugin. It also adds a class to the slideshow container, meaning you can style different combinations of options in your CSS.\n\n// create the arrows\nif ($$.is('.arrows') && list.length > 1) {\n\toptions.next = selector + '.next';\n\toptions.prev = selector + '.previous';\n\t$arrows = $('<ul />').addClass('cycle-arrows');\n\t$.each(arrows, function (i, val) {\n\t\tparts[pi++] = '<li class=\"' + val.toLowerCase() + '\">';\n\t\tparts[pi++] = '<a href=\"#' + val.toLowerCase() + '\">';\n\t\tparts[pi++] = '<span>' + val + '</span>';\n\t\tparts[pi++] = '</a>';\n\t\tparts[pi++] = '</li>';\n\t});\n\t$arrows.append(parts.join('')).appendTo($div);\n\t$div.addClass('has-cycle-arrows');\n}\n\nThe arrow array could be placed inside the plugin settings to allow for localisation.\n\nPagination\n\nThe Cycle plugin creates its own HTML for the pagination of the slideshow. All our plugin needs to do is create the list and selector to use. This snippet creates the pagination container and appends it to our specific slideshow container. It sets the Cycle plugin pager option, restricting it to the specific slideshow using the selector we created at the top of the plugin. Like the previous/next links, a class is added to the slideshow container allowing you to style the slideshow itself differently.\n\n// create the clickable pagination\nif ($$.is('.pagination') && list.length > 1) {\n\toptions.pager = selector + '.cycle-pagination';\n\t$pager = $('<ul />').addClass('cycle-pagination');\n\t$pager.appendTo($div);\n\t$div.addClass('has-cycle-pagination');\n}\n\nNote: the Cycle plugin creates a <ul> with anchors listed directly inside without the surrounding <li>. Unfortunately this is invalid markup but the code still works.\n\nDemos\n\nWell, that describes all the ins-and-outs of the plugin, but demos make it easier to understand! Viewing the source on the demo page shows some of the combinations you can create with a simple <img>, a few classes and some thought-out JavaScript.\n\nView the demos \u2192\n\nDecide on defaults\n\nThe slideshow plugin uses the exact same settings as the Cycle plugin, but some are explicitly set within the slideshow plugin when using the classes you have set.\n\nWhen deciding on what functionality is going to be controlled via this class method, be careful to choose your defaults wisely. If all slideshows should auto-play, don\u2019t make this an option \u2014 make the option to stop the auto-play. Similarly, if every slideshow should have previous/next functionality make this the default and expose the ability to remove them with a class such as \u201cno-pagination\u201d.\n\nIn the examples presented on this article I have used a class on each <img>. You can easily change this to anything you want and simply apply the plugin based on the jQuery selector required.\n\nGrab your images\n\nIf you are using AJAX to load in your images, you can speed up development by deciding on and keeping to a folder structure and naming convention. There are two methods: basing the image path based on the current URL; or based on the src of the image. The first allows a different slideshow on each page, but in many instances a site will have a couple of sets of images and therefore the second method is probably preferred.\n\nMetadata \u2021\n\nA method which allows you to directly modify settings in certain plugins, which also uses the classes from your HTML already exists. This is a jQuery plugin called Metadata. This method allows for finer control over the plugin settings themselves. Some people, however, may dislike the syntax and prefer using normal classes, like above which when sprinkled with a bit more JavaScript allows you to control what you need to control.\n\nThe takeaway\n\nHopefully you have understood not only what goes in to a basic jQuery plugin but also learnt a new and powerful idea which you can apply to other areas of your website.\n\nThe idea can also be applied to other common interfaces such as lightboxes or mapping services such as Google Maps \u2014 for example creating markers based on a list of places, each with different pin icons based the anchor class.", "year": "2009", "author": "Trevor Morris", "author_slug": "trevormorris", "published": "2009-12-06T00:00:00+00:00", "url": "https://24ways.org/2009/front-end-code-reusability-with-css-and-javascript/", "topic": "code"}