rowid,title,contents,year,author,author_slug,published,url,topic 311,Designing Imaginative Style Guides,"(Living) style guides and (atomic) patterns libraries are “all the rage,” as my dear old Nana would’ve said. If articles and conference talks are to be believed, making and using them has become incredibly popular. I think there are plenty of ways we can improve how style guides look and make them better at communicating design information to creatives without it getting in the way of information that technical people need. Guides to libraries of patterns Most of my consulting work and a good deal of my creative projects now involve designing style guides. I’ve amassed a huge collection of brand guidelines and identity manuals as well as, more recently, guides to libraries of patterns intended to help designers and developers make digital products and websites. Two pages from one of my Purposeful style guide packs. Designs © Stuff & Nonsense. “Style guide” is an umbrella term for several types of design documentation. Sometimes we’re referring to static style or visual identity guides, other times voice and tone. We might mean front-end code guidelines or component/pattern libraries. These all offer something different but more often than not they have something in common. They look ugly enough to have been designed by someone who enjoys configuring a router. OK, that was mean, not everyone’s going to think an unimaginative style guide design is a problem. After all, as long as a style guide contains information people need, how it looks shouldn’t matter, should it? Inspiring not encyclopaedic Well here’s the thing. Not everyone needs to take the same information away from a style guide. If you’re looking for markup and styles to code a ‘media’ component, you’re probably going to be the technical type, whereas if you need to understand the balance of sizes across a typographic hierarchy, you’re more likely to be a creative. What you need from a style guide is different. Sure, some people1 need rules: “Do this (responsive pattern)” or “don’t do that (auto-playing video.)” Those people probably also want facts: “Use this (hexadecimal value)” and not that inaccessible colour combination.” Style guides need to do more than list facts and rules. They should demonstrate a design, not just document its parts. The best style guides are inspiring not encyclopaedic. I’ll explain by showing how many style guides currently present information about colour. Colours communicate I’m sure you’ll agree that alongside typography, colour’s one of the most important ingredients in a design. Colour communicates personality, creates mood and is vital to an easily understandable interactive vocabulary. So you’d think that an average style guide would describe all this in any number of imaginative ways. Well, you’d be disappointed, because the most inspiring you’ll find looks like a collection of chips from a paint chart. Lonely Planet’s Rizzo does a great job of separating its Design Elements from UI Components, and while its ‘Click to copy’ colour values are a thoughtful touch, you’ll struggle to get a feeling for Lonely Planet’s design by looking at their colour chips. Lonely Planet’s Rizzo style guide. Lonely Planet approach is a common way to display colour information and it’s one that you’ll also find at Greenpeace, Sky, The Times and on countless more style guides. Greenpeace, Sky and The Times style guides. GOV.UK—not a website known for its creative flair—varies this approach by using circles, which I find strange as circles don’t feature anywhere else in its branding or design. On the plus side though, their designers have provided some context by categorising colours by usage such as text, links, backgrounds and more. GOV.UK style guide. Google’s Material Design offers an embarrassment of colours but most helpfully it also advises how to combine its primary and accent colours into usable palettes. Google’s Material Design. While the ability to copy colour values from a reference might be all a technical person needs, designers need to understand why particular colours were chosen as well as how to use them. Inspiration not documentation Few style guides offer any explanation and even less by way of inspiring examples. Most are extremely vague when they describe colour: “Use colour as a presentation element for either decorative purposes or to convey information.” The Government of Canada’s Web Experience Toolkit states, rather obviously. “Certain colors have inherent meaning for a large majority of users, although we recognize that cultural differences are plentiful.” Salesforce tell us, without actually mentioning any of those plentiful differences. I’m also unsure what makes the Draft U.S. Web Design Standards colours a “distinctly American palette” but it will have to work extremely hard to achieve its goal of communicating “warmth and trustworthiness” now. In Canada, “bold and vibrant” colours reflect Alberta’s “diverse landscape.” Adding more colours to their palette has made Adobe “rich, dynamic, and multi-dimensional” and at Skype, colours are “bold, colourful (obviously) and confident” although their style guide doesn’t actually provide information on how to use them. The University of Oxford, on the other hand, is much more helpful by explaining how and why to use their colours: “The (dark) Oxford blue is used primarily in general page furniture such as the backgrounds on the header and footer. This makes for a strong brand presence throughout the site. Because it features so strongly in these areas, it is not recommended to use it in large areas elsewhere. However it is used more sparingly in smaller elements such as in event date icons and search/filtering bars.” OpenTable style guide. The designers at OpenTable have cleverly considered how to explain the hierarchy of their brand colours by presenting them and their supporting colours in various size chips. It’s also obvious from OpenTable’s design which colours are primary, supporting, accent or neutral without them having to say so. Art directing style guides For the style guides I design for my clients, I go beyond simply documenting their colour palette and type styles and describe visually what these mean for them and their brand. I work to find distinctive ways to present colour to better represent the brand and also to inspire designers. For example, on a recent project for SunLife, I described their palette of colours and how to use them across a series of art directed pages that reflect the lively personality of the SunLife brand. Information about HEX and RGB values, Sass variables and when to use their colours for branding, interaction and messaging is all there, but in a format that can appeal to both creative and technical people. SunLife style guide. Designs © Stuff & Nonsense. Purposeful style guides If you want to improve how you present colour information in your style guides, there’s plenty you can do. For a start, you needn’t confine colour information to the palette page in your style guide. Find imaginative ways to display colour across several pages to show it in context with other parts of your design. Here are two CSS gradient filled ‘cover’ pages from my Purposeful style sheets. Colour impacts other elements too, including typography, so make sure you include colour information on those pages, and vice-versa. Purposeful. Designs © Stuff & Nonsense. A visual hierarchy can be easier to understand than labelling colours as ‘primary,’ ‘supporting,’ or ‘accent,’ so find creative ways to present that hierarchy. You might use panels of different sizes or arrange boxes on a modular grid to fill a page with colour. Don’t limit yourself to rectangular colour chips, use circles or other shapes created using only CSS. If irregular shapes are a part of your brand, fill SVG silhouettes with CSS and then wrap text around them using CSS shapes. Purposeful. Designs © Stuff & Nonsense. Summing up In many ways I’m as frustrated with style guide design as I am with the general state of design on the web. Style guides and pattern libraries needn’t be dull in order to be functional. In fact, they’re the perfect place for you to try out new ideas and technologies. There’s nowhere better to experiment with new properties like CSS Grid than on your style guide. The best style guide designs showcase new approaches and possibilities, and don’t simply document the old ones. Be as creative with your style guide designs as you are with any public-facing part of your website. Purposeful are HTML and CSS style guides templates designed to help you develop creative style guides and pattern libraries for your business or clients. Save time while impressing your clients by using easily customisable HTML and CSS files that have been designed and coded to the highest standards. Twenty pages covering all common style guide components including colour, typography, buttons, form elements, and tables, plus popular pattern library components. Purposeful style guides will be available to buy online in January. Boring people ↩",2016,Andy Clarke,andyclarke,2016-12-13T00:00:00+00:00,https://24ways.org/2016/designing-imaginative-style-guides/,design 65,The Accessibility Mindset,"Accessibility is often characterized as additional work, hard to learn and only affecting a small number of people. Those myths have no logical foundation and often stem from outdated information or misconceptions. Indeed, it is an additional skill set to acquire, quite like learning new JavaScript frameworks, CSS layout techniques or new HTML elements. But it isn’t particularly harder to learn than those other skills. A World Health Organization (WHO) report on disabilities states that, [i]ncluding children, over a billion people (or about 15% of the world’s population) were estimated to be living with disability. Being disabled is not as unusual as one might think. Due to chronic health conditions and older people having a higher risk of disability, we are also currently paving the cowpath to an internet that we can still use in the future. Accessibility has a very close relationship with usability, and advancements in accessibility often yield improvements in the usability of a website. Websites are also more adaptable to users’ needs when they are built in an accessible fashion. Beyond the bare minimum In the time of table layouts, web developers could create code that passed validation rules but didn’t adhere to the underlying semantic HTML model. We later developed best practices, like using lists for navigation, and with HTML5 we started to wrap those lists in nav elements. Working with accessibility standards is similar. The Web Content Accessibility Guidelines (WCAG) 2.0 can inform your decision to make websites accessible and can be used to test that you met the success criteria. What it can’t do is measure how well you met them. W3C developed a long list of techniques that can be used to make your website accessible, but you might find yourself in a situation where you need to adapt those techniques to be the most usable solution for your particular problem. The checkbox below is implemented in an accessible way: The input element has an id and the label associated with the checkbox refers to the input using the for attribute. The hover area is shown with a yellow background and a black dotted border: Open video The label is clickable and the checkbox has an accessible description. Job done, right? Not really. Take a look at the space between the label and the checkbox: Open video The gutter is created using a right margin which pushes the label to the right. Users would certainly expect this space to be clickable as well. The simple solution is to wrap the label around the checkbox and the text: Open video You can also set the label to display:block; to further increase the clickable area: Open video And while we’re at it, users might expect the whole box to be clickable anyway. Let’s apply the CSS that was on a wrapping div element to the label directly: Open video The result enhances the usability of your form element tremendously for people with lower dexterity, using a voice mouse, or using touch interfaces. And we only used basic HTML and CSS techniques; no JavaScript was added and not one extra line of CSS.
Button Example The button below looks like a typical edit button: a pencil icon on a real button element. But if you are using a screen reader or a braille keyboard, the button is just read as “button” without any indication of what this button is for. Open video A screen reader announcing a button. Contains audio. The code snippet shows why the button is not properly announced: An icon font is used to display the icon and no text alternative is given. A possible solution to this problem is to use the title or aria-label attributes, which solves the alternative text use case for screen reader users: Open video A screen reader announcing a button with a title. However, screen readers are not the only way people with and without disabilities interact with websites. For example, users can reset or change font families and sizes at will. This helps many users make websites easier to read, including people with dyslexia. Your icon font might be replaced by a font that doesn’t include the glyphs that are icons. Additionally, the icon font may not load for users on slow connections, like on mobile phones inside trains, or because users decided to block external fonts altogether. The following screenshots show the mobile GitHub view with and without external fonts: The mobile GitHub view with and without external fonts. Even if the title/aria-label approach was used, the lack of visual labels is a barrier for most people under those circumstances. One way to tackle this is using the old-fashioned img element with an appropriate alt attribute, but surprisingly not every browser displays the alternative text visually when the image doesn’t load. Providing always visible text is an alternative that can work well if you have the space. It also helps users understand the meaning of the icons. This also reads just fine in screen readers: Open video A screen reader announcing the revised button. Clever usability enhancements don’t stop at a technical implementation level. Take the BBC iPlayer pages as an example: when a user navigates the “captioned videos” or “audio description” categories and clicks on one of the videos, captions or audio descriptions are automatically switched on. Small things like this enhance the usability and don’t need a lot of engineering resources. It is more about connecting the usability dots for people with disabilities. Read more about the BBC iPlayer accessibility case study. More information W3C has created several documents that make it easier to get the gist of what web accessibility is and how it can benefit everyone. You can find out “How People with Disabilities Use the Web”, there are “Tips for Getting Started” for developers, designers and content writers. And for the more seasoned developer there is a set of tutorials on web accessibility, including information on crafting accessible forms and how to use images in an accessible way. Conclusion You can only produce a web project with long-lasting accessibility if accessibility is not an afterthought. Your organization, your division, your team need to think about accessibility as something that is the foundation of your website or project. It needs to be at the same level as performance, code quality and design, and it needs the same attention. Users often don’t notice when those fundamental aspects of good website design and development are done right. But they’ll always know when they are implemented poorly. If you take all this into consideration, you can create accessibility solutions based on the available data and bring accessibility to people who didn’t know they’d need it: Open video In this video from the latest Apple keynote, the Apple TV is operated by voice input through a remote. When the user asks “What did she say?” the video jumps back fifteen seconds and captions are switched on for a brief time. All three, the remote, voice input and captions have their roots in assisting people with disabilities. Now they benefit everyone.",2015,Eric Eggert,ericeggert,2015-12-17T00:00:00+00:00,https://24ways.org/2015/the-accessibility-mindset/,code 61,Animation in Responsive Design,"Animation and responsive design can sometimes feel like they’re at odds with each other. Animation often needs space to do its thing, but RWD tells us that the amount of space we’ll have available is going to change a lot. Balancing that can lead to some tricky animation situations. Embracing the squishiness of responsive design doesn’t have to mean giving up on your creative animation ideas. There are three general techniques that can help you balance your web animation creativity with your responsive design needs. One or all of these approaches might help you sneak in something just a little extra into your next project. Focused art direction Smaller viewports mean a smaller stage for your motion to play out on, and this tends to amplify any motion in your animation. Suddenly 100 pixels is really far and multiple moving parts can start looking like they’re battling for space. An effect that looked great on big viewports can become muddled and confusing when it’s reframed in a smaller space. Making animated movements smaller will do the trick for simple motion like a basic move across the screen. But for more complex animation on smaller viewports, you’ll need to simplify and reduce the number of moving parts. The key to this is determining what the vital parts of the animation are, to zone in on the parts that are most important to its message. Then remove the less necessary bits to distill the motion’s message down to the essentials. For example, Rally Interactive’s navigation folds down into place with two triangle shapes unfolding each corner on larger viewports. If this exact motion was just scaled down for narrower spaces the two corners would overlap as they unfolded. It would look unnatural and wouldn’t make much sense. Open video The main purpose of this animation is to show an unfolding action. To simplify the animation, Rally unfolds only one side for narrower viewports, with a slightly different animation. The action is still easily interpreted as unfolding and it’s done in a way that is a better fit for the available space. The message the motion was meant to convey has been preserved while the amount of motion was simplified. Open video Si Digital does something similar. The main concept of the design is to portray the studio as a creative lab. On large viewports, this is accomplished primarily through an animated illustration that runs the full length of the site and triggers its animations based on your scroll position. The illustration is there to support the laboratory concept visually, but it doesn’t contain critical content. Open video At first, it looks like Si Digital just turned off the animation of the illustration for smaller viewports. But they’ve actually been a little cleverer than that. They’ve also reduced the complexity of the illustration itself. Both the amount of motion (reduced down to no motion) and the illustration were simplified to create a result that is much easier to glean the concept from. Open video The most interesting thing about these two examples is that they’re solved more with thoughtful art direction than complex code. Keeping the main concept of the animations at the forefront allowed each to adapt creative design solutions to viewports of varying size without losing the integrity of their design. Responsive choreography Static content gets moved around all the time in responsive design. A three-column layout might line up from left to right on wide viewports, then stack top to bottom on narrower viewports. The same approach can be used to arrange animated content for narrower views, but the animation’s choreography also needs to be adjusted for the new layout. Even with static content, just scaling it down or zooming out to fit it into the available space is rarely an ideal solution. Rearranging your animations’ choreography to change which animation starts when, or even which animations play at all, keeps your animated content readable on smaller viewports. In a recent project I had three small animations that played one after the other, left to right, on wider viewports but needed to be stacked on narrower viewports to be large enough to see. On wide viewports, all three animations could play one right after the other in sequence because all three were in the viewable area at the same time. But once these were stacked for the narrower viewport layouts, that sequence had to change. Open video What was essentially one animation on wider viewports became three separate animations when stacked on narrower viewports. The layout change meant the choreography had to change as well. Each animation starts independently when it comes into view in the stacked layout instead of playing automatically in sequence. (I’ve put the animated parts in this demo if you want to peek under the hood.) Open video I choose to use the GreenSock library, with the choreography defined in two different timelines for this particular project. But the same goals could be accomplished with other JavaScript options or even CSS keyframe animations and media queries. Even more complex responsive choreography can be pulled off with SVG. Media queries can be used to change CSS animations applied to SVG elements at specific breakpoints for starters. For even more responsive power, SVG’s viewBox property, and the positioning of the objects within it, can be adjusted at JavaScript-defined breakpoints. This lets you set rules to crop the viewable area and arrange your animating elements to fit any space. Sarah Drasner has some great examples of how to use this technique with style in this responsive infographic and this responsive interactive illustration. On the other hand, if smart scalability is what you’re after, it’s also possible to make all of an SVG’s shapes and motion scale with the SVG canvas itself. Sarah covers both these clever responsive SVG techniques in detail. Creative and complex animation can easily become responsive thanks to the power of SVG! Open video Bake performance into your design decisions It’s hard to get very far into a responsive design discussion before performance comes up. Performance goes hand in hand with responsive design and your animation decisions can have a big impact on the overall performance of your site. The translate3D “hack”, backface-visibility:hidden, and the will-change property are the heavy hitters of animation performance. But decisions made earlier in your animation design process can have a big impact on rendering performance and your performance budget too. Pick a technology that matches your needs One of the biggest advantages of the current web animation landscape is the range of tools we have available to us. We can use CSS animations and transitions to add just a dash of interface animation to our work, go all out with webGL to create a 3D experience, or anywhere in between. All within our browsers! Having this huge range of options is amazing and wonderful but it also means you need to be cognizant of what you’re using to get the job done. Loading in the full weight of a robust JavaScript animation library is going to be overkill if you’re only animating a few small elements here and there. That extra overhead will have an impact on performance. Performance budgets will not be pleased. Always match the complexity of the technology you choose to the complexity of your animation needs to avoid unnecessary performance strain. For small amounts of animation, stick to CSS solutions since it’s the most lightweight option. As your animations grow in complexity, or start to require more robust logic, move to a JavaScript solution that can accomplish what you need. Animate the most performant properties Whether you’re animating in CSS or JavaScript, you’re affecting specific properties of the animated element. Browsers can animate some properties more efficiently than others based on how many steps need to happen behind the scenes to visually update those properties. Browsers are particularly efficient at animating opacity, scale, rotation, and position (when the latter three are done with transforms). This article from Paul Irish and Paul Lewis gives the full scoop on why. Conveniently, those are also the most common properties used in motion design. There aren’t many animated effects that can’t be pulled off with this list. Stick to these properties to set your animations up for the best performance results from the start. If you find yourself needing to animate a property outside of this list, check CSS Triggers… to find out how much of an additional impact it might have. Offset animation start times Offsets (the concept of having a series of similar movements execute one slightly after the other, creating a wave-like pattern) are a long-held motion graphics trick for creating more interesting and organic looking motion. Employing this trick of the trade can also be smart for performance. Animating a large number of objects all at the same time can put a strain on the browser’s rendering abilities even in the best cases. Adding short delays to offset these animations in time, so they don’t all start at once, can improve rendering performance. Go explore the responsive animation possibilities for yourself! With smart art direction, responsive choreography, and an eye on performance you can create just about any creative web animation you can think up while still being responsive. Keep these in mind for your next project and you’ll pull off your animations with style at any viewport size!",2015,Val Head,valhead,2015-12-09T00:00:00+00:00,https://24ways.org/2015/animation-in-responsive-design/,design 205,Why Design Systems Fail,"Design systems are so hot right now, and for good reason. They promote a modular approach to building a product, and ensure organizational unity and stability via reusable code snippets and utility styles. They make prototyping a breeze, and provide a common language for both designers and developers. A design system is a culmination of several individual components, which can include any or all of the following (and more): Style guide or visual pattern library Design tooling (e.g. Sketch Library) Component library (where the components live in code) Code usage guidelines and documentation Design usage documentation Voice and tone guideline Animation language guideline Design systems are standalone (internal or external) products, and have proven to be very effective means of design-driven development. However, in order for a design system to succeed, everyone needs to get on board. I’d like to go over a few considerations to ensure design system success and what could hinder that success. Organizational Support Put simply, any product, including internal products, needs support. Something as cross-functional as a design system, which spans every vertical project team, needs support from the top and bottom levels of your organization. What I mean by that is that there needs to be top-level support from project managers up through VP’s to see the value of a design system, to provide resources for its implementation, and advocate for its use company-wide. This is especially important in companies where such systems are being put in place on top of existing, crufty codebases, because it may mean there needs to be some time and effort put in the calendar for refactoring work. Support from the bottom-up means that designers and engineers of all levels also need to support this system and feel responsibility for it. A design system is an organization’s product, and everyone should feel confident contributing to it. If your design system supports external clients as well (such as contractors), they too can become valuable teammates. A design system needs support and love to be nurtured and to grow. It also needs investment. Investment To have a successful design system, you need to make a continuous effort to invest resources into it. I like to compare this to working out. You can work out intensely for 3 months and see some gains, but once you stop working out, those will slowly fade away. If you continue to work out, even if its less often than the initial investment, you’ll see yourself maintaining your fitness level at a much higher rate than if you stopped completely. If you invest once in a design system (say, 3 months of overhauling it) but neglect to keep it up, you’ll face the same situation. You’ll see immediate impact, but that impact will fade as it gets out of sync with new designs and you’ll end up with strange, floating bits of code that nobody is using. Your engineers will stop using it as the patterns become outdated, and then you’ll find yourself in for another round of large investment (while dreading going through the process since its fallen so far out of shape). With design systems, small incremental investments over time lead to big gains overall. With this point, I also want to note that because of how they scale, design systems can really make a large impact across the platform, making it extremely important to really invest in things like accessibility and solid architecture from the start. You don’t want to scale a brittle system that’s not easy to use. Take care of your design systems, and keep working on them to ensure their effectiveness. One way to ensure this is to have a dedicated team working on this design system, managing tickets and styling updates that trickle out to the rest of your company. Responsibility With some kind of team to act as an owner of a design system, whether it be the design team, engineering team, or a new team made of both designers and engineers (the best option), your company is more likely to keep a relevant, up-to-date system that doesn’t break. This team is responsible for a few things: Helping others get set up on the system (support) Designing and building components (development) Advocating for overall UI consistency and adherence (evangelism) Creating a rollout plan and update system (product management) As you can see, these are a lot of roles, so it helps to have multiple people on this team, at least part of the time, if you can. One thing I’ve found to be effective in the past is to hold office hours for coworkers to book slots within to help them get set up and to answer any questions about using the system. Having an open Slack channel also helps for this sort of thing, as well as for bringing up bugs/issues/ideas and being an channel for announcements like new releases. Communication Once you have resources and a plan to invest in a design system, its really important that this person or team acts as a bridge between design and engineering. Continuous communication is really important here, and the way you communicate is even more important. Remember that nobody wants to be told what to do or prescribed a solution, especially developers, who are used to a lot of autonomy (usually they get to choose their own tools at work). Despite how much control the other engineers have on the process, they need to feel like they have input, and feel heard. This can be challenging, especially since ultimately, some party needs to be making a final decision on direction and execution. Because it’s a hard balance to strike, having open communication channels and being as transparent as possible as early as possible is a good start. Buy-in For all of the reasons we’ve just looked over, good communication is really important for getting buy-in from your users (the engineers and designers), as well as from product management. Building and maintaining a design system is surprisingly a lot of people-ops work. To get buy-in where you don’t have a previous concensus that this is the right direction to take, you need to make people want to use your design system. A really good way to get someone to want to use a product is to make it the path of least resistance, to show its value. Gather examples and usage wins, because showing is much more powerful than telling. If you can, have developers use your product in a low-stakes situation where it provides clear benefits. Hackathons are a great place to debut your design system. Having a hackathon internally at DigitalOcean was a perfect opportunity to: Evangelize for the design system See what people were using the component library for and what they were struggling with (excellent user testing there) Get user feedback afterward on how to improve it in future iterations Let people experience the benefits of using it themselves These kinds of moments, where people explore on their own are where you can really get people on your side and using the design system, because they can get their hands on it and draw their own conclusions (and if they don’t love it — listen to them on how to improve it so that they do). We don’t always get so lucky as to have this sort of instantaneous user feedback from our direct users. Architecture I briefly mentioned the scalable nature of design systems. This is exactly why it’s important to develop a solid architecture early on in the process. Build your design system with growth and scalability in mind. What happens if your company acquires a new product? What happens when it develops a new market segment? How can you make sure there’s room for customization and growth? A few things we’ve found helpful include: Namespacing Use namespacing to ensure that the system doesn’t collide with existing styles if applying it to an existing codebase. This means prefixing every element in the system to indicate that this class is a part of the design system. To ensure that you don’t break parts of the existing build (which may have styled base elements), you can namespace the entire system inside of a parent class. Sass makes this easy with its nested structure. This kind of namespacing wouldn’t be necessary per se on new projects, but it is definitely useful when integrating new and old styles. Semantic Versioning I’ve used Semantic Versioning on all of the design systems I’ve ever worked on. Semantic versioning uses a system of Major.Minor.Patch for any updates. You can then tag released on Github with versioned updates and ensure that someone’s app won’t break unintentionally when there is an update, if they are anchored to a specific version (which they should be). We also use this semantic versioning as a link with our design system assets at DigitalOcean (i.e. Sketch library) to keep them in sync, with the same version number corresponding to both Sketch and code. Our design system is served as a node module, but is also provided as a series of built assets using our CDN for quick prototyping and one-off projects. For these built assets, we run a deploy script that automatically creates folders for each release, as well as a latest folder if someone wanted the always-up-to-date version of the design system. So, semantic versioning for the system I’m currently building is what links our design system node module assets, sketch library assets, and statically built file assets. The reason we have so many ways of consuming our design system is to make adoption easier and to reduce friction. Friction A while ago, I posed the question of why design systems become outdated and unused, and a major conclusion I drew from the conversation was: “If it’s harder for people to use than their current system, people just won’t use it” You have to make your design system the path of least resistance, lowering cognitive overhead of development, not adding to it. This is vital. A design system is intended to make development much more efficient, enforce a consistent style across sites, and allow for the developer to not worry as much about small decisions like naming and HTML semantics. These are already sorted out for them, meaning they can focus on building product. But if your design system is complicated and over-engineered, they may find it frustrating to use and go back to what they know, even if its not the best solution. If you’re a Sass expert, and base your system on complex mixins and functions, you better hope your user (the developer) is also a Sass expert, or wants to learn. This is often not the case, however. You need to talk to your audience. With the DigitalOcean design system, we provide a few options: Option 1 Users can implement the component library into a development environment and use Sass, select just the components they want to include, and extend the system using a hook-based system. This is the most performant and extensible output. Only the components that are called upon are included, and they can be easily extended using mixins. But as noted earlier, not everyone wants to work this way (including Sass a dependency and potentially needing to set up a build system for it and learn a new syntax). There is also the user who just wants to throw a link onto their page and have it look nice, and thats where our versioned built assets come in. Option 2 With Option 2, users pull in links that are served via a CDN that contain JS, CSS, and our SVG icon library. The code is a bit bigger than the completely customized version, but often this isn’t the aim when people are using Option 2. Reducing friction for adoption should be a major goal of your design system rollout. Conclusion Having a design system is really beneficial to any product, especially as it grows. In order to have an effective system, it’s important to primarily always keep your user in mind and garner support from your entire company. Once you have support and acceptance, this system will flourish and grow. Make sure someone is responsible for it, and make sure its built with a solid foundation from the start which will be carefully maintained toward the future. Good luck, and happy holidays!",2017,Una Kravets,unakravets,2017-12-14T00:00:00+00:00,https://24ways.org/2017/why-design-systems-fail/,process 249,Fast Autocomplete Search for Your Website,"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. I’m going to build a search engine for 24 ways that’s fast enough to support autocomplete (a.k.a. typeahead) search queries and can be hosted for free. I’ll 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. Try it out here, then read on to see how I built it. First step: crawling the data The first step in building a search engine is to grab a copy of the data that you plan to make searchable. There 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’t have access to the raw data, you can imitate Google and write a crawler to extract the data that you need. I’m going to do exactly that against 24 ways: I’ll build a simple crawler using wget, a command-line tool that features a powerful “recursive” mode that’s ideal for scraping websites. We’ll start at the https://24ways.org/archives/ page, which links to an archived index for every year that 24 ways has been running. Then we’ll tell wget to recursively crawl the website, using the --recursive flag. We don’t want to fetch every single page on the site - we’re 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 We want to be polite, so let’s wait for 2 seconds between each request rather than hammering the site as fast as we can: --wait 2 The first time I ran this, I accidentally downloaded the comments pages as well. We don’t want those, so let’s exclude them from the crawl using -X ""/*/*/comments"". Finally, it’s 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. Tie all of those options together and we get this command: wget --recursive --wait 2 --no-clobber -I /2005,/2006,/2007,/2008,/2009,/2010,/2011,/2012,/2013,/2014,/2015,/2016,/2017 -X ""/*/*/comments"" https://24ways.org/archives/ If you leave this running for a few minutes, you’ll end up with a folder structure something like this: $ find 24ways.org 24ways.org 24ways.org/2013 24ways.org/2013/why-bother-with-accessibility 24ways.org/2013/why-bother-with-accessibility/index.html 24ways.org/2013/levelling-up 24ways.org/2013/levelling-up/index.html 24ways.org/2013/project-hubs 24ways.org/2013/project-hubs/index.html 24ways.org/2013/credits-and-recognition 24ways.org/2013/credits-and-recognition/index.html ... As a quick sanity check, let’s count the number of HTML pages we have retrieved: $ find 24ways.org | grep index.html | wc -l 328 There’s one last step! We got everything up to 2017, but we need to fetch the articles for 2018 (so far) as well. They aren’t linked in the /archives/ yet so we need to point our crawler at the site’s front page instead: wget --recursive --wait 2 --no-clobber -I /2018 -X ""/*/*/comments"" https://24ways.org/ Thanks to --no-clobber, this is safe to run every day in December to pick up any new content. We now have a folder on our computer containing an HTML file for every article that has ever been published on the site! Let’s use them to build ourselves a search index. Building a search index using SQLite There 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. I’m going to use something that’s less commonly used for web applications but makes for a powerful and extremely inexpensive alternative: SQLite. SQLite is the world’s most widely deployed database, even though many people have never even heard of it. That’s because it’s designed to be used as an embedded database: it’s commonly used by native mobile applications and even runs as part of the default set of apps on the Apple Watch! SQLite has one major limitation: unlike databases like MySQL and PostgreSQL, it isn’t really designed to handle large numbers of concurrent writes. For this reason, most people avoid it for building web applications. This doesn’t 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. It turns out SQLite has very powerful full-text search functionality built into the core database - the FTS5 extension. I’ve been doing a lot of work with SQLite recently, and as part of that, I’ve been building a Python utility library to make building new SQLite databases as easy as possible, called sqlite-utils. It’s designed to be used within a Jupyter notebook - an enormously productive way of interacting with Python code that’s similar to the Observable notebooks Natalie described on 24 ways yesterday. If you haven’t used Jupyter before, here’s 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’t clash with any other installed packages: $ python3 -m venv ./jupyter-venv $ ./jupyter-venv/bin/pip install jupyter # ... lots of installer output # Now lets install some extra packages we will need later $ ./jupyter-venv/bin/pip install beautifulsoup4 sqlite-utils html5lib # And start the notebook web application $ ./jupyter-venv/bin/jupyter-notebook # This will open your browser to Jupyter at http://localhost:8888/ You should now be in the Jupyter web application. Click New -> Python 3 to start a new notebook. A 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’ve published the notebook I used to build the search index on my GitHub account. ​ Here’s 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’s going on. from pathlib import Path from bs4 import BeautifulSoup as Soup base = Path(""/Users/simonw/Dropbox/Development/24ways-search"") articles = list(base.glob(""*/*/*/*.html"")) # articles is now a list of paths that look like this: # PosixPath('...24ways-search/24ways.org/2013/why-bother-with-accessibility/index.html') docs = [] for path in articles: year = str(path.relative_to(base)).split(""/"")[1] url = 'https://' + str(path.relative_to(base).parent) + '/' soup = Soup(path.open().read(), ""html5lib"") author = soup.select_one("".c-continue"")[""title""].split( ""More information about"" )[1].strip() author_slug = soup.select_one("".c-continue"")[""href""].split( ""/authors/"" )[1].split(""/"")[0] published = soup.select_one("".c-meta time"")[""datetime""] contents = soup.select_one("".e-content"").text.strip() title = soup.find(""title"").text.split("" ◆"")[0] try: topic = soup.select_one( '.c-meta a[href^=""/topics/""]' )[""href""].split(""/topics/"")[1].split(""/"")[0] except TypeError: topic = None docs.append({ ""title"": title, ""contents"": contents, ""year"": year, ""author"": author, ""author_slug"": author_slug, ""published"": published, ""url"": url, ""topic"": topic, }) After 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: [ { ""title"": ""Why Bother with Accessibility?"", ""contents"": ""Web accessibility (known in other fields as inclus..."", ""year"": ""2013"", ""author"": ""Laura Kalbag"", ""author_slug"": ""laurakalbag"", ""published"": ""2013-12-10T00:00:00+00:00"", ""url"": ""https://24ways.org/2013/why-bother-with-accessibility/"", ""topic"": ""design"" }, { ""title"": ""Levelling Up"", ""contents"": ""Hello, 24 ways. Iu2019m Ashley and I sell property ins..."", ""year"": ""2013"", ""author"": ""Ashley Baxter"", ""author_slug"": ""ashleybaxter"", ""published"": ""2013-12-06T00:00:00+00:00"", ""url"": ""https://24ways.org/2013/levelling-up/"", ""topic"": ""business"" }, ... My 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’s how to do that using this list of dictionaries. import sqlite_utils db = sqlite_utils.Database(""/tmp/24ways.db"") db[""articles""].insert_all(docs) That’s 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. (I put the database in /tmp/ for the moment - you can move it to a more sensible location later on.) You can inspect the table using the sqlite3 command-line utility (which comes with OS X) like this: $ sqlite3 /tmp/24ways.db sqlite> .headers on sqlite> .mode column sqlite> select title, author, year from articles; title author year ------------------------------ ------------ ---------- Why Bother with Accessibility? Laura Kalbag 2013 Levelling Up Ashley Baxte 2013 Project Hubs: A Home Base for Brad Frost 2013 Credits and Recognition Geri Coady 2013 Managing a Mind Christopher 2013 Run Ragged Mark Boulton 2013 Get Started With GitHub Pages Anna Debenha 2013 Coding Towards Accessibility Charlie Perr 2013 ... There’s one last step to take in our notebook. We know we want to use SQLite’s 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: db[""articles""].enable_fts([""title"", ""author"", ""contents""]) Introducing Datasette Datasette is the open-source tool I’ve been building that makes it easy to both explore SQLite databases and publish them to the internet. We’ve been exploring our new SQLite database using the sqlite3 command-line tool. Wouldn’t it be nice if we could use a more human-friendly interface for that? If you don’t 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’ll show you how to deploy Datasette to Heroku like this later in the article. If you want to install Datasette locally, you can reuse the virtual environment we created to play with Jupyter: ./jupyter-venv/bin/pip install datasette This will install Datasette in the ./jupyter-venv/bin/ folder. You can also install it system-wide using regular pip install datasette. Now you can run Datasette against the 24ways.db file we created earlier like so: ./jupyter-venv/bin/datasette /tmp/24ways.db This will start a local webserver running. Visit http://localhost:8001/ to start interacting with the Datasette web application. If 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 Publishing the database to the internet One 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’s how I deployed https://search-24ways.herokuapp.com/ (running on Heroku’s free tier) using datasette publish: $ ./jupyter-venv/bin/datasette publish heroku /tmp/24ways.db --name search-24ways -----> Python app detected -----> Installing requirements with pip -----> Running post-compile hook -----> Discovering process types Procfile declares types -> web -----> Compressing... Done: 47.1M -----> Launching... Released v8 https://search-24ways.herokuapp.com/ deployed to Heroku If you try this out, you’ll need to pick a different --name, since I’ve already taken search-24ways. You can run this command as many times as you like to deploy updated versions of the underlying database. Searching and faceting Datasette 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. ​ SQLite search supports wildcards, so if you want autocomplete-style search where you don’t need to enter full words to start getting results you can add a * to the end of your search term. Here’s a search for access* which returns articles on accessibility: http://search-24ways.herokuapp.com/24ways-ae60295/articles?_search=acces%2A A neat feature of Datasette is the ability to calculate facets against your data. Here’s a page showing search results for svg with facet counts calculated against both the year and the topic columns: http://search-24ways.herokuapp.com/24ways-ae60295/articles?_search=svg&_facet=year&_facet=topic Every 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: http://search-24ways.herokuapp.com/24ways-ae60295/articles.json?_search=acces%2A Better search using custom SQL The search results we get back from ../articles?_search=svg are OK, but the order they are returned in is not ideal - they’re 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. This exposes the underlying SQL query, which looks like this: select rowid, * from articles where rowid in ( select rowid from articles_fts where articles_fts match :search ) order by rowid limit 101 We can do better than this by constructing a custom SQL query. Here’s the query we will use instead: select snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet, articles_fts.rank, articles.title, articles.url, articles.author, articles.year from articles join articles_fts on articles.rowid = articles_fts.rowid where articles_fts match :search || ""*"" order by rank limit 10; You 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’s safe to allow users to provide arbitrary SQL select queries for Datasette to execute. There’s a lot going on here! Let’s break the SQL down line-by-line: select snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet, We’re 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’ll see why in the JavaScript later on. articles_fts.rank, articles.title, articles.url, articles.author, articles.year These 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. from articles join articles_fts on articles.rowid = articles_fts.rowid articles 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. where articles_fts match :search || ""*"" order by rank limit 10; :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. How 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’re going to use ?_shape=array to get back a plain array of objects: JSON API call to search for articles matching SVG The 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. A simple JavaScript autocomplete search interface I 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. We need a few small utility functions: first, a classic debounce function adapted from this one by David Walsh: function debounce(func, wait, immediate) { let timeout; return function() { let context = this, args = arguments; let later = () => { timeout = null; if (!immediate) func.apply(context, args); }; let callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; We’ll use this to only send fetch() requests a maximum of once every 100ms while the user is typing. Since we’re rendering data that might include HTML tags (24 ways is a site about web development after all), we need an HTML escaping function. I’m amazed that browsers still don’t bundle a default one of these: const htmlEscape = (s) => s.replace( />/g, '>' ).replace( /Autocomplete search

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

${htmlEscape(r.title)}

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

${highlight(r.snippet)}

`).join(""""); document.getElementById(""results"").innerHTML = results; }); }, 100); // debounce every 100ms There’s just one more utility function, used to help construct the HTML results: const highlight = (s) => htmlEscape(s).replace( /b4de2a49c8/g, '' ).replace( /8c94a2ed4b/g, '' ); This is what those unique strings passed to the snippet() function were for. Avoiding race conditions in autocomplete One 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: User types acces Browser sends request A - querying documents matching acces* User continues to type accessibility Browser sends request B - querying documents matching accessibility* Request B returns. It was fast, because there are fewer documents matching the full term The results interface updates with the documents from request B, matching accessibility* Request A returns results (this was the slower of the two requests) The results interface updates with the documents from request A - results matching access* This 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. Thankfully there’s an easy way to avoid this. I set up a variable in the outer scope called requestInFlight, initially set to null. Any time I start a new fetch() request, I create a new currentRequest = {} object and assign it to the outer requestInFlight as well. When 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. It’s not a lot of code, really And that’s 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’t think it matters. You’re welcome to refactor it as much you like. How good is this search implementation? I’ve been building search engines for a long time using a wide variety of technologies and I’m 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’s based on SQL makes it easy and flexible to work with. A surprisingly large number of desktop and mobile applications you use every day implement their search feature on top of SQLite. More 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’re 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. For 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.",2018,Simon Willison,simonwillison,2018-12-19T00:00:00+00:00,https://24ways.org/2018/fast-autocomplete-search-for-your-website/,code 18,Grunt for People Who Think Things Like Grunt are Weird and Hard,"Front-end developers are often told to do certain things: Work in as small chunks of CSS and JavaScript as makes sense to you, then concatenate them together for the production website. Compress your CSS and minify your JavaScript to make their file sizes as small as possible for your production website. Optimize your images to reduce their file size without affecting quality. Use Sass for CSS authoring because of all the useful abstraction it allows. That’s not a comprehensive list of course, but those are the kind of things we need to do. You might call them tasks. I bet you’ve heard of Grunt. Well, Grunt is a task runner. Grunt can do all of those things for you. Once you’ve got it set up, which isn’t particularly difficult, those things can happen automatically without you having to think about them again. But let’s 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. Let’s nip some misconceptions in the bud right away Perhaps you’ve heard of Grunt, but haven’t done anything with it. I’m sure that applies to many of you. Maybe one of the following hang-ups applies to you. I don’t need the things Grunt does You probably do, actually. Check out that list up top. Those things aren’t nice-to-haves. They are pretty vital parts of website development these days. If you already do all of them, that’s 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’t 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. Grunt runs on Node.js — I don’t know Node You don’t have to know Node. Just like you don’t have to know Ruby to use Sass. Or PHP to use WordPress. Or C++ to use Microsoft Word. I have other ways to do the things Grunt could do for me Are they all organized in one place, configured to run automatically when needed, and shared among every single person working on that project? Unlikely, I’d venture. Grunt is a command line tool — I’m just a designer I’m a designer too. I prefer native apps with graphical interfaces when I can get them. But I don’t think that’s going to happen with Grunt1. The extent to which you need to use the command line is: Navigate to your project’s directory. Type grunt and press Return. After set-up, that is, which again isn’t particularly difficult. OK. Let’s get Grunt installed Node is indeed a prerequisite for Grunt. If you don’t have Node installed, don’t worry, it’s very easy. You literally download an installer and run it. Click the big Install button on the Node website. You install Grunt on a per-project basis. Go to your project’s folder. It needs a file there named package.json at the root level. You can just create one and put it there. package.json at root The contents of that file should be this: { ""name"": ""example-project"", ""version"": ""0.1.0"", ""devDependencies"": { ""grunt"": ""~0.4.1"" } } Feel free to change the name of the project and the version, but the devDependencies thing needs to be in there just like that. This 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’re familiar with that). You could even think of it a bit like a plug-in for WordPress. Once that package.json file is in place, go to the terminal and navigate to your folder. Terminal rubes like me do it like this: Terminal rube changing directories Then run the command: npm install After you’ve run that command, a new folder called node_modules will show up in your project. Example of node_modules folder The other files you see there, README.md and LICENSE are there because I’m going to put this project on GitHub and that’s just standard fare there. The last installation step is to install the Grunt CLI (command line interface). That’s what makes the grunt command in the terminal work. Without it, typing grunt will net you a “Command Not Found”-style error. It is a separate installation for efficiency reasons. Otherwise, if you had ten projects you’d have ten copies of Grunt CLI. This is a one-liner again. Just run this command in the terminal: npm install -g grunt-cli You should close and reopen the terminal as well. That’s 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. Let’s make Grunt concatenate some files Perhaps in our project there are three separate JavaScript files: jquery.js – The library we are using. carousel.js – A jQuery plug-in we are using. global.js – Our authored JavaScript file where we configure and call the plug-in. In 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. But wait. Grunt actually doesn’t do anything all by itself. Remember Grunt is a task runner. The tasks themselves we will need to add. We actually haven’t set up Grunt to do anything yet, so let’s do that. The 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’s root folder): npm install grunt-contrib-concat --save-dev A 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’ll see a new line: ""grunt-contrib-concat"": ""~0.3.0"" Now we’re ready to use it. To use it we need to start configuring Grunt and telling it what to do. You tell Grunt what to do via a configuration file named Gruntfile.js2 Just like our package.json file, our Gruntfile.js has a very special format that must be just right. I wouldn’t worry about what every word of this means. Just check out the format: module.exports = function(grunt) { // 1. All configuration goes here grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { // 2. Configuration for concatinating files goes here. } }); // 3. Where we tell Grunt we plan to use this plug-in. grunt.loadNpmTasks('grunt-contrib-concat'); // 4. Where we tell Grunt what to do when we type ""grunt"" into the terminal. grunt.registerTask('default', ['concat']); }; Now we need to create that configuration. The documentation can be overwhelming. Let’s focus just on the very simple usage example. Remember, we have three JavaScript files we’re trying to concatenate. We’ll list file paths to them under src in an array of file paths (as quoted strings) and then we’ll list a destination file as dest. The destination file doesn’t have to exist yet. It will be created when this task runs and squishes all the files together. Both our jquery.js and carousel.js files are libraries. We most likely won’t be touching them. So, for organization, we’ll 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’s 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. concat: { dist: { src: [ 'js/libs/*.js', // All JS in the libs folder 'js/global.js' // This specific file ], dest: 'js/build/production.js', } } Note: 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. With that concat configuration in place, head over to the terminal, run the command: grunt and 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’s do more things! Let’s make Grunt minify that JavaScript We have so much prep work done now, adding new tasks for Grunt to run is relatively easy. We just need to: Find a Grunt plug-in to do what we want Learn the configuration style of that plug-in Write that configuration to work with our project The 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: npm install grunt-contrib-uglify --save-dev Then we alter our Gruntfile.js to load the plug-in: grunt.loadNpmTasks('grunt-contrib-uglify'); Then we configure it: uglify: { build: { src: 'js/build/production.js', dest: 'js/build/production.min.js' } } Let’s update that default task to also run minification: grunt.registerTask('default', ['concat', 'uglify']); Super-similar to the concatenation set-up, right? Run grunt at the terminal and you’ll get some deliciously minified JavaScript: Minified JavaScript That production.min.js file is what we would load up for use in our index.html file. Let’s make Grunt optimize our images We’ve got this down pat now. Let’s just go through the motions. The official image minification plug-in for Grunt is grunt-contrib-imagemin. Install it: npm install grunt-contrib-imagemin --save-dev Register it in the Gruntfile.js: grunt.loadNpmTasks('grunt-contrib-imagemin'); Configure it: imagemin: { dynamic: { files: [{ expand: true, cwd: 'images/', src: ['**/*.{png,jpg,gif}'], dest: 'images/build/' }] } } Make sure it runs: grunt.registerTask('default', ['concat', 'uglify', 'imagemin']); Run grunt and watch that gorgeous squishification happen: Squished images Gotta love performance increases for nearly zero effort. Let’s get a little bit smarter and automate What we’ve 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: Run these tasks automatically when they should Run only the tasks needed at the time For instance: Concatenate and minify JavaScript when JavaScript changes Optimize images when a new image is added or an existing one changes We 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. I’ll 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. We 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: watch: { scripts: { files: ['js/*.js'], tasks: ['concat', 'uglify'], options: { spawn: false, }, } } Feels pretty comfortable at this point, hey? The only weird bit there is the spawn thing. And you know what? I don’t even really know what that does. From what I understand from the documentation it is the smart default. That’s real-world development. Just leave it alone if it’s working and if it’s not, learn more. Note: Isn’t it frustrating when something that looks so easy in a tutorial doesn’t seem to work for you? If you can’t get Grunt to run after making a change, it’s very likely to be a syntax error in your Gruntfile.js. That might look like this in the terminal: Errors running Grunt Usually 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. Let’s make Grunt do our preprocessing The last thing on our list from the top of the article is using Sass — yet another task Grunt is well-suited to run for us. But wait? Isn’t 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’s not quite up-to-snuff with the main Ruby project. So, we’ll use the official grunt-contrib-sass plug-in which just assumes you have Sass installed on your machine. If you don’t, follow the command line instructions. What’s 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: sass: { dist: { options: { style: 'compressed' }, files: { 'css/build/global.css': 'css/global.scss' } } } We wouldn’t want to manually run this task. We already have the watch plug-in installed, so let’s use it! Within the watch configuration, we’ll add another subtask: css: { files: ['css/*.scss'], tasks: ['sass'], options: { spawn: false, } } That’ll do it. Now, every time we change any of our Sass files, the CSS will automaticaly be updated. Let’s take this one step further (it’s absolutely worth it) and add LiveReload. With LiveReload, you won’t 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). It’s very easy to set up, since the LiveReload ability is built into the watch plug-in. We just need to: Install the browser plug-in Add to the top of the watch configuration: . watch: { options: { livereload: true, }, scripts: { /* etc */ Restart the browser and click the LiveReload icon to activate it. Update some Sass and watch it change the page automatically. Live reloading browser Yum. Prefer a video? If you’re the type that likes to learn by watching, I’ve made a screencast to accompany this article that I’ve published over on CSS-Tricks: First Moments with Grunt Leveling up As 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. Some hardcore devops nerds might scoff at the simplistic setup we have going here. But I’d advise them to slow their roll. Even what we have done so far is tremendously valuable. And don’t forget this is all free and open source, which is amazing. You might level up by adding more useful tasks: Running your CSS through Autoprefixer (A+ Would recommend) instead of a preprocessor add-ons. Writing and running JavaScript unit tests (example: Jasmine). Build your image sprites and SVG icons automatically (example: Grunticon). Start 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. Check for code problems with HTML-Inspector, CSS Lint, or JS Hint. Have new CSS be automatically injected into the browser when it ever changes. Help you commit or push to a version control repository like GitHub. Add version numbers to your assets (cache busting). Help you deploy to a staging or production environment (example: DPLOY). You might level up by simply understanding more about Grunt itself: Read Grunt Boilerplate by Mark McDonnell. Read Grunt Tips and Tricks by Nicolas Bevacqua. Organize your Gruntfile.js by splitting it up into smaller files. Check out other people’s and projects’ Gruntfile.js. Learn more about Grunt by digging into its source and learning about its API. Let’s share I 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’re all in this thing together! 1 Maybe someday someone will make a beautiful Grunt app for your operating system of choice. But I’m 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. Perhaps a decent middleground is this Grunt DevTools Chrome add-on. 2 Gruntfile.js is often referred to as Gruntfile in documentation and examples. Don’t literally name it Gruntfile — it won’t work.",2013,Chris Coyier,chriscoyier,2013-12-11T00:00:00+00:00,https://24ways.org/2013/grunt-is-not-weird-and-hard/,code 79,Responsive Images: What We Thought We Needed,"If you were to read a web designer’s 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. Having experimented with complex and sometimes devilish hacks, consensus is forming around defining new standards that could solve this problem. Two approaches have emerged. The 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:

Accessible text

A second proposal put forward by Apple, the srcset attribute, uses a more concise syntax intended for use with the element, although it could be compatible with the element too. This would allow authors to provide a set of images, but with the decision on which to use left to the browser: Enter Scrooge Men’s courses will foreshadow certain ends, to which, if persevered in, they must lead. Ebenezer Scrooge Given the complexity of this issue, there’s a heated debate about which is the best option. Yet code belies a certain truth. That both feature verbose and opaque syntax, I’m not sure either should find its way into the browser – especially as alternative approaches have yet to be fully explored. So, as if to dampen the festive cheer, here are five reasons why I believe both proposals are largely redundant. 1. We need better formats, not more markup As 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. There 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’t widely supported. While it’s tempting to try to solve this issue by inventing new markup, the crux of it remains at the file level. Daan Jobsis’s 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. This may be a hack in lieu of a more permanent solution, but it’s 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. 2. Art direction doesn’t belong in markup A desired benefit of the 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: This 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. Art direction concerns design, not content. If we wish to maintain a separation of concerns, including presentation within our markup seems misguided. 3. The size of a display has little relation to the size of an image By using media queries, the element allows authors to choose which characteristics of the screen or viewport to query for different images to be displayed. In developing sites at Clearleft, we have noticed that the viewport is essentially arbitrary, with the size of an image’s containing element more important. For example, look at how this grid of images may adapt at different viewport widths: As 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. 4. We haven’t lived with the problem long enough A 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. The 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. Only 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. 5. Images and the web aesthetic The srcset proposal has emerged from a company that markets its phones as being able to browse the real – yet squashed down, tapped and zoomable – web. Perhaps Apple should make its own website responsive before suggesting how the rest of us should do so. Converserly, while the 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. Its design shares a vernacular to that of contemporary newspaper websites, with a columnar, image-laden and densely packed layout. Compared to more recent examples – Quartz, The Next Web and the New York Times Skimmer – 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’t as great as originally thought. Building for the future With responsive design, we’ve accepted the idea that a fully fluid layout, rather than a set of fixed layouts, is best suited to the web’s unpredictable nature. Current responsive image proposals are antithetical to this approach. We 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. While it’s 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. To 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. So here is my proposal. Instead of spending the next year worrying about responsive images, let’s embrace the constraints of the medium, and seek out new solutions that can work within them.",2012,Paul Lloyd,paulrobertlloyd,2012-12-11T00:00:00+00:00,https://24ways.org/2012/responsive-images-what-we-thought-we-needed/,code 308,How to Make a Chrome Extension to Delight (or Troll) Your Friends,"If you’re like me, you grew up drawing mustaches on celebrities. Every photograph was subject to your doodling wrath, and your brilliance was taken to a whole new level with computer programs like Microsoft Paint. The advent of digital cameras meant that no one was safe from your handiwork, especially not your friends. And when you finally got your hands on Photoshop, you spent hours maniacally giggling at your artistic genius. But today is different. You’re a serious adult with important things to do and a reputation to uphold. You keep up with modern web techniques and trends, and have little time for fun other than a random Giphy on Slack… right? Nope. If there’s one thing 2016 has taught me, it’s that we—the self-serious, world-changing tech movers and shakers of the universe—haven’t changed one bit from our younger, more delightable selves. How do I know? This year I created a Chrome extension called Tabby Cat and watched hundreds of thousands of people ditch productivity for randomly generated cats. Tabby Cat replaces your new tab page with an SVG cat featuring a silly name like “Stinky Dinosaur” or “Tiny Potato”. Over time, the cats collect goodies that vary in absurdity from fishbones to lawn flamingos to Raybans. Kids and adults alike use this extension, and analytics show the majority of use happens Monday through Friday from 9-5. The popularity of Tabby Cat has convinced me there’s still plenty of room in our big, grown-up hearts for fun. Today, we’re going to combine the formula behind Tabby Cat with your intrinsic desire to delight (or troll) your friends, and create a web app that generates your friends with random objects and environments of your choosing. You can publish it as a Chrome extension to replace your new tab, or simply host it as a website and point to it with the New Tab Redirect extension. Here’s a sneak peek at my final result featuring my partner, my cat, and I in cheerfully weird accessories. Your result will look however you want it to. Along the way, we’ll cover how to build a Chrome extension that replaces the new tab page, and explore ways to program randomness into your work to create something truly delightful. What you’ll need Adobe Illustrator (or a similar illustration program to export PNG) Some images of your friends A text editor Note: This can be as simple or as complex as you want it to be. Most of the application is pre-built so you can focus on kicking back and getting in touch with your creative side. If you want to dive in deeper, you’ll find ways to do it. Getting started Download a local copy of the boilerplate for today’s tutorial here, and open it in a text editor. Inside, you’ll find a simple web app that you can run in Chrome. Open index.html in Chrome. You should see a grey page that says “Noname”. Open template.pdf in Adobe Illustrator or a similar program that can export PNG. The file contains an artboard measuring 800px x 800px, with a dotted blue outline of a face. This is your template. Note: We’re using Google Chrome to build and preview this application because the end-result is a Chrome extension. This means that the application isn’t totally cross-browser compatible, but that’s okay. Step 1: Gather your friends The first thing to do is choose who your muses are. Since the holidays are upon us, I’d suggest finding inspiration in your family. Create your artwork For each person, find an image where their face is pointed as forward as possible. Place the image onto the Artwork layer of the Illustrator file, and line up their face with the template. Then, rename the artboard something descriptive like face_bob. Here’s my crew: As you can see, my use of the word “family” extends to cats. There’s no judgement here. Notice that some of my photos don’t completely fill the artboard–that’s fine. The images will be clipped into ovals when they’re rendered in the application. Now, export your images by following these steps: Turn the Template layer off and export the images as PNGs. In the Export dialog, tick the “Use Artboards” checkbox and enter the range with your faces. Export at 72ppi to keep things running fast. Save your images into the images/ folder in your project. Add your images to config.js Open scripts/config.js. This is where you configure your extension. Add key value pairs to the faces object. The key should be the person’s name, and the value should be the filepath to the image. faces: { leslie: 'images/face_leslie.png', kyle: 'images/face_kyle.png', beep: 'images/face_beep.png' } The application will choose one of these options at random each time you open a new tab. This pattern is used for everything in the config file. You give the application groups of choices, and it chooses one at random each time it loads. The only thing that’s special about the faces object is that person’s name will also be displayed when their face is chosen. Now, when you refresh the project in Chrome, you should see one of your friends along with their name, like this: Congrats, you’re off and running! Step 2: Add adjectives Now that you’ve loaded your friends into the application, it’s time to call them names. This step definitely yields the most laughs for the least amount of effort. Add a list of adjectives into the prefixes array in config.js. To get the words flowing, I took inspiration from ways I might describe some of my relatives during a holiday gathering… prefixes: [ 'Loving', 'Drunk', 'Chatty', 'Merry', 'Creepy', 'Introspective', 'Cheerful', 'Awkward', 'Unrelatable', 'Hungry', ... ] When you refresh Chrome, you should see one of these words prefixed before your friend’s name. Voila! Step 3: Choose your color palette Real talk: I’m bad at choosing color palettes, so I have a trick up my sleeve that I want to share with you. If you’ve been blessed with the gift of color aptitude, skip ahead. How to choose colors To create a color palette, I start by going to a Coolors.co, and I hit the spacebar until I find a palette that I like. We need a wide gamut of hues for our palette, so lock down colors you like and keep hitting the spacebar until you find a nice, full range. You can use as many or as few colors as you like. Copy these colors into your swatches in Adobe Illustrator. They’ll be the base for any illustrations you create later. Now you need a set of background colors. Here’s my trick to making these consistent with your illustration palette without completely blending in. Use the “Adjust Palette” tool in Coolors to dial up the brightness a few notches, and the saturation down just a tad to remove any neon effect. These will be your background colors. Add your background colors to config.js Copy your hex codes into the bgColors array in config.js. bgColors: [ '#FFDD77', '#FF8E72', '#ED5E84', '#4CE0B3', '#9893DA', ... ] Now when you go back to Chrome and refresh the page, you’ll see your new palette! Step 4: Accessorize This is the fun part. We’re going to illustrate objects, accessories, lizards—whatever you want—and layer them on top of your friends. Your objects will be categorized into groups, and one option from each group will be randomly chosen each time you load the page. Think of a group like “hats” or “glasses”. This will allow combinations of accessories to show at once, without showing two of the same type on the same person. Create a group of accessories To get started, open up Illustrator and create a new artboard out of the template. Think of a group of objects that you can riff on. I found hats to be a good place to start. If you don’t feel like illustrating, you can use cut-out images instead. Next, follow the same steps as you did when you exported the faces. Here they are again: Turn the Template layer off and export the images as PNGs. In the Export dialog, tick the “Use Artboards” checkbox and enter the range with your hats. Export at 72ppi to keep things running fast. Save your images into the images/ folder in your project. Add your accessories to config.js In config.js, add a new key to the customProps object that describes the group of accessories that you just created. Its value should be an array of the filepaths to your images. This is my hats array: customProps: { hats: [ 'images/hat_crown.png', 'images/hat_santa.png', 'images/hat_tophat.png', 'images/hat_antlers.png' ] } Refresh Chrome and behold, accessories! Create as many more accessories as you want Repeat the steps above to create as many groups of accessories as you want. I went on to make glasses and hairstyles, so my final illustrator file looks like this: The last step is adding your new groups to the config object. List your groups in the order that you want them to be stacked in the DOM. My final output will be hair, then hats, then glasses: customProps: { hair: [ 'images/hair_bowl.png', 'images/hair_bob.png' ], hats: [ 'images/hat_crown.png', 'images/hat_santa.png', 'images/hat_tophat.png', 'images/hat_antlers.png' ], glasses: [ 'images/glasses_aviators.png', 'images/glasses_monacle.png' ] } And, there you have it! Randomly generated friends with random accessories. Feel free to go much crazier than I did. I considered adding a whole group of animals in celebration of the new season of Planet Earth, or even adding Sir David Attenborough himself, or doing a bit of role reversal and featuring the animals with little safari hats! But I digress… Step 5: Publish it It’s time to put this in your new tabs! You have two options: Publish it as a Chrome extension in the Chrome Web Store. Host it as a website and point to it with the New Tab Redirect extension. Today, we’re going to cover Option #1 because I want to show you how to make the simplest Chrome extension possible. However, I recommend Option #2 if you want to keep your project private. Every Chrome extension that you publish is made publicly available, so unless your friends want their faces published to an extension that anyone can use, I’d suggest sticking to Option #2. How to make a simple Chrome extension to replace the new tab page All you need to do to make your project into a Chrome extension is add a manifest.json file to the root of your project with the following contents. There are plenty of other properties that you can add to your manifest file, but these are the only ones that are required for a new tab replacement: { ""manifest_version"": 2, ""name"": ""Your extension name"", ""version"": ""1.0"", ""chrome_url_overrides"" : { ""newtab"": ""index.html"" } } To test your extension, you’ll need to run it in Developer Mode. Here’s how to do that: Go to the Extensions page in Chrome by navigating to chrome://extensions/. Tick the checkbox in the upper-right corner labelled “Developer Mode”. Click “Load unpacked extension…” and select this project. If everything is running smoothly, you should see your project when you open a new tab. If there are any errors, they should appear in a yellow box on the Extensions page. Voila! Like I said, this is a very light example of a Chrome extension, but Google has tons of great documentation on how to take things further. Check it out and see what inspires you. Share the love Now that you know how to make a new tab extension, go forth and create! But wield your power responsibly. New tabs are opened so often that they’ve become a part of everyday life–just consider how many tabs you opened today. Some people prefer to-do lists in their tabs, and others prefer cats. At the end of the day, let’s make something that makes us happy. Cheers!",2016,Leslie Zacharkow,lesliezacharkow,2016-12-08T00:00:00+00:00,https://24ways.org/2016/how-to-make-a-chrome-extension/,code 209,Feeding the Audio Graph,"In 2004, I was given an iPod. I count this as one of the most intuitive pieces of technology I’ve ever owned. It wasn’t because of the the snazzy (colour!) menus or circular touchpad. I loved how smoothly it fitted into my life. I could plug in my headphones and listen to music while I was walking around town. Then when I got home, I could plug it into an amplifier and carry on listening there. There was no faff. It didn’t matter if I could find my favourite mix tape, or if my WiFi was flakey - it was all just there. Nowadays, when I’m trying to pair my phone with some Bluetooth speakers, or can’t find my USB-to-headphone jack, or even access any music because I don’t have cellular reception; I really miss this simplicity. The Web Audio API I think the Web Audio API feels kind of like my iPod did. It’s different from most browser APIs - rather than throwing around data, or updating DOM elements - you plug together a graph of audio nodes, which the browser uses to generate, process, and play sounds. The thing I like about it is that you can totally plug it into whatever you want, and it’ll mostly just work. So, let’s get started. First of all we want an audio source.