{"rowid": 7, "title": "Get Started With GitHub Pages (Plus Bonus Jekyll)", "contents": "After several failed attempts at getting set up with GitHub Pages, I vowed that if I ever figured out how to do it, I\u2019d write it up. Fortunately, I did eventually figure it out, so here is my write-up.\n\nWhy I think GitHub Pages is cool\n\nNormally when you host stuff on GitHub, you\u2019re just storing your files there. If you push site files, what you\u2019re storing is the code, and when you view a file, you\u2019re viewing the code rather than the output. What GitHub Pages lets you do is store those files, and if they\u2019re HTML files, you can view them like any other website, so there\u2019s no need to host them separately yourself.\n\nGitHub Pages accepts static HTML but can\u2019t execute languages like PHP, or use a database in the way you\u2019re probably used to, so you\u2019ll need to output static HTML files. This is where templating tools such as Jekyll come in, which I\u2019ll talk about later.\n\nThe main benefit of GitHub Pages is ease of collaboration. Changes you make in the repository are automatically synced, so if your site\u2019s hosted on GitHub, it\u2019s as up-to-date as your GitHub repository. This really appeals to me because when I just want to quickly get something set up, I don\u2019t want to mess around with hosting; and when people submit a pull request, I want that change to be visible as soon as I merge it without having to set up web hooks.\n\nBefore you get started\n\nIf you\u2019ve used GitHub before, already have an account and know the basics like how to set up a repository and clone it to your computer, you\u2019re good to go. If not, I recommend getting familiar with that first. The GitHub site has extensive documentation on getting started, and if you\u2019re not a fan of using the command line, the official GitHub apps for Mac and Windows are great.\n\nI also found this tutorial about GitHub Pages by Thinkful really useful, and it contains details on how to turn an existing repository into a GitHub Pages site.\n\nAlthough this involves a bit of using the command line, it\u2019s minimal, and I\u2019ll guide you through the basics.\n\nSetting up GitHub Pages\n\nFor this demo we\u2019re going to build a Christmas recipe site \u2014 nothing complex, just a place to store recipes so we can share them with people, and they can fork or suggest changes to ones they like. My GitHub username is maban, and the project I\u2019ve set up is called christmas-recipes, so once I\u2019ve set up GitHub Pages, the site can be found here: http://maban.github.io/christmas-recipes/\n\nYou can set up a custom domain, but by default, the URL for your GitHub Pages site is your-username.github.io/your-project-name.\n\nSet up the repository\n\nThe first thing we\u2019re going to do is create a new GitHub repository, in exactly the same way as normal, and clone it to the computer. Let\u2019s give it the name christmas-recipes. There\u2019s nothing in it at the moment, but that\u2019s OK.\n\n\n\nAfter setting up the repository on the GitHub website, I cloned it to my computer in my Sites folder using the GitHub app (you can clone it somewhere else, if you want), and now I have a local repository synced with the remote one on GitHub.\n\nNavigate to the repository\n\nNow let\u2019s open up the command line and navigate to the local repository. The easiest way to do this in Terminal is by typing cd and dragging and dropping the folder into the terminal window and pressing Return. You can refer to Chris Coyier\u2019s GIF illustrating this very same thing, from last week\u2019s 24 ways article \u201cGrunt for People Who Think Things Like Grunt are Weird and Hard\u201d (which is excellent).\n\nSo, for me, that\u2019s\u2026\n\ncd /Users/Anna/Sites/christmas-recipes \n\nCreate a special GitHub Pages branch\n\nSo far we haven\u2019t done anything different from setting up a regular repository, but here\u2019s where things change.\n\nNow we\u2019re in the right place, let\u2019s create a gh-pages branch. This tells GitHub that this is a special branch, and to treat the contents of it differently.\n\nMake sure you\u2019re still in the christmas-recipes directory, and type this command to create the gh-pages branch:\n\ngit checkout --orphan gh-pages\n\nThat --orphan option might be new to you. An orphaned branch is an empty branch that\u2019s disconnected from the branch it was created off, and it starts with no commits, making it a special standalone branch. checkout switches us from the branch we were on to that branch.\n\nIf all\u2019s gone well, we\u2019ll get a message saying Switched to a new branch \u2018gh-pages\u2019.\n\nYou may get an error message saying you don\u2019t have admin privileges, in which case you\u2019ll need to type sudo at the start of that command.\n\nMake gh-pages your default branch (optional)\n\nThe gh-pages branch is separate to the master branch, but by default, the master branch is what will show up if we go to our repository\u2019s URL on GitHub. To change this, go to the repository settings and select gh-pages as the default branch.\n\n\n\nIf, like me, you only want the one branch, you can delete the master branch by following Oli Studholme\u2019s tutorial. It\u2019s actually really easy to do, and means you only have to worry about keeping one branch up to date.\n\nIf you prefer to work from master but push updates to the gh-pages branch, Lea Verou has written up a quick tutorial on how to do this, and it basically involves working from the master branch, and using git rebase to bring one branch up to date with another.\n\nAt the moment, we\u2019ve only got that branch on the local machine, and it\u2019s empty, so to be able to see something at our special GitHub Pages URL, we\u2019ll need to create a page and push it to the remote repository.\n\nMake a page\n\nOpen up your favourite text editor, create a file called index.html in your christmas-recipes folder, and put some exciting text in it. Don\u2019t worry about the markup: all we need is text because right now we\u2019re just checking it works.\n\n\n\nNow, let\u2019s commit and push our changes. You can do that in the command line if you\u2019re comfortable with that, or you can do it via the GitHub app. Don\u2019t forget to add a useful commit message.\n\n\n\nNow we\u2019re ready to see our gorgeous new site! Go to your-username.github.io/your-project-name and, hopefully, you\u2019ll see your first GitHub Pages site. If not, don\u2019t panic, it can take up to ten minutes to publish, so you could make a quick cake in a cup while you wait.\n\nAfter a short wait, our page should be live! Hopefully that wasn\u2019t too traumatic. Now we know it works, we can add some proper markup and CSS and even some more pages.\n\nIf you\u2019re feeling brave, how about we take it to the next level\u2026\n\nSetting up Jekyll\n\nSince GitHub Pages can\u2019t execute languages like PHP, we need to give it static HTML files. This is fine if there are only a few pages, but soon we\u2019ll start to miss things like PHP includes for content that\u2019s the same on every page, like headers and footers.\n\nJekyll helps set up templates and turn them into static HTML. It separates markup from content, and makes it a lot easier for people to edit pages collaboratively. With our recipe site, we want to make it really easy for people to fix typos or add notes, without having to understand PHP. Also, there\u2019s the added benefit that static HTML pages load really fast.\n\nJekyll isn\u2019t officially supported on Windows, but it is still possible to run it if you\u2019re prepared to get your hands dirty.\n\nInstall Jekyll\n\nBack in Terminal, we\u2019re going to install Jekyll\u2026\n\ngem install jekyll\n\n\u2026and wait for the script to run. This might take a few moments. It might take so long that you get worried its broken, but resist the urge to start mashing your keyboard like I did.\n\nGet Jekyll to run on the repository\n\nFingers crossed nothing has gone wrong so far. If something did go wrong, don\u2019t give up! Check this helpful post by Andy Taylor \u2013 you probably just need to install something else first. \n\nNow we\u2019re going to tell Jekyll to set up a new project in the repository, which is in my Sites folder (yours may be in a different place). Remember, we can drag the directory into the terminal window after the command.\n\njekyll new /Users/Anna/Sites/christmas-recipes\n\nIf everything went as expected, we should get this error message: Conflict: /Users/Anna/Sites/christmas-recipes exists and is not empty.\n\nBut that\u2019s OK. It\u2019s just upset because we\u2019ve got that index.html file and possibly also a README.md in there that we made earlier. So move those onto your desktop for the moment and run the command again.\n\njekyll new /Users/Anna/Sites/christmas-recipes\n\nIt should say that the site has installed.\n\nCheck you\u2019re in the repository, and if you\u2019re not, navigate to it by typing cd , drag the christmas-recipes directory into terminal\u2026\n\njekyll cd /Users/Anna/Sites/christmas-recipes\n\n\u2026and type this command to tell Jekyll to run:\n\njekyll serve --watch\n\nBy adding --watch at the end, we\u2019re forcing Jekyll to rebuild the site every time we hit Save, so we don\u2019t have to keep telling it to update every time we want to view the changes. We\u2019ll need to run this every time we start work on the project, otherwise changes won\u2019t be applied. For now, wait while it does its thing. \n\nUpdate the config file\n\nWhen it\u2019s finished, we\u2019ll see the text press ctrl-c to stop. Don\u2019t do that, though. Instead, open up the directory. You\u2019ll notice some new files and folders in there. There\u2019s one called _site, and that\u2019s where all the site files are saved when they\u2019re turned into static HTML. Don\u2019t touch the files in here \u2014 they\u2019re the generated files and will get overwritten every time we make changes to pages and layouts.\n\nThere\u2019s a file in our directory called _config.yml. This has some settings we can change, one of them being what our base URL is. GitHub Pages will assume the base URL is above the project repository, so changing the settings here will help further down the line when setting up navigation links.\n\nReplace the contents of the _config.yml file with this:\n\nname: Christmas Recipes\nmarkdown: redcarpet\npygments: true\nbaseurl: /christmas-recipes\n\nSet up your files\n\nOverwrite the index.html file in the root with the one we made earlier (you might want to pop the README.md back in there, too). \n\nDelete the files in the css folder \u2014 we\u2019ll add our own later.\n\nView the Jekyll site\n\nOpen up your favourite browser and type http://localhost:4000/christmas-recipes in the address bar.\n\n\n\nCheck it out, that\u2019s your site! But it could do with a bit more love.\n\nSet up the _includes files\n\nIt\u2019s always useful to be able to pull in snippets of content onto pages, such as the header and footer, so they only need to be updated in one place. That\u2019s what an _includes folder is for in Jekyll. Create a folder in the root called _includes, and within it add two files: head.html and foot.html. \n\nIn head.html, paste the following:\n\n\n\n \n \n {{ page.title }}\n \n \n \n\nand in foot.html:\n\n\n\n\nWhenever we want to pull in something from the _includes folder, we can use {% include filename.html %} in the layout file \u2014 I\u2019ll show you how to set that up in next step.\n\nMaking layouts\n\nIn our directory, there\u2019s a folder called _layouts and this lets us create a reusable template for pages. Inside that is a default.html file. \n\nDelete everything in default.html and paste in this instead:\n\n{% include head.html %}\n\n

{{ page.title }}

\n\n {{ content }}\n\n{% include foot.html %}\n\nThat\u2019s a very basic page with a header, footer, page title and some content. To apply this template to a page, go back into the index.html page and add this snippet to the very top of the file:\n\n---\nlayout: default\ntitle: Home\n---\n\nNow save the index.html file and hit Refresh in the browser. We should see a heading where {{ page.title }} was in the layout, which matches what comes after title: on the page itself (in this case, Home). So, if we wanted a subheading to appear on every page, we could add {{ page.subheading }} to where we want it to appear in our layout file, and a line that says subheading: This is a subheading in between the dashes at the top of the page itself.\n\nUsing Markdown for templates\n\nAnything on a page that sits under the closing dashes is output where {{ content }} appears in the template file. At the moment, this is being output as HTML, but we can use Markdown instead, and Jekyll will convert that into HTML. For this recipe site, we want to make it as easy as possible for people to be able to collaborate, and also have the markup separate from the content, so let\u2019s use Markdown instead of HTML for the recipes.\n\nTelling a page to use Markdown instead of HTML is incredibly simple. All we need to do is change the filename from .html to .md, so let\u2019s rename the index.html to index.md. Now we can use Markdown, and Jekyll will output that as HTML.\n\nCreate a new layout\n\nWe\u2019re going to create a new layout called recipe which is going to be the template for any recipe page we create. Let\u2019s keep it super simple.\n\nIn the _layouts folder, create a file called recipe.html and paste in this:\n\n{% include head.html %}\n\n\t
\n\n \t

{{ page.title }}

\n\n \t{{ content }}\n\n \t

Recipe by {{ page.recipe-attribution }}.

\n\n\t
\n\n\t{% include nav.html %}\n\n{% include foot.html %}\n\nThat\u2019s our template. The content that goes on the recipe layout includes a page title, the recipe content, a recipe attribution and a recipe attribution link.\n\nAdding some recipe pages\n\nCreate a new file in the root of the christmas-recipes folder and call it gingerbread.md. Paste the following into it:\n\n---\nlayout: recipe\ntitle: Gingerbread\nrecipe-attribution: HungryJenny\nrecipe-attribution-link: http://www.opensourcefood.com/people/HungryJenny/recipes/soft-christmas-gingerbread-cookies\n---\nMakes about 15 small cookies.\n\n## Ingredients\n\n* 175g plain flour\n* 90g brown sugar\n* 50g unsalted butter, diced, at room temperature\n* 2 tbsp golden syrup\n* 1 egg, beaten\n* 1 tsp ground ginger\n* 1 tsp cinnamon\n* 1 tsp bicarbonate of soda\n* Icing sugar to dust\n\n## Method\n\n1. Sift the flour, ginger, cinnamon and bicarbonate of soda into a large mixing bowl.\n2. Use your fingers to rub in the diced butter. Mix in the sugar.\n3. Mix the egg with the syrup then pour into the flour mixture. Fold in well to form a dough.\n4. Tip some flour onto the work surface and knead the dough until smooth.\n5. Preheat the oven to 180\u00b0C.\n6. Roll the dough out flat and use a shaped cutter to make as many cookies as you like.\n7. Transfer the cookies to a tray and bake in the oven for 15 minutes. Lightly dust the cookies with icing sugar.\n\nThe content is in Markdown, and when we hit Save, it\u2019ll be converted into HTML in the _site folder. Save the file, and go to http://localhost:4000/christmas-recipes/gingerbread.html in your favourite browser.\n\n \n\nAs you can see, the Markdown content has been converted into HTML, and the attribution text and link has been inserted in the right place.\n\n\nAdd some navigation\n\nIn your _includes folder, create a new file called nav.html. Here is some code that will generate your navigation:\n\n\n\nThis is going to look for all pages and generate a list of them, and give the navigation item that is currently active a class of active so we can style it differently.\n\nNow we need to include that navigation snippet in our layout. Paste {% include nav.html %} in default.html file, under {{ content }}.\n\nPush the changes to GitHub Pages\n\nNow we\u2019ve got a couple of pages, it\u2019s time to push our changes to GitHub. We can do this in exactly the same way as before. Check your special GitHub URL (your-username.github.io/your-project-name) and you should see your site up and running.\n\nIf you quit Terminal, don\u2019t forget to run jekyll serve --watch from within the directory the next time you want to work on the files.\n\nNext steps\n\nNow we know the basics of creating Jekyll templates and publishing them as GitHub Pages, we can have some fun adding more pages and styling them up.\n\n \n \n Here\u2019s one I made earlier\n\n\nI\u2019ve only been using Jekyll for a matter of weeks, mainly for prototyping. It\u2019s really good as a content management system for blogs, and a lot of people host their Jekyll blogs on GitHub, such as Harry Roberts\n\n\n\tBy hosting the code so openly it will make me take more pride in it and allow me to work on it much more easily; no excuses now!\n\n\nOverall, the documentation for Jekyll feels a little sparse and geared more towards blogs than other sites, but as more people discover the benefits of it, I\u2019m sure this will improve over time.\n\nIf you\u2019re interested in poking about with some code, all the files from this tutorial are available on GitHub.", "year": "2013", "author": "Anna Debenham", "author_slug": "annadebenham", "published": "2013-12-18T00:00:00+00:00", "url": "https://24ways.org/2013/get-started-with-github-pages/", "topic": null} {"rowid": 22, "title": "The Responsive Hover Paradigm", "contents": "CSS transitions and animations provide web designers with a whole slew of tools to spruce up our designs. Move over ActionScript tweens! The techniques we can now implement with CSS are reminiscent of Flash-based adventures from the pages of web history.\n\nPairing CSS enhancements with our :hover pseudo-class allows us to add interesting events to our websites. We have a ton of power at our fingertips. However, with this power, we each have to ask ourselves: just because I can do something, should I?\n\nWhy bother? \n\nWe hear a lot of mantras in the web community. Some proclaim the importance of content; some encourage methods like mobile first to support content; and others warn of the overhead and speed impact of decorative flourishes and visual images. I agree, one hundred percent. At the same time, I believe that content can reign king and still provide a beautiful design with compelling interactions and acceptable performance impacts. Maybe, just maybe, we can even have a little bit of fun when crafting these systems!\n\nYes, a site with pure HTML content and no CSS will load very fast on your mobile phone, but it leaves a lot to be desired. If you went to your local library and every book looked the same, how would you know which one to borrow? Imagine if every book was printed on the same paper stock with the same cover page in the same type size set at a legible point value\u2026 how would you know if you were going to purchase a cookbook about wild game or a young adult story about teens fighting to the death?\n\nFor certain audiences, seeing a site with hip, lively hovers sure beats a stale website concept. I\u2019ve worked on many higher education sites, and setting the interactive options is often a very important factor in engaging potential students, alumni, and donors. The same can go for e-commerce sites: enticing your audience with surprise and delight factors can be the difference between a successful and a lost sale. \n\nKnowing your content and audience can help you decide if an intriguing experience is appropriate for your site; if it is, then hover responses can be a real asset. \n\nWhy hover?\n\nWe have all these capabilities with CSS properties to create the aforementioned fun interactions, and it would be quite easy to fall back into some old patterns and animation abuse. The world of Flash intros and skip links could be recreated with CSS keyframes. However, I don\u2019t think any of us want to go the route of forcing users into unwanted exchanges and road blocking content. \n\nWhat\u2019s great about utilizing hover to pair with CSS powered actions is that it\u2019s user initiated. It\u2019s a well-established expectation that when a user mouses over an object, something changes. If we can identify that something as a link, then we will expect something to change as we move our mouse over it. By waiting to trigger a CSS-based response until a user chooses to engage with a target makes for a more polished experience (as opposed to barraging our screens with animations all willy-nilly). This makes it the perfect opportunity to add some unique spunk. \n\nWhat about mobile, touch, and responsive?\n\nSo, you\u2019re on board with this so far, but what about mobile and touch devices? Sure, some devices like the Samsung Galaxy S4 have some hovering capabilities, but certainly most do not. Beyond mobile devices, we also have to worry about desktops with touch capabilities. It\u2019s super difficult to detect if a user is currently using touch or hover. One option we have is to design strictly for touch only and send hover enhancements to the graveyard. However, being that I\u2019m all \u201cfuck yeah hovers!,\u201d I like to explore all options. So, let\u2019s examine four different types of hover patterns and see how they can translate to our touch devices.\n\n1. The essential text hover\n\nChanging text color on hover is something we\u2019ve done for a while and it has helped aid in identifying links. To maintain the best accessibility we can achieve, it helps to have a different visual indicator on the default :link state, such as an underline. By making sure all text links have an underline, we won\u2019t have to rely on visual changes during hover to make sure touch device users know that it is a link. For hover-enabled devices, we can add a basic color transition. Doing so creates a nice fade, which makes the change on hover less jarring. Kinda like smooth jazz. The code* to achieve this is quite simple: \n\na {\n\tcolor: #6dd4b1;\n\ttransition: color 0.25s linear; \n}\n\na:hover, a:focus {\n\tcolor: #357099;\n}\n\n\n\tBrowser prefixes are omitted\n\n\nYou can see in the final result that, for both touch and hover, everyone wins: \n\nSee the Pen Most Basic Link Transition by Jenn Lukas (@Jenn) on CodePen\n\n \n\n2. Visual background wizardry and animated hovers\n\nWe can take this a step further by again making changes to our aesthetic on hover, but not making any content changes. Altering image hovers for fun and personality can separate your site from others; that personality is important and can enhance our content. \n\nLet\u2019s look at a few sites that do this really well. Scroll down to the judges section of CSS Off and check out the illustrations of the judges. On hover, the illustration fades into a photo of the judge. This provides a realistic alternative to the drawing. Users without the hover can click into the detail page, where they can see the full color picture and learn more about the judges; the information is still available through a different pathway. \n\nGoing back to the higher education field, let\u2019s visit Delaware Valley College. The school had recently gone through a rebranding that included loop icons as a symbol to connect ideas. These icons are brought into the website on hover of the slideshow arrows (WebKit browsers). The hover reveals a loop animation, tying in overall themes and adding some extra pizzazz that makes me think, \u201cThis is a hip place that feels current.\u201d For visitors who can\u2019t access the hover effect, the default arrow state clearly represents a clickable link, and there is swipe functionality on mobile devices to boot. \n\nDIY.org\u2019s Frontend Dev page has a bunch of enjoyable hover actions happening, featuring scaling transforms and looping animations. Nothing new is revealed on hover, so touch devices won\u2019t miss anything, but it intrigues the user who is visiting a site about front-end dev doing cool front-end things. It backs up its claim of front-end knowledge by adding this enhancement. \n\nThe old Cowork Chicago (now redirecting) had a great example, captured here:\n\n Coop: Chicago Coworking from Jenn Lukas on Vimeo.\n\nThe code for the Join areas is quite simple: \n\n.join-buttons .daily, .join-buttons .monthly { \n height: 260px; z-index: 0; margin-top: 30px;\n\ttransition: height .2s linear,margin .2s linear;\n}\n\n.join-buttons .daily:hover, .join-buttons .monthly:hover { \n\theight: 280px; margin-top: 20px; \n}\n\nli.button:hover { \n z-index: 20; \n}\n\nThe slight rotation on the photos, and the change of color and size of the rate options on hover, add to the fun factor. The site attempts to advertise the co-working space by letting bits of their charisma show through with these transitions. They don\u2019t hit the user over the head with animations, but provide a nice addition to make sure visitors know it\u2019s a welcoming place to work. Some text is added on the hover, but the text isn\u2019t essential to determine where the link goes.\n\n3. Image block hovers\n\nThere have been more designs popping up with large image blocks acting as extensive hit area links to subsequent pages. On hover of these links, text is revealed, letting the user know where the link destination goes. \n\nSee the Pen Transitioning Max Height by Jenn Lukas (@Jenn) on CodePen\n\nThis type of link is tough for users on touch as the image might not provide enough context to reveal its target. If you weren\u2019t aware of what my illustrated avatar from 2007 looked like (or even if you did), then how would you know that this is a link to my Twitter page? Instead, if we provide enough context \u2014 such as the @jennlukas handle \u2014 you could assume the destination. Users who receive the hover can also see the Twitter bio. It won\u2019t break the experience for users that can\u2019t hover, but it will provide a nice interaction and some more information for those that can. \n\nSee the Pen Transitioning Max Height by Jenn Lukas (@Jenn) on CodePen\n\nThe Esquire site follows this same pattern, in which the title of the story is shown and the subheading is revealed on hover. Dining at Altitude took the opposite approach, where all text is shown by default and, on hover, you can see more of the image that the text sits atop. This is a nice technique to follow. For touch users, following the link will allow them to see more of the image detail that was revealed on hover. \n\n4. Drop-down navigation menu hovers\n\nMain navigation options that rely on hover have come up as a problem for touch. One way to address this is to be sure your top level items are all functional links to somewhere, and not blank anchors to trigger a submenu drop-down. This ensures that, even without the hover-triggered menu, users can still navigate to those top-level pages. From there, they should be able to access the tertiary pages shown in the drop-down. Following this arrangement, drop-down menus act as a quick shortcut and aren\u2019t necessary to the navigational structure. If the top navigation items are your most visited pages, this execution won\u2019t hinder your visitors. \n\nIf the information within the menu is vital, such as a lone account menu, another option is to show drop-down menus on click instead of hover. This pattern will allow both mouse and touch users to access the drop-downs. \n\nWhy can\u2019t we just detect hover?\n\nThis is a really tricky thing to do. Internet Explorer 10 on Windows 8 uses the aria-haspopup attribute to simulate hover on touch devices, but usually our audience stretches beyond that group. There\u2019s been discussion around using Modernizr, but false positives have come with that. A W3C draft for Media Queries Level 4 includes a hover feature, but it\u2019s not supported yet. Since some devices can hover and touch, should you rely on hover effects for those? Arguments have come up that users can be browsing your site with a mouse and then decide to switch to touch, or vice versa. That might be a large concern for you, or it might be an edge case that isn\u2019t vital to your site\u2019s success. \n\nFor one site, I used mousemove and touchstart JavaScript events in order to detect if a visitor starts to browse the site with a mouse. The design initiates for touch users, showing all text on load, but as soon as a mouse movement occurs, the text becomes hidden and is then revealed on hover. \n\nSee the Pen Detect Touch devices with mousemove and touchstart by Jenn Lukas (@Jenn) on CodePen\n\nOne downside to this approach is that the text is viewable until a mouse enters the document, but if the elements are further down the page it might not be noticed. A second downside is if a user on a touch- and hover-enabled device starts browsing with the mouse and then switches back to touch, the hover-centric styles will remain until a new page load. These were acceptable scenarios in the project I worked on, but might not be for every project. \n\nCan we give our visitors a choice?\n\nI\u2019ve been thinking about how we can combat the concern of not knowing if our customers are using touch or a mouse, not to mention keyboard or Wacom tablets or Minority Report screens. We can cover keyboards with our friend :focus, but that still doesn\u2019t solve our other dilemmas. \n\nRemember when we couldn\u2019t rely on browsers to zoom text and we had to use those small A, medium A, big A [AAA] buttons? On selection of one of those options, a different style sheet would load with small, medium, or large text sizes to satisfy our user\u2019s request. We could even set cookies to remember their font choices. What if we offered a similar solution, a hover/touch switcher, for our new predicament? \n\nSee the Pen cwuJf by Jenn Lukas (@Jenn) on CodePen\n\nWe could add this switcher to our design. Maybe add it to the header on smaller screens and the footer on larger screens to play the odds. Then be sure to deliver the appropriate touch- or hover-optimized adventure for our guests.\n\nHow about adding View options in the areas where we\u2019re hiding content until hover? Looking at Delta Cycle, there\u2019s logic in place to switch layouts on some mobile devices. On desktops we can see the layout shows the product and price by default, and the name of the item and an Add to cart button on hover. If you want to keep this hover, but also worry that touch users can\u2019t access it \u2014 or even if you are concerned that people might want to view it with more details up front \u2014 we could add another view switcher. \n\nSee the Pen List/Grid Views for Hover or Touch by Jenn Lukas (@Jenn) on CodePen\n\nSimilar to the list versus grid view we often see in operating systems, a choice here could cover all of our bases. \n\nConclusion\n\nThere is no one-size-fits-all solution when it comes to hover patterns. Design for your content. If you are providing important information about driving directions or healthcare, you might want to err on the side of designing for touch only. If you are behind an educational site and trying to entice more traffic and sign-ups, or a more immersive e-commerce site selling pies, then hover activity can help support your content and engage your visitors without being a detriment. While content can be our top priority, let\u2019s not forget that our designs and interactions, hovers included, can have a great positive impact on how visitors experience our site. Hover wisely, friends.", "year": "2013", "author": "Jenn Lukas", "author_slug": "jennlukas", "published": "2013-12-12T00:00:00+00:00", "url": "https://24ways.org/2013/the-responsive-hover-paradigm/", "topic": null} {"rowid": 23, "title": "Animating Vectors with SVG", "contents": "It is almost 2014 and fifteen years ago the W3C started to develop a web-based scalable vector graphics (SVG) format. As web technologies go, this one is pretty old and well entrenched. \n\nSee the Pen yJflC by Drew McLellan (@drewm) on CodePen\n\n\nEmbed not working on your device? Try direct. \n\nUnlike rasterized images, SVG files will stay crisp and sharp at any resolution. With high-DPI phones, tablets and monitors, all those rasterized icons are starting to look a bit old and blocky. There are several options to get simpler, decorative pieces to render smoothly and respond to various device widths, shapes and sizes. Symbol fonts are one option; the other is SVG.\n\nI\u2019m a big fan of SVG. SVG is an XML format, which means it is possible to write by hand or to script. The most common way to create an SVG file is through the use of various drawing applications like Illustrator, Inkscape or Sketch. All of them open and save the SVG format.\n\nBut, if SVG is so great, why doesn\u2019t it get more attention?\n\nThe simple answer is that for a long time it wasn\u2019t well supported, so no one touched the technology. SVG\u2019s adoption has always been hampered by browser support, but that\u2019s not the case any more. Every modern browser (at least three versions back) supports SVG. Even IE9. \n\nAlthough the browsers support SVG, it is implemented in many different ways.\n\nSVG in HTML\n\nSome browsers allow you to embed SVG right in the HTML: the element. Treating SVG as a first-class citizen works \u2014 sometimes. Another way to embed SVG is via the element; using the src attribute, you can refer to an SVG file. Again, this only works sometimes and leaves you in a tight space if you need to have a fallback for older browsers. The most common solution is to use the element, with the data attribute referencing the SVG file. When a browser does not support this, it falls back to the content inside the . This could be a rasterized fallback . This method gets you the best of both worlds: a nice vector image with an alternative rasterized image for browsers that don\u2019t support SVG. The downside is that you need to manage both formats, and some browsers will download both the SVG and the rasterized version, becoming a performance problem.\n\nAlexey Ten came up with a brilliant little trick that uses inline SVG combined with an SVG element. This has an SVG href pointing to the vector SVG representation and a src attribute to the rasterized version. Older browsers will rewrite the element as and use the rasterized src attribute, but modern browsers will show the vector SVG.\n\n\n \n\n\nIt is a great workaround for most situations. You will have to determine the browsers you want or need to support and consider performance issues to decide which method is best for you.\n\nSo it can be used in HTML. Why?\n\nThere are two compelling reasons why vector graphics in the form of icons and symbols are going to be important on the web. With higher resolution screens, going from 72dpi to 200, 300, even over 400dpi, your rasterized icons are looking a little too blocky. As we zoom and print, we expect the visuals on the site to also stay smooth and crisp.\n\nThe other main reason vector graphics are useful is scaling. As responsive websites become the norm, we need a way to dynamically readjust the heights, widths and styles of various elements. SVG handles this perfectly, since vectors remain smooth when changing size.\n\nSVG files are text-based, so they\u2019re small and can be gzipped nicely. There are also techniques for creating SVG sprites to further squeeze out performance gains. But SVG really shines when you begin to couple it with JavaScript. Since SVG elements are part of the DOM, they can be interacted with just like any other element you are used to.\n\nThe folks at Vox Media had an ingenious little trick with their SVG for a Playstation and Xbox One reviews. I\u2019ve used the same technique for the 24 ways example. Vox Media spent a lot of time creating SVG line art of the two consoles, but once in place the artwork scaled and resized beautifully. \n\nThey still had another trick up their sleeves. In their example, they knew each console was line art, so they used SVG\u2019s line dash property to simulate the lines being drawn by animating the growth of the line by small percentage increments until the lines were complete.\n\nThis is a great example of a situation where the alternatives wouldn\u2019t be as straightforward to implement. Using an animated GIF would create a heavy file since it would need to contain all the frames of the animation at a large size to permit scaling; even then, smooth aliasing would be lost. canvas and plenty of JavaScript would be another alternative, but this is a rasterized format. It would need be redrawn at each scale, which is certainly possible, but smoothness would be lost when zooming or printing.\n\nThe HTML, SVG and JavaScript for this example is less than 4KB! Let\u2019s have a quick look at the code:\n\n\n\nFirst, we need to initialize a few variables to set the current frame, the number of frames, how fast the animation will run, and we get each of the paths based on their IDs. With those paths, we set the dash and dash offset.\n\npath[i].style.strokeDasharray = l + ' ' + l; \npath[i].style.strokeDashoffset = l;\n\nWe start the line as a dash, which effectively makes it blank or invisible.\n\nNext, we move to the draw() function. This is where the magic happens. We want to increment the frame to move us forward in the animation and check it\u2019s not finished. If it continues, we then take a percentage of the distance based on the frame and then set the dash offset to this new percentage. This gives the illusion that the line is being drawn. Then we have an animation callback, which starts the draw process over again.\n\nThat\u2019s it! It will work with any SVG element that you can draw.\n\nLibraries to get you started\n\nIf you aren\u2019t sure where to start with SVG, there are several libraries out there to help. They also abstract all browser compatibility issues to make your life easier.\n\n\n\tRapha\u00ebl\n\tSnap.svg\n\tsvg.js\n\n\nYou can also get most vector applications to export SVG. This means that you can continue your normal workflows, but instead of flattening the image as a PNG or bringing it over to Photoshop to rasterize, you can keep all your hard work as vectors and reap the benefits of SVG.", "year": "2013", "author": "Brian Suda", "author_slug": "briansuda", "published": "2013-12-07T00:00:00+00:00", "url": "https://24ways.org/2013/animating-vectors-with-svg/", "topic": null} {"rowid": 2, "title": "Levelling Up", "contents": "Hello, 24 ways. I\u2019m Ashley and I sell property insurance. I\u2019m interrupting your Christmas countdown with an article about rental property software and a guy, Pete, who selflessly encouraged me to build my first web app. It doesn\u2019t sound at all festive, or \u2014 considering I\u2019ve used both \u201cinsurance\u201d and \u201crental property\u201d \u2014 interesting, but do stick with me. There\u2019s eggnog at the end.\n\nI run a property insurance business, Brokers Direct. It\u2019s a small operation, but well established. We\u2019ve been selling landlord insurance on the web for over thirteen years, for twelve of which we have provided our clients with third-party software for managing their rental property portfolios. Free. Of. Charge.\n\nIt sounds like a sweet deal for our customers, but it isn\u2019t. At least, not any more. The third-party software is victim to years of neglect by its vendor. Its questionable interface, garish visuals and, ahem, clip art icons have suffered from a lack of updates. While it was never a contender for software of the year, I\u2019ve steadily grown too embarrassed to associate my business with it.\n\n The third-party rental property software we distributed\n\nI wanted to offer my customers a simple, clean and lightweight alternative. In an industry that\u2019s dominated by dated and bloated software, it seemed only logical that I should build my own rental property tool.\n\nThe long learning-to-code slog\n\nLearning a programming language is daunting, the source of my frustration stemming from a non-programming background. Generally, tutorials assume a degree of familiarity with programming, whether it be tools, conventions or basic skills. I had none and, at the time, there was nothing on the web really geared towards a novice. I reached the point where I genuinely thought I was just not cut out for coding. Surrendering to my feelings of self-doubt and frustration, I sourced a local Rails developer, Pete, to build it for me.\n\nPete brought a pack of index cards to our meeting. Index cards that would represent each feature the rental property software would launch with.\n\n \n\n\u201cOK,\u201d he began. \u201cWe\u2019ll need a user model, tenant model, authentication, tenant and property relationships\u2026\u201d A dozen index cards with a dozen features lined the coffee table in a grid-like format. Logical, comprehensible, achievable. Seeing the app laid out in a digestible manner made it seem surmountable. Maybe I could do this.\n\n\u201cI\u2019ve been trying to learn Rails\u2026\u201d, I piped up.\n\nI don\u2019t know why I said it. I was fully prepared to hire Pete to do the hard work for me. But Pete, unprompted, gathered the index cards and neatly stacked them together, coasting them across the table towards me. \u201cYou should build this\u201d.\n\nPete, a full-time freelance developer at the time, was turning down a paying job in favour of encouraging me to learn to code. Looking back, I didn\u2019t realise how significant this moment was.\n\nThat evening, I took Pete\u2019s index cards home to make a start on my app, slowly evolving each of the cards into a working feature. Building the app solo, I turned to Stack Overflow to solve the inevitable coding hurdles I encountered, as well as calling on a supportive Rails community. Whether they provided direct solutions to my programming woes, or simply planted a seed on how to solve a problem, I kept coding. Many months later, and after several more doubtful moments, Lodger was born.\n\n Property overview of my app, Lodger.\n\nIf I can do it, so can you\n\nI misspent a lot of time building Twitter and blogging applications (apparently, all Rails tutorials centre around Twitter and blogging). If I could rewind and impart some advice to myself, this is what I\u2019d say.\n\nThere\u2019s no magic formula\n\n\u201cI haven\u2019t quite grasped Rails routing. I should tackle another tutorial.\u201d \n\nMaking excuses \u2014 or procrastination \u2014 is something we are all guilty of. I was waiting for a programming book that would magically deposit a grasp of the entire Ruby syntax in my head. I kept buying books thinking each one would be the one where it all clicked. I now have a bookshelf full of Ruby material, all of which I\u2019ve barely read, and none of which got me any closer to launching my web app. Put simply, there\u2019s no magic formula.\n\nBreak it down\n\nWhatever it is you want to build, break it down into digestible chunks. Taking Pete\u2019s method as an example, having an index card represent an individual feature helped me tremendously. Tackle one at a time. Even if each feature takes you a month to build, and you have eight features to launch with, after eight months you\u2019ll have your MVP. Remember, if you do nothing each day, it adds up to nothing.\n\nHave a tangible product to build\n\nI have a wonderful habit of writing down personal notes, usually to express my feelings at the time or to log an idea, only to uncover them months or years down the line, long after I forgot I had written them. I made a timely discovery while writing this article, discovering this gem while flicking through a battered Moleskine:\n\n\n\t\u201cI don\u2019t seem to be making good progress with learning Rails, but development still excites me. I should maybe stop doing tutorials and work towards building a specific app.\u201d\n\n\nHaving a real product to work on, like I did with Lodger, means you have something tangible to apply the techniques you are learning. I found this prevented me from flitting aimlessly between tutorials and books, which is an easy area to accidentally remain in.\n\nTeam up\n\nIf possible, team up with a designer and create something together. Designers are great at presenting features in a way you\u2019d never have considered. You will learn a lot from making their designs come to life.\n\nYour homework for the holiday\n\nDespite having a web app under my belt, I am not a programmer. I tinker with code, piecing enough bits of it together to make something functional. And that\u2019s OK! I\u2019m not excusing sloppiness, but if we aimed for perfection every time, we\u2019d never execute any of our ideas.\n\nAs the holidays approach and you\u2019ve exhausted yet another viewing of The Muppet Christmas Carol (or is that just my guilty pleasure at Christmas?), you may have time on your hands. Time to explore an idea you\u2019ve been sitting on, but \u2014 plagued with procrastination and doubt \u2014 have yet to bring to life. This holiday, I am here to say to you what Pete said to me.\n\nYou should build this.\n\nYou don\u2019t need to be the next Mark Zuckerberg or Larry Page. You just have to learn enough to get it done.\n\nPS: I lied about the eggnogg, but try capturing somebody\u2019s attention when you tell them you sell property insurance!", "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"} {"rowid": 14, "title": "The Command Position Principle", "contents": "Living where I do, in a small village in rural North Wales, getting anywhere means driving along narrow country roads. Most of these are just about passable when two cars meet. \n\nIf you\u2019re driving too close to the centre of the road, when two drivers meet you stop, glare at each other and no one goes anywhere. Drive too close to your nearside and in summer you\u2019ll probably scratch your paintwork on the hedgerows, or in winter you\u2019ll sink your wheels into mud. \n\nDriving these lanes requires a balance between caring for your own vehicle and consideration for someone else\u2019s, but all too often, I\u2019ve seen drivers pushed towards the hedgerows and mud when someone who\u2019s inconsiderate drives too wide because they don\u2019t want to risk scratching their own paintwork or getting their wheels dirty.\n\nIf you learn to ride a motorcycle,\u00a0you\u2019ll be taught about the command position:\n\n\n\tApproximate central position, or any position from which the rider can exert control over invitation space either side.\n\n\nThe command position helps motorcyclists stay safe, because when they ride in the centre of their lane it prevents other people, usually car drivers, from driving alongside, either forcing them into the curb or potentially dangerously close to oncoming traffic. \n\nTaking the command position isn\u2019t about motorcyclists being aggressive, it\u2019s about them being confident. It\u2019s them knowing their rightful place on the road and communicating that through how they ride.\n\nI\u2019ve recently been trying to take that command position when driving my car on our lanes. When I see someone coming in the opposite direction, instead of instinctively moving closer to my nearside \u2014 and in so doing subconsciously invite them into my space on the road \u2014 I hold both my nerve and a central position in my lane. Since I done this I\u2019ve noticed that other drivers more often than not stay in their lane or pull closer to their nearside so we occupy equal space on the road. Although we both still need to watch our wing mirrors, neither of us gets our paint scratched or our wheels muddy.\n\nWe can apply this principle to business too, in particular to negotiations and the way we sell. Here\u2019s how we might do that.\n\nCommanding negotiations\n\nWhen a customer\u2019s been sold to well \u2014\u00a0more on that in just a moment \u2014 and they\u2019ve made the decision to buy, the thing that usually stands in the way of us doing business is a negotiation over price. Some people treat negotiations as the equivalent of driving wide. They act offensively, because their aim is to force the other person into getting less, usually in return for giving more.\n\nIn encounters like this, it\u2019s easy for us to act defensively. We might lack confidence in the price we ask for, or the value of the product or service we offer. We might compromise too early because of that. When that happens, there\u2019s a pretty good chance that we\u2019ll drive away with less than we deserve unless we use the command position principle to help us.\n\nBefore we start any negotiation it\u2019s important to know that both sides ultimately want to reach an agreement. This isn\u2019t always obvious. If one side isn\u2019t already committed, at least in principle, then it\u2019s not a negotiation at that point, it\u2019s something else. \n\nFor example, a prospective customer may be looking to learn our lowest price so that they can compare it to our competitors. When that\u2019s the case, we\u2019ve probably failed to qualify that prospect properly as, after all, who wants to be chosen simply because they\u2019re the cheapest? In this situation, negotiating is a waste of time since we don\u2019t yet know that it will result in us making a deal. We should enter into a negotiation only when we know where we stand. So ask confidently: \u201cAre you looking to [make a decision]?\u201d\n\nWhen that\u2019s been confirmed, it\u2019s down to everyone to compromise until a deal\u2019s been reached. That\u2019s because good negotiations aren\u2019t about one side beating the other, they\u2019re about achieving a good deal for both. Using the command position principle helps us to maintain control over our negotiating space and affords us the opportunity to give ground only if we need to and only when we\u2019re ready. It can also ensure that the person we\u2019re negotiating with gives up some of their space.\n\nCommanding sales\n\nIt\u2019s not always necessary to negotiate when we\u2019re doing a business deal, but we should always be prepared to sell. One of the most important parts of our sales process should be controlling when and how we tell someone our price. \n\nUnless it\u2019s impossible to avoid, don\u2019t work out a price for someone on the spot. When we do that we lose control over the time and place for presenting our price alongside the value factors that will contribute to the prospective customer accepting that price. For the same reason, never give a ballpark or, worse, a guesstimate figure. If the question of price comes up before we\u2019re fully prepared, we should say politely that we need more time to work out a meaningful cost. \n\nWhen we are ready, we shouldn\u2019t email a price for our prospective customer to read unaccompanied. Instead, create an opportunity to talk a prospect through our figures, demonstrate how we arrived at them and, most importantly, explain the value of what we\u2019re selling to their business. Agree a time and place to do this and, if possible, do it all face-to-face. \n\nWe shouldn\u2019t hesitate when we give someone a price. When we sound even the slightest bit unsure or apologetic, we give the impression that we\u2019ll be flexible in our position before negotiations have even begun.\n\nThink about the command position principle, know the price and present it confidently. That way we send a clear signal that we know our business and how we deal with people. The command position principle isn\u2019t about being cocky, it\u2019s about showing other people respect, asking for it in return and showing it to ourselves.\n\n \n\nEarlier, I mentioned selling well, because we sometimes hear people say that they dislike being sold to. In my experience, it\u2019s not that people dislike the sales process, it\u2019s that we dislike it done badly.\n\nTaking part in a good sales process, either by selling or being sold to, can be a pleasurable experience. Try to be confident \u2014 after all, we understand how our skills will benefit a customer better than anyone else. Our confidence will inspire confidence in others. \n\nSelf-confidence isn\u2019t the same as arrogance, just as the command position isn\u2019t the same as riding without consideration for others. The command position principle preserves others\u2019 space as well as our own. By the same token, we should be considerate of others\u2019 time and not waste it and our own by attempting to force them into buying something that\u2019s inappropriate.\n\nTo prevent this from happening, evaluate them well to ensure that they\u2019re the right customer for us. If they\u2019re not, let them go on their way. They\u2019ll thank us for it and may well become customers the next time we meet.\n\nThe business of closing a deal can be made an enjoyable experience for everyone if we take control by guiding someone through the sales process by asking the right questions to uncover their concerns, then allaying them by being knowledgeable and confident. This is riding in the command position.\n\nJust like demonstrating we know our rightful position on the road, knowing our rightful place in a business relationship and communicating that through how we deal with people will help everyone achieve an equitable balance. When that happens in business, as well as on the road, no one gets their paintwork scratched or their wheels muddy.", "year": "2013", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2013-12-23T00:00:00+00:00", "url": "https://24ways.org/2013/the-command-position-principle/", "topic": "business"} {"rowid": 29, "title": "What It Takes to Build a Website", "contents": "In 1994 we lost Kurt Cobain and got the world wide web as a weird consolation prize. In the years that followed, if you\u2019d asked me if I knew how to build a website I\u2019d have said yes, I know HTML, so I know how to build a website. If you\u2019d then asked me what it takes to build a website, I\u2019d have had to admit that HTML would hardly feature.\n\nAmong the design nerdery and dev geekery it\u2019s easy to think that the nuts and bolts of building a page just need to be multiplied up and Ta-da! There\u2019s your website. That can certainly be true with weekend projects and hackery for fun. It works for throwing something together on GitHub or experimenting with ideas on your personal site. But what about working professionally on client projects?\n\nThe web is important, so we need to build it right.\n\nIt\u2019s 2015 \u2013 your job involves people paying you money for building websites. What does it take to build a website and to do it right? What practices should we adopt to make really great, successful and professional web projects in 2015? I put that question to some friends and 24 ways authors to see what they thought.\n\nGetting the tech right\n\nInevitably, it all starts with the technology. We work in a technical medium, after all. From Notepad and WinFTP through to continuous integration and deployment \u2013 how do you build sites?\n\nCreate a stable development environment\n\nThere\u2019s little more likely to send a web developer into a wild panic and a client into a wild rage than making a new site live and things just not working. That\u2019s why it\u2019s important to have realistic development and staging environments that mimic the live server as closely as possible.\n\nAre you in the habit of developing new sites right on the client\u2019s server? Or maybe in a subfolder on your local machine? It\u2019s time to reconsider.\n\nCharlie Perrins writes:\n\n\n\tDon\u2019t work on a live server \u2013 this feels like one of those gear-changing moments for a developer\u2019s growth. Build something that works just as well locally on your own machine as it does on a live server, and capture the differences in the code between the local and live version in a single config file. Ultimately, if you can get all the differences between environments down to a config level then you\u2019ll be in a really good position to automate the deployment process at some point in the future.\n\n\nAnything that creates a significant difference between the development and the live environments has the potential to cause problems you won\u2019t know about until the site goes live \u2013 and at that point the problems are very public and very embarrassing, not to mention unprofessional.\n\nA reasonable solution is to use a tool like MAMP PRO which enables you to set up an individual local website for each project you work on. Importantly, individual sites give you both consistency of paths between development and live, but also the ability to configure server options (like PHP versions and configuration, for example) to match the live site.\n\nBetter yet is to use a virtual machine, managed with a tool such as Vagrant. If you\u2019re interested in learning more about that, we have an article on that subject later in the series.\n\nUse source control\n\nTrent Walton writes:\n\n\n\tWe use source control, and it\u2019s become the centerpiece for how we handle collaboration, enhancements, and issues. It drives our process.\n\n\nI\u2019m hoping by now that you\u2019re either using source control for all your work, or feeling a nagging guilt that you should be. Be it Git, Mercurial, Subversion (name your poison), a revision control system enables you to keep track of changes, revert anything that breaks, and keep rolling backups of your project.\n\nThe benefits only start there, and Charlie Perrins recommends using source control \u201cnot just as a personal backup of your code, but as a way to play nicely with other developers.\u201c\n\nNoting the benefits when collaborating with other developers, he adds:\n\n\n\tGraduating from being the sole architect of your codebase to contributing to a shared codebase is a huge leap for a developer. Perhaps a practical way for people who tend to work on their own to do that would be to submit a pull request or a patch to an open source project or plugin.\u201d\n\n\nRichard Rutter of Clearleft sees clear advantages for the client, too. He recommends using source control \u201cpreferably in some sort of collaborative environment that you can open up or hand over to the client\u201d \u2013 a feature found with hosted services such as GitHub.\n\nIf you\u2019d like to hone your Git skills, Emma Jane Westby wrote Git for Grown-ups in last year\u2019s 24 ways.\n\nDon\u2019t repeat, automate!\n\nTim Kadlec is a big proponent of automating your build process:\n\n\n\tI\u2019ve been hammering that home to every client I\u2019ve had this year. It\u2019s amazing how many companies don\u2019t really have a formal build/deployment process in place. So many issues on the web (performance, accessibility, etc.) can be greatly improved just by having a layer of automation involved.\n\n\tFor example, graphic editing software spits out ridiculously bloated images. Very frequently, that\u2019s what ends up getting put on a site. If you have a build process, you can have the compression automated and start seeing immediate gains for no effort. On a recent project, they were able to shave around 1.5MB from their site weight simply by automating compression.\n\n\nOnce you have your code in source control, some of that automation can be made easier. Brian Suda writes:\n\n\n\tWe have a few bash scripts that run on git commit: they compile the less, jslint and remove white-space, basically the 3 Cs, Compress, Concatenate, Combine. This is now part of our workflow without even realising it.\n\n\nOne great way to get started with a build process is to use a tool like Grunt, and a great way to get started with Grunt is to read Chris Coyier\u2019s Grunt for People Who Think Things Like Grunt are Weird and Hard.\n\nTim reinforces:\n\n\n\tIssues like [image compression] \u2014 or simple accessibility issues like alt tags on images \u2014 should never be able to hit a live server. If you can detect it, you can automate it. And if you can automate it, you can free up time for designers and developers to focus on more challenging \u2014 and interesting \u2014 problems.\n\n\nA clear call to arms to tighten up and formalise development and deployment practices. The less that has to be done manually or is susceptible to change, the less that can go wrong when a site is built and deployed. Any procedures that are automated are no longer dependant on a single person\u2019s knowledge, making it easier to build your team or just cope when someone important is out of the office or leaves.\n\nIf you\u2019re interested in kicking the FTP habit and automating your site deployments, we have an article later in the series just for you.\n\nBuild systems, not sites\n\nOne big theme arising this year was that of building websites as systems, not as individual pages.\n\nBrad Frost:\n\n\n\tFor me, teams making websites in 2015 shouldn\u2019t be working on just-another-redesign redesign. People are realizing that in order to make stable, future-friendly, scalable, extensible web experiences they\u2019re going to need to think more systematically. That means crafting deliberate and thoughtful design systems. That means establishing front-end style guides. That means killing the out-dated, siloed, assembly-line waterfall process and getting cross-disciplinary teams working together in meaningful ways. That means treating development as design. That means treating performance as design. That means taking the time out of the day to establish the big picture, rather than aimlessly crawling along quarter by quarter.\n\n\nDesigner and developer Jina Bolton also advocates the use of style guides, and recommends making the guide a project deliverable:\n\n\n\tConsider adding on a style guide/UI library to your project as a deliverable for maintainability and thinking through all UI elements and components.\n\n\nVal Head agrees: \u201cbuild and maintain a style guide for each project\u201d she wrote. On the subject of approaching a redesign, she added:\n\n\n\tA UI inventory goes a long way to helping get your head around what a design system needs in the early stages of a redesign project.\n\n\nSo what about that old chestnut, responsive web design? Should we be making sites responsive by default? How about mobile first?\n\nRichard Rutter:\n\n\n\tThink mobile first unless you have a very good reason not to. Remember to take the client with you on this principle, otherwise it won\u2019t work as a convincing piece of design.\n\n\nTrent Walton adds:\n\n\n\tThe more you can test and sort of skew your perception for what is typical on the web, the better. 4k displays hooked up to 100Mbps connections can make one extremely unsympathetic.\n\n\nThe value of testing with real devices is something Ruth John appreciates. She wrote:\n\n\n\tI still have my own small device lab at home, even though I work permanently for a well-established company (which has a LOT of devices at its disposal) \u2013 it just means I can get a good overview of how things are looking during development.\n\n\nAnd speaking of systems, Mark Norman Francis recommends the use of measuring tools to aid the design process; \u201c[U]se analytics and make decisions from actual data\u201d he suggests, rather than relying totally on intuition.\n\nTim Kadlec adds a word on performance planning:\n\n\n\tI think having a performance budget in place should now be a given on any project. We\u2019ve proven pretty conclusively through a hundred and one case studies that performance matters. And over the last year or so, we\u2019ve really seen a lot of great tools emerge to help track and enforce performance budgets. There\u2019s not really a good excuse for not using one any more.\n\n\nIt\u2019s clear that in the four years since Ethan Marcotte\u2019s Responsive Web Design article the diversity of screen sizes, network connection speeds and input methods has only increased. New web projects should presume visitors will be using anything from a watch up to a big screen desktop display, and from being offline, through to GPRS, 3G and fast broadband.\n\nWill it take more time to design and build for those constraints? Yes, it most likely will. If Internet Explorer is brave enough to ask to be your default browser, you can be brave enough to tell your client they need to build responsively.\n\nWorking collaboratively\n\nA big part of delivering a successful website project is how we work together, both as a design team and a wider project team with the client.\n\nVal Head recommends an open line of communication:\n\n\n\tKeep conversations going. With clients, with teammates. Talking is so important with the way we work now. A good team conversation place, like Slack, is slowly becoming invaluable for me too.\n\n\nRuth John agrees:\n\n\n\tWe\u2019ve recently opened up our lines of communication by using Slack. It has transformed the way we work. We\u2019re easily more productive and collaborative on projects, as well as making it a lot easier for us all to work remotely (including freelancers).\n\n\nShe goes on to point out how tools can be combined to ease team communication without adding further complications:\n\n\n\tWe have a private GitHub organisation (which everyone who works with us is granted access to), which not only holds all our project code but also a team wiki. This has lots of information to get you set up within the team, as well as coding guidelines and best practices and other admin info, like contact numbers/emails for the team.\n\n\nSmall-A agile is also the theme of the day, with Mark Norman Francis suggesting an approach of \u201csmall iterations with constant feedback around individual features, not spec-it-all-first\u201d. He also encourages you to review as you go, at each stage of the project:\n\n\n\tAlways reflect on what went well and what went badly, and how you can learn from that, even if not Doing Agile\u2122. Ultimately \u201cbest practices\u201d should come from learning lessons (both good and bad).\n\n\nRichard Rutter echoes this, warning against working in isolation from the client for too long:\n\n\n\tAvoid big reveals. Your engagement with the client should be participatory. In business no one likes surprises.\n\n\nThis experience rings true for Ruth John who recommends involving real users in the feedback loop, not just the client:\n\n\n\tWe also try and get feedback on what we\u2019re building as soon and as often as we can with our stakeholders/clients and real users.\n\n\nWe should also remember that our role is to serve the client\u2019s needs, not just bill them for whatever we can. Brian Suda adds:\n\n\n\tDon\u2019t sell clients on things they don\u2019t need. We can spout a lot of jargon and scare clients into thinking you are a god. We can do things few can now, but you can\u2019t rip people off because they are unknowledgeable.\n\n\nBut do clients know what they\u2019re getting, even when they see it? Trent Walton has an interesting take:\n\n\n\tWe focus on prototypes over image-based comps at all costs, especially when meetings are involved. It\u2019s much easier to assess a prototype, and too often with image-based comps, discussions devolve into how something might feel when actually live, or how a layout could change to fit a given viewport.\n\n\nVal Head also likes to get work into the browser:\n\n\n\tSketch design ideas with any software you like, but get to the browser as soon as possible.\n\n\nBeyond your immediate team, Emma Jane Westby has advice for looking further afield:\n\n\n\tInvest time into building relationships within your (technical) community. You never know when you might be able to lend a hand; or benefit from someone who\u2019s able to lend theirs.\n\n\nAnd when things don\u2019t go according to plan, Brian Suda has the following advice:\n\n\n\tIf something doesn\u2019t work out, be professional and don\u2019t burn bridges. It will always come back to you.\n\n\nThe best work comes from working collaboratively, not just as a team within an agency or department, but with the client and stakeholders too. If doing your job and chucking it over the fence ever worked, it certainly doesn\u2019t fly any more. You can work in isolation, but doing really great work requires collaboration.\n\nThe business end\n\nWhen you\u2019re building sites professionally, every team member has to think about the business aspects. Estimating time, setting billing rates, and establishing deliverables are all part of the job.\n\nIn 2008, Andrew Clarke gave us the Contract Killer sample contract we could use to establish a working agreement for a web design project. Richard Rutter agrees that contracts are still an essential part of business:\n\n\n\tThey are there for both parties\u2019 protection. Make sure you know what will happen if you decide you don\u2019t want to work with the client any more (it happens) and, of course, what circumstances mean they can stop taking your services.\n\n\nHaving a contract is one thing, but does it adequately protect both you and the client? Emma Jane Westby adds:\n\n\n\tFind a good IP lawyer/legal counsel. I routinely had an IP lawyer read all of my contracts to find loopholes I wouldn\u2019t have noticed. I didn\u2019t always change the contract, but at least I knew what might come back to bite me.\n\n\nSo, you have a contract in place, and know what the project is. Brian Suda recommends keeping track of time and making sure you bill fairly for the hours the project costs you:\n\n\n\tIf I go to a meeting and they are 15 minutes late, the billing clock has already started. They can\u2019t expect me to be in the 1h meeting and not bill for the extra 15\u201330 minutes they wasted. It goes both ways too. You need to do your best to respect their deadlines and time frame \u2013 this is always hard to get right.\n\n\nAs ever, it\u2019s good business to do good business. Perhaps we can at last shed the old image of web designers being snowboarding layabouts and demonstrate to clients that we care as much about conducting professional business as they do.\n\nTime to review\n\nIt\u2019s a lot to take in. Some of these ideas and practices will be familiar, others new and yet to be evaluated. The web moves at a fast pace, and we need to be constantly reexamining our tools, techniques and working practices. The most important thing is not to blindly adopt any and all suggestions, but to carefully look at what the benefits might be and decide how they apply to your work.\n\nCould you benefit from more formalised development and deployment procedures? Would your design projects run more smoothly and have a longer maintainable life if you approached the solution as a componentised system rather than a series of pages? Are your teams structured in a way that enables the most fluid communication, or are there changes you could make? Are your billing procedures and business agreements serving you and your clients in the best way possible?\n\nThe new year is a good time to look at your working practices and see what can be improved, and maybe this time next year you\u2019ll look back and think \u201cthank goodness we don\u2019t work like that any more\u201d.", "year": "2014", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2014-12-01T00:00:00+00:00", "url": "https://24ways.org/2014/what-it-takes-to-build-a-website/", "topic": "business"} {"rowid": 35, "title": "SEO in 2015 (and Why You Should Care)", "contents": "If your business is healthy, you can always find plenty of reasons to leave SEO on your to-do list in perpetuity. After all, SEO is technical, complicated, time-consuming and potentially dangerous. The SEO industry is full of self-proclaimed gurus whose lack of knowledge can be deadly. There\u2019s the terrifying fact that even if you dabble in SEO in the most gentle and innocent way, you might actually end up in a worse state than you were to begin with.\n\nTo make matters worse, Google keeps changing the rules. There have been a bewildering number of major updates, which despite their cuddly names have had a horrific impact on website owners worldwide.\n\nFear aside, there\u2019s also the issue of time. It\u2019s probably tricky enough to find the time to read this article. Setting up, planning and executing an SEO campaign might well seem like an insurmountable obstacle.\n\nSo why should you care enough about SEO to do it anyway?\n\nThe main reason is that you probably already see between 30% and 60% of your website traffic come from the search engines. That might make you think that you don\u2019t need to bother, because you\u2019re already doing so well. But you\u2019re almost certainly wrong.\n\nIf you have a look through the keyword data in your Google Webmaster Tools account, you\u2019ll probably see that around 30\u201350% of the keywords used to find your website are brand names \u2013 the names of your products or companies. These are searches carried out by people who already know about you. But the people who don\u2019t know who you are but are searching for what you sell aren\u2019t finding you right now. This is your opportunity.\n\nIf a person goes looking for a company or product by name, Google will steer them towards what they\u2019re looking for. Their intelligence does have limits, however, and even though they know your name they won\u2019t be completely clear about what you sell. That\u2019s where SEO would come in.\n\nStill need more convincing? How about the fact that the seeming complexities of SEO mean that your competition are almost certainly neglecting it too. They have the same reservations as you about complexity, time and danger, and hopefully they aren\u2019t reading this article and so are none the wiser of the well-kept secret: that 70% of SEO is easy.\n\nI\u2019m going to lead you through what you need to do to tap into that stream of people looking for what you sell right now.\n\nWhat is real SEO?\n\nReal SEO is all about helping Google understand the content of your website. It\u2019s about steering, guiding and assisting Google. Not manipulating it.\n\nIt\u2019s easy to assume that Google already understands the content and relevance of each and every page on your website, but the fact is that it needs a fair amount of hand-holding. Fortunately, helping Google along really isn\u2019t very difficult at all.\n\nRest assured that real SEO has nothing to do with keyword stuffing, keyword density, hacks, tricks or cunning techniques. If you hear any of these terms from your SEO advisor, run away from them as quickly as you can.\n\nUnderstanding your current situation \u2013 Google Analytics\n\nBefore you can do anything to improve your SEO status, you need to get an idea of how you\u2019re already doing. Below is a very quick and easy way of doing so.\n\n1. Open up your Google Analytics account.\n\n2. Click on the date range selector on the top-right of the interface and change the year of the first date to last year. So 12 Dec 2014 will become 12 Dec 2013. Then click on Apply.\n\n3. Click on the All Sessions rectangle towards the top-left, click once on Organic Traffic and click Apply.\n\n4. Click the little black-and-white squares icon that has now appeared under the date selector on the top-right, and drag the slider all the way over to Higher Precision.\n\n5. Change the interval buttons on the top-right of the graph to Week to make this easier to digest.\n\nAt this point your graph should look something like this:\n\n\n\nIt\u2019s worth noting the approximate proportion of your visitors that currently come from organic sources.\n\n6. Click the little downwards arrow to the right of the All Sessions rectangle and choose Remove, so that we\u2019re only looking at the organic traffic on its own.\n\n7. Click on Select a metric next to the Sessions button above the graph and select Pages / Session. You should then see something like this:\n\n\n\nIn the example above we can see that the quantity of traffic has been increasing since the middle of August, but the quality of the traffic (as measured by the number of pages per session) has fallen significantly. \n\nHow you choose to view this is down to your own graph, recent history and interpretation of events, but this should give you an indication of how things stand at the present time. Trends are often much more revealing than a snapshot of a brief moment in time.\n\nYour Google Webmaster Tools data\n\nIf you\u2019re not very familiar with your Google Webmaster Tools account, it\u2019s really worth taking ten to fifteen minutes to see what\u2019s on offer. I can\u2019t recommend this enough. From the point of view of an SEO health check, I\u2019d advise you to look into the HTML Improvements, Crawl Errors and Crawl Stats, and most importantly the Search Queries.\n\nFrom what you see here and the trends shown in your Analytics data, you should now have a good idea of your current status. If you want to explore further, I recommend Screaming Frog as a good diagnostics tool, or Botify if your website is large or unusually complex.\n\nCombining the data into something useful\n\nYour Google Analytics session will have shown you how you\u2019re doing from an SEO point of view in terms of the quantity and, to some extent, the quality of your visitors. But it\u2019s only showing you what is already working. In other words: the people who are finding you on the search engines, and clicking on your links.\n\nThe Google Webmaster Tools search query data, on the other hand, will give you a better idea of what isn\u2019t working. It will show you the keyword searches that are getting you listed in the results, but which aren\u2019t necessarily getting clicked. And it doesn\u2019t take much by the way of expertise to see why.\n\nFor example, if you see your targeted keyword, which you feel is extremely relevant, has generated over 2,000 impressions in the last month but produced only two clicks, you\u2019ll probably find a very low average position. Bear in mind that an average position of fourteen will mean being around halfway down the second page of results. Think about how rarely you go beyond the first two or three listings, never mind to the second page of results, and you\u2019ll understand why the click-through rate is so low.\n\nSo now you have an idea of what you\u2019re being found for at the present time. But what about the other terms?\n\nWhat would you like to be found for?\n\nThis is one of the more common SEO mistakes, on a number of different levels. \n\nMany businesses assume that they don\u2019t need to worry about keyword research. They think they know what terms people use to find what they sell, and they also assume that Google understands the content on their website. This is incorrect on all counts.\n\nA better starting point is to brainstorm a small number of your most obvious keywords, then run them through Google\u2019s Keyword Planner. Ignore the information in the Ad group ideas tab, and instead go straight to the Keyword ideas tab. Rather than wade through the very unfriendly interface, I recommend downloading the data as a spreadsheet, in which not only is more detail included, but you can also slice, dice, sort and report the data as required.\n\nFrom there you can delete all the irrelevant columns, and start working your way through the list, deleting any irrelevant keywords as you go along.\n\nIt\u2019s around this stage that you may hit a problem in terms of where to focus your efforts. The number of reported searches for a given keyword is of course important, but so is the level of competition. Ideally, you\u2019d like keywords with plenty of searches but not too much competition.\n\nI personally like to factor both together by adding a column that simply divides the number of searches squared by the level of competition:\n\n(number of searches \u00d7 number of searches) \u00f7 competition\n\nThere are plenty of alternatives to this basic formula, but I like it for ease of use and simplicity. Once I\u2019ve added this column, I then sort the data by this value (largest to smallest) and I then only usually need ten to fifteen keywords at most to give me plenty of ideas to work with.\n\nThis is a slightly involved but effective methodology for keyword research, as what you\u2019re left with is a list of keywords that both Google and you consider to be relevant to the content of your website. And relevance is an important concept in SEO.\n\nReal SEO keyword research is about making sure that your customers, website and Google are all in agreement and alignment over the content of your website. Other sources of inspiration and ideas include having a look at what terms your competition are targeting, Google Trends and, of course, Google Suggest. If you\u2019re not sure where to find these things, you can probably work out where to search for them!\n\nIf you want to dive further into understanding your current search engine status, search for some of the better keywords that you just discovered and see where you rank compared to your competition. Note that it\u2019s vital to avoid Google serving up personalised results, so either use the privacy, incognito or anonymous mode of your browser for the searches, or use a browser that you don\u2019t normally use. I hope this is Internet Explorer. If what you find isn\u2019t great, don\u2019t despair: everything in SEO is fixable (terms and conditions may apply).\n\nPutting it all together\n\nYou should now have a good idea of where things stand with your current search engine traffic, and a solid list of keywords that you\u2019re not getting visitors for but very much want.\n\nAll that\u2019s left now is to work out how to use these keywords. But before we do, let\u2019s take a quick step back.\n\nIf you have in any way kept up with what\u2019s been happening in SEO over the last couple of years, you\u2019ll have probably heard about Google updates with names like Panda, Hummingbird, Phantom, Pirate and more.\n\nI won\u2019t go into the technical details of what Google is doing, but it is important to understand why they\u2019re trying to do it. At the most basic level, Google understands that there\u2019s a very real problem with people who are trying manipulate its index. In response to this, Google is trying to clean up its results. They don\u2019t want people getting fed up with bad results and considering other options \u2013 have you even tried Bing?\n\nThis is extremely important. Remember earlier when I said that 70% of SEO was easy? That rule still applies. So, for example, if you have a list of keywords that you know are relevant to what you sell, then all you need to do is create great content for them. Incredibly, that\u2019s all there is to it (terms and conditions apply again, unfortunately \u2013 see below).\n\nThere is, however, one simple rule to be consistently followed without exception: that the content you create should not only be good quality and completely original, but it should also be written primarily for the human visitor and not the search engine spider.\n\nIn other words, if you create some fantastic content for a keyword like \u201cchoosing a small business HR service\u201d, then the article should not only make perfect sense if read out loud (as opposed to the same phrase being repeated fifteen times), but also provide real value to the person reading it.\n\nSo the process is simple:\n\n\n\tChoose your keywords\n\tCreate spectacular content\n\n\nWait. Is it really that simple?\n\nUnfortunately there\u2019s a lot more to the other 30% of SEO than just creating great content and waiting for the visitors. There are issues like helping Google understand the content on your pages and website, incoming links, page authority, domain authority, usage patterns, spam factors, canonical issues and much more.\n\nBut there\u2019s the often overlooked fact about Google: it actually does a reasonable job of working out what\u2019s on your website and (to some extent) understanding the gist of it. If you\u2019ve never done any SEO on your website but still get some traffic from Google, this is why.\n\nEven without dabbling in the other 30% of SEO, by creating the right content for the right visitors using the precise language and terminology that your potential customers are using, you\u2019re significantly better off than your competition. And you can only gain from this.\n\nWhen you\u2019ve checked this off your to-do list and made it an ingrained part of your content creation process, then you\u2019re ready to delve into the other 30% of SEO. The not-so-easy side.\n\nUntil then, work on understanding your current situation, exploring the opportunities, creating a list of good keywords, creating the right content for them, and starting 2015 with a little bit of smart, safe and real SEO.", "year": "2014", "author": "Dave Collins", "author_slug": "davecollins", "published": "2014-12-15T00:00:00+00:00", "url": "https://24ways.org/2014/seo-in-2015-and-why-you-should-care/", "topic": "business"} {"rowid": 40, "title": "Don\u2019t Push Through the Pain", "contents": "In 2004, I lost my web career. In a single day, it was gone. I was in too much pain to use a keyboard, a Wacom tablet (I couldn\u2019t even click the pen), or a trackball. Switching my mouse to use my left (non-dominant) hand only helped a bit; then that hand went, too. I tried all the easy-to-find equipment out there, except for expensive gizmos with foot pedals. I had tingling in my fingers\u2014which, when I was away from the computer, would rhythmically move as if some other being controlled them. I worried about Parkinson\u2019s because the movements were so dramatic. Pen on paper was painful. Finally, I discovered one day that I couldn\u2019t even turn a doorknob.\n\nThe only highlight was that I couldn\u2019t dust, scrub, or vacuum. We were forced to hire someone to come in once a week for an hour to whip through the house. You can imagine my disappointment. \n\nMy injuries had gradually slithered into my life without notice. I\u2019d occasionally have sore elbows, or my wrist might ache for a day, or my shoulders feel tight. But nothing to keyboard home about. That\u2019s the critical bit of news. One day, you\u2019re pretty fine. The next day, you don\u2019t have your job\u2014or any job that requires the use of your hands and wrists. \n\nI had to walk away from the computer for over four months\u2014and partially for several months more. That\u2019s right: no income. If I hadn\u2019t found a gifted massage therapist, the right book of stretches, the equipment I should have been using all along, and learned how to pay attention to my body\u2014even just a little bit more\u2014I quite possibly wouldn\u2019t be writing this article today. I wouldn\u2019t be writing anything, anywhere. \n\nMost of us have heard of (and even claimed to have read all of) Mihaly Csikszentmihalyi, author of Flow: The Psychology of Optimal Experience, who describes the state of flow\u2014the place our minds go when we are fully engaged and in our element. This lovely state of highly focused activity is deeply satisfying, often creative, and quite familiar to many of us on the web who just can\u2019t quit until the copy sings or the code is untangled or we get our highest score yet in Angry Birds. Our minds may enter that flow, but too often as our brains take flight, all else recedes. And we leave something very important behind. \n\nOur bodies. \n\nMy body wasn\u2019t made to make the same minute movements thousands of times a day, most days of the year, for decades, and neither was yours. The wear and tear sneaks up on you, especially if you\u2019re the obsessive perfectionist that we all pretend not to be. Oh? You\u2019re not obsessed? I wasn\u2019t like this all the time, but I remember sitting across from my husband, eating dinner, and I didn\u2019t hear a word he said. I\u2019d left my brain upstairs in my office, where it was wrestling in a death match with the box model or, God help us all, IE 5.2. I was a writer, too, and I was having my first inkling that I was a content strategist. Work was exciting. I could sit up late, in the flow, fingers flying at warp speed. I could sit until those wretched birds outside mocked me with their damn, cheerful \u201cHurray, it\u2019s morning!\u201d songs. Suddenly, while, say, washing dishes, the one magical phrase that captured the essence of a voice or idea would pop up, and I would have mowed down small animals and toddlers to get to my computer and hammer out that website or article, to capture that thought before it escaped. Note my use of the word hammer. Sound at all familiar? \n\nBut where was my body during my work? Jaw jutting forward to see the screen, feet oddly positioned\u2014and then left in place like chunks of marble\u2014back unsupported, fingers pounding the keys, wrists and arms permanently twisted in unnatural angles that we thought were natural. And clicking. Clicking, clicking, clicking that mouse. Thumbing tiny keyboards on phones. A lethal little gesture for tiny little tendons. Though I was fine from, say 1997 to 2004, by the end of 2004 this behavior culminated in disaster. I had repetitive stress injuries, aka repetitive motion injuries. As the Apple site says, \u201cA brief exposure to these conditions would not cause harm. But a prolonged exposure may, in some people, result in reduced ability to function.\u201d I\u2019ll say. \n\nI frantically turned to people on lists and forums. \u201cTry a track ball.\u201d Already did that. \u201cTry a tablet.\u201d Worse. One person wrote, \u201cI still come here once in a while and can type a couple sentences, but I\u2019ve permanently got thoracic outlet syndrome and I\u2019ll never work again.\u201d Oh, beauteous web, oh, long-distance friends, farewell. \n\nThe Wrist Bone\u2019s Connected to the Brain Bone\n\nThat variation on the old song tells part of the story. Most people (and many of their physicians) believe that tingling fingers and aching wrists MUST be carpel tunnel syndrome. Nope. If your neck juts forward, it tenses and stays tense the entire time you work in that position. Remember how your muscles felt after holding a landline phone with your neck tilted to one side for a long client meeting? Regrettable. Tensing your shoulders because your chair\u2019s not designed properly puts you at risk for thoracic outlet syndrome, a career-killer if ever there was one. The nerves and tendons in your neck and shoulder refer down your arms, and muscles swell around nerves, causing pain and dysfunction. Your elbows have a tendon that is especially vulnerable to repetitive movements (think tennis elbow). Your wrists are performing something akin to a circus act with one thousand shows a day. \n\nSo, all the fine tendons and ligaments in your fingers have problems that may not start at your wrists at all. Though some people truly do have carpal tunnel syndrome, my finger and wrist problems weren\u2019t solved by heavily massaging my fingers (though, that was helpful, too) or my wrists. They were fixed by work on my neck, upper back, shoulders, arms, and elbows. This explains why many people have surgery for carpal tunnel syndrome and just months later say, \u201cWhat?! How can I possibly have it again? I had an operation!\u201d Well, fellow buckaroo, you may never have had carpel tunnel syndrome. You may have had\u2014or perhaps will have\u2014one long disaster area from your neck to your fingertips. \n\nHow to Crawl Back \n\nBefore trying extreme measures, you may be able to function again even if you feel hopeless. I managed to heal, and so have others, but I\u2019ll always be at risk. \n\nAs Jen Simmons, of The Web Ahead podcast and other projects told me, \u201cIt took a long time to injure myself. It took a long time to get back to where I was. My right arm between my elbow and wrist would start aching intermittently. Eventually, my arm even ached at night. I started each day with yesterday\u2019s pain.\u201d Simple measures, used consistently, helped her back. \n\n1. Massage therapy\n\nI don\u2019t remember what the rest of the world is like, but in Portland, Oregon, we have more than one massage therapy college. (Of course we do.) I saw a former teacher at the most respected school. This is not your \u201cIt was all so soothing. Why, I fell asleep!\u201d massage. This is \u201cHoly crap, he\u2019s grinding his elbow into my armpit!\u201c massage therapy, with the emphasis on therapy. I owe him everything. Make sure you have someone who really knows what they\u2019re doing. Get many referrals. Try a question, \u201cDoes my psoas muscle affect my back?\u201d If they can\u2019t answer it, flee. Regularly see the one you choose and after a while, depending on how injured you are, you may be able to taper off. \n\n2. Change your equipment\n\nYou may need to be hands-on with several pieces of equipment before you find the ones that don\u2019t cause more pain. Many companies have restocking fees, charges to ship the equipment you want to return, and other retail atrocities. Always be sure to ask what the return policies are at any company before purchasing.\n\nMice \n\nYou may have more success than I did with equipment such as the Wacom tablet. Mine came with a pen, and it hurt to repetitively click it. Trackballs are another option but, for many, they are better at prevention than recovery. But let\u2019s get to the really effective stuff. One of the biggest sources of pain is using your mouse. One major reason is that your hand and wrist are in a perpetually unnatural position and you\u2019re also moving your arm quite a bit. Each time you move the mouse, it is placing stress on your neck, shoulders and arms, because you need to lift them slightly in order to move the mouse and you need to angle your wrist. You may also be too injured to use the trackpad all the time, and this mouse, the vertical mouse is a dandy preventative measure, too. Shaking up your patterns is a wise move. I have long fingers, not especially thin, yet the small size works best for me. (They have larger choices available.) What?! A sideways mouse? Yep. All the weight of your hand will be resting on it in the handshake position. Your forearms aren\u2019t constantly twisting over hill and dale. You aren\u2019t using any muscles in your wrist or hand. They are relaxing. You\u2019ll adapt in a day, and oh, oh, what a relief it is. \n\nKeyboards\n\nI really liked doing business with the people at Kinesis-Ergo. (I\u2019m not affiliated with them in any way.) They have the vertical mouse and a number of keyboards. The one that felt the most natural to me, and, once again, it only takes a day to adapt, is the Freestyle2 for the Mac. They have several options. I kept the keyboard halves attached to each other at first, and then spread them apart a little more. I recommend choosing one that slants and can separate. You can adjust the angle. For a little extra, they\u2019ll make sure it\u2019s all set up and ready to go for you. I\u2019m guessing that some Googling will find you similar equipment, wherever you live. \n\nWarning: if you use the ergonomic keyboards, you may have fewer USB ports. The laptop will be too far away to see unless you find a satisfactory setup using a stand. This is the perfect excuse for purchasing a humongous display. \n\nYou may not look cool while jetting coast to coast in your skinny jeans and what appears to be the old-time orthopedic shoe version of computing gear. But once you have rested and used many of these suggestions consistently, you may be able to use your laptop or other device in all its lovely sleekness during the trip. \n\nOther doohickies\n\nThe Kinesis site and The Human Solution have a wide selection of ergonomic products: standing desks, ergonomically correct chairs, and, yes, even things with foot pedals. Explore! \n\n3. Stop clicking, at least for a while\n\nUse keyboard shortcuts, but use them slowly. This is not the time to show off your skillz. You\u2019ll be sort of like a recovering alcoholic, in that you\u2019ll be a recovering repetitive stress survivor for the rest of your life, once you really injure yourself. Always be vigilant. There\u2019s also a bit of software sold by The Human Solution and other places, and it was my salvation. It\u2019s called the McNib for Macs, and the Nib for PCs. (I\u2019ve only used the McNib.) It\u2019s for click-free mousing. I found it tricky to use when writing markup and code, but you may become quite adept at it. A little rectangle pops up on your screen, you mouse over it and choose, let\u2019s say, \u201cDouble-click.\u201d Until you change that choice, if you mouse over a link or anything else, it will double-click it for you. All you do is glide your mouse around. Awkward for a day or two, but you\u2019ll pick it up quickly. Though you can use it all day for work, even if you just use this for browsing LOLcats or Gary Vaynerchuk\u2019s YouTube videos, it will help you by giving your fingers a sweet break. \n\nBut here\u2019s the sad news. The developer who invented this died a few years ago. (Yes, I used to speak to him on the phone.) While it is for sale, it isn\u2019t compatible with Mac OS X Lion or anything subsequent. PowerPC strikes again. His site is still up. Demos for use with older software can be downloaded free at his old site, or at The Human Solution. Perhaps an enterprising developer can invent something that would provide this help, without interfering with patents. Rumor has it among ergonomic retailers (yes, I\u2019m like a police dog sniffing my way to a criminal once I head down a trail) that his company was purchased by a company in China, with no update in sight. \n\n4. Use built-in features\n\nThat little microphone icon that comes up alongside the keyboard on your iPhone allows you to speak your message instead of incessantly thumbing it. I believe it works in any program that uses the keyboard. It\u2019s not Siri. She\u2019s for other things, like having a personal relationship with an inanimate object. Apple even has a good section on ergonomics. You think I\u2019m intense about this subject? To improve your repetitive stress, Apple doesn\u2019t want you to use oral contraceptives, alcohol, or tobacco, to which I say, \u201cHave as much sex, bacon, and chocolate as possible to make up for it.\u201d \n\nApple\u2019s info even has illustrations of things like a faucet dripping into what is labeled a bucket full of \u201cTRAUMA.\u201d Sounds like upgrading to Yosemite, but I digress. \n\n5. Take breaks \n\nIf it\u2019s a game or other non-essential activity, take a break for a month. Fine, now that I\u2019ve called games non-essential, I suppose you\u2019ll all unfollow me on Twitter. \n\n6. Whether you are sore or not, do stretches throughout the day \n\nThis is a big one. Really big. The best book on the subject of repetitive stress injuries is Conquering Carpal Tunnel Syndrome and Other Repetitive Strain Injuries: A Self-Care Program by Sharon J. Butler. Don\u2019t worry, most of it is illustrations. Pretend it\u2019s a graphic novel. \n\nI\u2019m notorious for never reading instructions, and who on earth reads the introduction of a book, unless they wrote it? I wrote a book a long time ago, and I bet my house, husband, and life savings that my own parents never read the intro. Well, I did read the intro to this book, and you should, too. Stretching correctly, in a way that doesn\u2019t further hurt you, that keeps you flexible if you aren\u2019t injured, that actually heals you, calls for precision. Read and you\u2019ll see. The key is to stretch just until you start to feel the stretch, even if that\u2019s merely a tiny movement. Don\u2019t force anything past that point. Kindly nurse yourself back to health, or nurture your still-healthy body by stretching. Over the following days, weeks, months, you\u2019ll be moving well past that initial stretch point. \n\nThe book is brimming with examples. You only have to pick a few stretches, if this is too much to handle. Do it every single day. I can tell you some of the best ones for me, but it depends on the person. You\u2019ll also discover in Butler\u2019s book that areas that you think are the problem are sometimes actually adjacent to the muscle or tendon that is the source of the problem. Add a few stretches or two for that area, too. \n\nBut please follow the instructions in the introduction. If you overdo it, or perform some other crazy-ass hijinks, as I would be tempted to do, I am not responsible for your outcome. I give you fair warning that I am not a healthcare provider. I\u2019m just telling you as a friend, an untrained one, at that, who has been through this experience. \n\n7. Follow good habits\n\nDevelop habits like drinking lots of water (which helps with lactic acid buildup in muscles), looking away from the computer for twenty seconds every twenty to thirty minutes, eating right, and probably doing everything else your mother told you to do. Maybe this is a good time to bring up flossing your teeth, and going outside to play instead of watching TV. As your mom would say, \u201cIt\u2019s a beautiful day outside, what are you kids doing in here?\u201d \n\n8. Speak instead of writing, if you can \n\nAmber Simmons, who is very smart and funny, once tweeted in front of the whole world that, \u201c@carywood is a Skype whore.\u201d I was always asking people on Twitter if we could Skype instead of using iChat or exchanging emails. (I prefer the audio version so I don\u2019t have to, you know, do something drastic like comb my hair.) Keyboarding is tough on hands, whether you notice it or not at the time, and when doing rapid-fire back-and-forthing with people, you tend to speed up your typing and not take any breaks. This is a hand-killer. Voice chats have made such a difference for me that I am still a rabid Skype whore. Wait, did I say that out loud? \n\nSpeak your text or emails, using Dragon Dictate or other software. In about 2005, accessibility and user experience design expert, Derek Featherstone, in Canada, and I, at home, chatted over the internet, each of us using a different voice-to-text program. The programs made so many mistakes communicating with each other that we began that sort of endless, tearful laughing that makes you think someone may need to call an ambulance. This type of software has improved quite a bit over the years, thank goodness. Lack of accessibility of any kind isn\u2019t funny to Derek or me or to anyone who can\u2019t use the web without pain. \n\n9. Watch your position \n\nFor example, if you lift up your arms to use the computer, or stare down at your laptop, you\u2019ll need to rearrange your equipment. The internet has a lot of information about ideal ergonomic work areas. Please use a keyboard drawer. Be sure to measure the height carefully so that even a tented keyboard, like the one I recommend, will fit. I also recommend getting the version of the Freestyle with palm supports. Just these two measures did much to help both Jen Simmons and me. \n\n10. If you need to take anti-inflammatories, stop working\n\nIf you are all drugged up on ibuprofen, and pounding and clicking like mad, your body will not know when you are tired or injuring yourself. I don\u2019t recommend taking these while using your computing devices. Perhaps just take it at night, though I\u2019m not a fan of that category of medications. Check with your healthcare provider. At least ibuprofen is an anti-inflammatory, which may help you. In contrast, acetaminophen (paracetamol) only makes your body think it\u2019s not in pain. Ice is great, as is switching back and forth between ice and heat. But again, if you need ice and ibuprofen you really need to take a major break. \n\n11. Don\u2019t forget the rest of your body\n\nI\u2019ve zeroed in on my personal area of knowledge and experience, but you may be setting yourself up for problems in other areas of your body. There\u2019s what is known to bad writers as \u201ca veritable cornucopia\u201d of information on the web about how to help the rest of your body. A wee bit of research on the web and you\u2019ll discover simple exercises and stretches for the rest of your potential catastrophic areas: your upper back, your lower back, your legs, ankles, and eyes. Do gentle stretches, three or four times a day, rather than powering your way through. Ease into new equipment such as standing desks. Stretch those newly challenged areas until your body adapts. Pay attention to your body, even though I too often forget mine. \n\n12. Remember the children\n\nKids are using equipment to play highly addictive games or to explore amazing software, and if these call for repetitive motions, children are being set up for future injuries. They\u2019ll grab hold of something, as parents out there know, and play it 3,742 times. That afternoon. Perhaps by the time they are adults, everything will just be holograms and mind-reading, but adult fingers and hands are used for most things in life, not just computing devices and phones with keyboards sized for baby chipmunks. \n\nI\u2019ll be watching you\n\nQuickly now, while I (possibly) have your attention. Don\u2019t move a muscle. Is your neck tense? Are you unconsciously lifting your shoulders up? How long since you stopped staring at the screen? How bright is your screen? Are you slumping (c\u2019mon now, \u2018fess up) and inviting sciatica problems? Do you have to turn your hands at an angle relative to your wrist in order to type? Uh-oh. That\u2019s a bad one. Your hands, wrists, and forearms should be one straight line while keyboarding. Future you is begging you to change your ways. Don\u2019t let your #ThrowbackThursday in 2020 say, \u201cHere\u2019s a photo from when I used to be able to do so many wonderful things that I can\u2019t do now.\u201d And, whatever you do, don\u2019t try for even a nanosecond to push through the pain, or the next thing you know, you\u2019ll be an unpaid extra in The Expendables 7.", "year": "2014", "author": "Carolyn Wood", "author_slug": "carolynwood", "published": "2014-12-06T00:00:00+00:00", "url": "https://24ways.org/2014/dont-push-through-the-pain/", "topic": "business"} {"rowid": 44, "title": "Taglines and Truisms", "contents": "To bring her good luck, \u201cwhite rabbits\u201d was the first thing that my grandmother said out loud on the first day of every month. We all need a little luck, but we shouldn\u2019t rely on it, especially when it comes to attracting new clients.\n\nThe first thing we say to a prospective client when they visit our website for the first time helps them to understand not only what we do but why we do it. We can also help them understand why they should choose to work with us over one of our competitors.\n\nTake a minute or two to look at your competitors\u2019 websites. What\u2019s the first thing that they say about themselves? Do they say that they \u201cdesign delightful digital experiences,\u201d \u201ccraft beautiful experiences\u201d or \u201ccreate remarkable digital experiences?\u201d\n\nIt\u2019s easy to find companies who introduce themselves with what they do, their proposition, but what a company does is only part of their story. Their beliefs and values, what they stand for why they do what they do are also important. \n\nWhen someone visits our websites for the first time, we have only a brief moment to help them understand us. To help us we can learn from the advertising industry, where the job of a tagline is to communicate a concept, deliver a message and sell a product, often using only a few words.\n\nWhen an advertising campaign is effective, its tagline stays with you, sometimes long after that campaign is over. For example, can you remember which company or brand these taglines help to sell? (Answers at the bottom of the article:)\n\n\nThe Ultimate Driving Machine\nJust Do It\nDon\u2019t Leave Home Without It\n\n\nA clever tagline isn\u2019t just a play on words, although it can include one. A tagline does far more than help make your company memorable. Used well, it brings together notions of what makes your company and what you offer special. Then it expresses those notions in a few words or possibly a short sentence. \n\nI\u2019m sure that everyone can find examples of company slogans written in the type of language that should stay within the walls of a marketing department. We can also find taglines where the meaning is buried so deep that the tag itself becomes effectively meaningless.\n\nA meaningful tagline supports our ideas about who we are and what we offer, and provides a platform for different executions of them, sometimes over a period of time. For a tagline to work well, it must allow for current and future ideas about a brand.\n\nIt must also be meaningful to our brand and describe a truism, a truth that need not be a fact or statistic, but something that\u2019s true about us, who we are, what we do and why that\u2019s distinctive. It can be obvious, funny, serious or specific but above all it must be true. It should also be difficult to argue with, making your messages difficult to argue with too.\n\nI doubt that I need remind you who this tagline belongs to:\n\n\n\tThere are some things money can\u2019t buy. For everything else there\u2019s MasterCard.\n\n\nThat tagline was launched in 1997 by McCann-Erickson along with the \u201cPriceless\u201d campaign and it helped establish MasterCard as a friendlier credit card company, one with a sense of humour. \n\nMasterCard\u2019s truism is that the things which really matter in life can\u2019t be bought. They are worth more than anything that a monetary value can be applied to. In expressing that truism through the tagline, MasterCard\u2019s advertising tells people to use not just any credit card, but their MasterCard, to pay for everything they buy.\n\n\u201cGuinness is good for you\u201d may have been a stretch, but \u201cGood things come to those who wait\u201d builds on the truism that patience is a virtue and therefore a good pint of Guinness takes time to pour (119.5 seconds. I know you were wondering.)\n\nThe fact that British Airways flies to more destinations than any other airline is their truism, and led their advertisers to the now famous tagline, \u201cThe world\u2019s favourite airline.\u201d\n\n\n\nAt my company, Stuff & Nonsense, we\u2019ve been thinking about taglines as we think about our position within an industry that seems full of companies who \u201cdesign\u201d, \u201ccraft\u201d, and \u201ccreate\u201d \u201cdelightful\u201d, \u201cbeautiful\u201d, \u201cremarkable digital experiences\u201d.\n\nMuch of what made us different has changed along with the type of work we\u2019re interested in doing. Our work\u2019s expanded beyond websites and now includes design for mobile and other media. It\u2019s true we can\u2019t know how or where it will be seen. The ways that we make it are flexible too as we\u2019re careful not to become tied to particular tools or approaches. \n\nIt\u2019s also true that we\u2019re a small team. One that\u2019s flexible enough to travel around the world to work alongside our clients. We join their in-house teams and we collaborate with them in ways that other agencies often find more difficult. We know that our clients appreciate our flexibility and have derived enormous value from it. We know that we\u2019ve won business because of it and that it\u2019s now a big part of our proposition.\n\nOur truism is that we\u2019re flexible, \u201cFabulously flexible\u201d as our tagline now expresses. And although we know that there may be other agencies who can be similarly flexible \u2013 after all, being flexible is not a unique selling proposition \u2013 only we do it so fabulously.\n\n\n\nAs the old year rolls into the new, how will your company describe what you do in 2015? More importantly, how will you tell prospective clients why you do it, what matters to you and why they should work with you?\n\nStart by writing a list of truisms about your company. Write as many as you can, but then whittle that list down to just one, the most important truth. Work on that truism to create a tagline that\u2019s meaningful, difficult to be argue with and, above all, uniquely yours.\n\nAnswers\n\n\nThe Ultimate Driving Machine (BMW)\nJust Do It (Nike)\nDon\u2019t Leave Home Without It (American Express)", "year": "2014", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2014-12-23T00:00:00+00:00", "url": "https://24ways.org/2014/taglines-and-truisms/", "topic": "business"} {"rowid": 51, "title": "Blow Your Own Trumpet", "contents": "Even if your own trumpet\u2019s tiny and fell out of a Christmas cracker, blowing it isn\u2019t something that everyone\u2019s good at. Some people find selling themselves and what they do difficult. But, you know what? Boo hoo hoo. If you want people to buy something, the reality is you\u2019d better get good at selling, especially if that something is you.\nFor web professionals, the best place to tell potential business customers or possible employers about what you do is on your own website. You can write what you want and how you want, but that doesn\u2019t make knowing what to write any easier. As a matter of fact, writing for yourself often proves harder than writing for someone else.\nI spent this autumn thinking about what I wanted to say about Stuff & Nonsense on the website we relaunched recently. While I did that, I spoke to other designers about how they struggled to write about their businesses.\nIf you struggle to write well, don\u2019t worry. You\u2019re not on your own. Here are five ways to hit the right notes when writing about yourself and your work.\nBe genuine about who you are\nI\u2019ve known plenty of talented people who run a successful business pretty much single-handed. Somehow they still feel awkward presenting themselves as individuals. They wonder whether describing themselves as a company will give them extra credibility. They especially agonise over using \u201cwe\u201d rather than \u201cI\u201d when describing what they do. These choices get harder when you\u2019re a one-man band trading as a limited company or LLC business entity.\nIf you mainly work alone, don\u2019t describe yourself as anything other than \u201cI\u201d. You might think that saying \u201cwe\u201d makes you appear larger and will give you a better chance of landing bigger and better work, but the moment a prospective client asks, \u201cHow many people are you?\u201d you\u2019ll have some uncomfortable explaining to do. This will distract them from talking about your work and derail your sales process. There\u2019s no need to be anything other than genuine about how you describe yourself. You should be proud to say \u201cI\u201d because working alone isn\u2019t something that many people have the ability, business acumen or talent to do.\nExplain what you actually do\nHow many people do precisely the same job as you? Hundreds? Thousands? The same goes for companies. If yours is a design studio, development team or UX consultancy, there are countless others saying exactly what you\u2019re saying about what you do. Simply stating that you code, design or \u2013 God help me \u2013 \u201chandcraft digital experiences\u201d isn\u2019t enough to make your business sound different from everyone else. Anyone can and usually does say that, but people buy more than deliverables. They buy something that\u2019s unique about you and your business.\nPotentially thousands of companies deliver code and designs the same way as Stuff & Nonsense, but our clients don\u2019t just buy page designs, prototypes and websites from us. They buy our taste for typography, colour and layout, summed up by our \u201cIt\u2019s the taste\u201d tagline and bowler hat tip to the PG Tips chimps. We hope that potential clients will understand what\u2019s unique about us. Think beyond your deliverables to what people actually buy, and sell the uniqueness of that.\nDescribe work in progress\nIt\u2019s sad that current design trends have made it almost impossible to tell one website from another. So many designers now demonstrate finished responsive website designs by pasting them onto iMac, MacBook, iPad and iPhone screens that their portfolios don\u2019t fare much better. Every designer brings their own experience, perspective and process to a project. In my experience, it\u2019s understanding those differences which forms a big part of how a prospective client makes a decision about who to work with. Don\u2019t simply show a prospective client the end result of a previous project; explain your process, the development of your thinking and even the wrong turns you took.\nTraditional case studies, like the one I\u2019ve just written about Stuff & Nonsense\u2019s work for WWF UK, can take a lot of time. That\u2019s probably why many portfolios get out of date very quickly. Designers make new work all the time, so there must be a better way to show more of it more often, to give prospective clients a clearer understanding of what we do. At Stuff & Nonsense our solution was to create a feed where we could post fragments of design work throughout a project. This also meant rewriting our Contract Killer to give us permission to publish work before someone signs it off.\nOutline a client\u2019s experience\nRecently a client took me to one side and offered some valuable advice. She told me that our website hadn\u2019t described anything about the experience she\u2019d had while working with us. She said that knowing more about how we work would\u2019ve helped her make her buying decision.\nWhen a client chooses your business, they\u2019re hoping for more than a successful outcome. They want their project to run smoothly. They want to feel that they made a correct decision when they chose you. If they work for an organisation, they\u2019ll want their good judgement to be recognised too. Our client didn\u2019t recognise her experience because we hadn\u2019t made our own website part of it. Remember, the challenge of creating a memorable user experience starts with selling to the people paying you for it.\nAddress your ideal client\nIt\u2019s important to understand that a portfolio\u2019s job isn\u2019t to document your work, it\u2019s to attract new work from clients you want. Make sure that work you show reflects the work you want, because what you include in your portfolio often leads to more of the same.\nWhen you\u2019re writing for your portfolio and elsewhere on your website, imagine that you\u2019re addressing your ideal client. Picture them sitting opposite and answer the questions they\u2019d ask as you would in conversation. Be direct, funny if that\u2019s appropriate and serious when it\u2019s not. If it helps, ask a friend to read the questions aloud and record what you say in response. This will help make what you write sound natural. I\u2019ve found this technique helps clients write copy too.\nToot your own horn\nSome people confuse expressing confidence in yourself and your work as boastfulness, but in a competitive world the reality is that if you are to succeed, you need to show confidence so that others can show their confidence in you. If you want people to hear you, pick up your trumpet and blow it.", "year": "2015", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2015-12-23T00:00:00+00:00", "url": "https://24ways.org/2015/blow-your-own-trumpet/", "topic": "business"} {"rowid": 56, "title": "Helping VIPs Care About Performance", "contents": "Making a site feel super fast is the easy part of performance work. Getting people around you to care about site speed is a much bigger challenge. How do we keep the site fast beyond the initial performance work? Keeping very important people like your upper management or clients invested in performance work is critical to keeping a site fast and empowering other designers and developers to contribute.\nThe work to get others to care is so meaty that I dedicated a whole chapter to the topic in my book Designing for Performance. When I speak at conferences, the majority of questions during Q&A are on this topic. When I speak to developers and designers who care about performance, getting other people at one\u2019s organization or agency to care becomes the most pressing question.\nMy primary response to folks who raise this issue is the question: \u201cWhat metric(s) do your VIPs care about?\u201d This is often met with blank stares and raised eyebrows. But it\u2019s also our biggest clue to what we need to do to help empower others to care about performance and work on it. Every organization and executive is different. This means that three major things vary: the primary metrics VIPs care about; the language they use about measuring success; and how change is enacted. By clueing in to these nuances within your organization, you can get a huge leg up on crafting a successful pitch about performance work.\nLet\u2019s start with the metric that we should measure. Sure, (most) everybody cares about money - but is that really the metric that your VIPs are looking at each day to measure the success or efficacy of your site? More likely, dollars are the end game, but the metrics or key performance indicators (KPIs) people focus on might be:\n\nrate of new accounts created/signups\ncost of acquiring or retaining a customer\nvisitor return rate\nvisitor bounce rate\nfavoriting or another interaction rate\n\nThese are just a few examples, but they illustrate how wide-ranging the options are that people care about. I find that developers and designers haven\u2019t necessarily investigated this when trying to get others to care about performance. We often reach for the obvious \u2013 money! \u2013 but if we don\u2019t use the same kind of language our VIPs are using, we might not get too far. You need to know this before you can make the case for performance work.\nTo find out these metrics or KPIs, start reading through the emails your VIPs are sending within your company. What does it say on company wikis? Are there major dashboards internally that people are looking at where you could find some good metrics? Listen intently in team meetings or thoroughly read annual reports to see what these metrics could be.\nThe second key here is to pick up on language you can effectively copy and paste as you make the case for performance work. You need to be able to reflect back the metrics that people already find important in a way they\u2019ll be able to hear. Once you know your key metrics, it\u2019s time to figure out how to communicate with your VIPs about performance using language that will resonate with them.\nLet\u2019s start with visit traffic as an example metric that a very important person cares about. Start to dig up research that other people and companies have done that correlates performance and your KPI. For example, cite studies:\n\n\u201cWhen the home page of Google Maps was reduced from 100KB to 70\u201380KB, traffic went up 10% in the first week, and an additional 25% in the following three weeks.\u201d (source).\n\nRead through websites like WPOStats, which collects the spectrum of studies on the impact of performance optimization on user experience and business metrics. Tweet and see if others have done similar research that correlates performance and your site\u2019s main KPI.\nOnce you have collected some research that touches on the same kind of language your VIPs use about the success of your site, it\u2019s time to present it. You can start with something simple, like a qualitative description of the work you\u2019re actively doing to improve the site that translates to improved metrics that your VIPs care about. It can be helpful to append a performance budget to any proposal so you can compare the budget to your site\u2019s reality and how it might positively impact those KPIs folks care about.\nWords and graphs are often only half the battle when it comes to getting others to care about performance. Often, videos appeal to folks\u2019 emotions in a way that is missed when glancing through charts and graphs. On A List Apart I recently detailed how to create videos of how fast your site loads. Let\u2019s say that your VIPs care about how your site loads on mobile devices; it\u2019s time to show them how your site loads on mobile networks.\nOpen video\n\nYou can use these videos to make a number of different statements to your VIPs, depending on what they care about:\n\nLook at how slow our site loads versus our competitor!\nLook at how slow our site loads for users in another country!\nLook at how slow our site loads on mobile networks!\n\nAgain, you really need to know which metrics your VIPs care about and tune into the language they\u2019re using. If they don\u2019t care about the overall user experience of your site on mobile devices, then showing them how slow your site loads on 3G isn\u2019t going to work. This will be your sales pitch; you need to practice and iterate on the language and highlights that will land best with your audience. \nTo make your sales pitch as solid as possible, gut-check your ideas on how to present it with other co-workers to get their feedback. Read up on how to construct effective arguments and deliver them; do some research and see what others have done at your company when pitching to VIPs. Are slides effective? Memos or emails? Hallway conversations? Sometimes the best way to change people\u2019s minds is by mentioning it in informal chats over coffee. Emulate the other leaders in your organization who are successful at this work. \nEvery organization and very important person is different. Learn what metrics folks truly care about, study the language that they use, and apply what you\u2019ve learned in a way that\u2019ll land with those individuals. It may take time to craft your pitch for performance work over time, but it\u2019s important work to do. If you\u2019re able to figure out how to mirror back the language and metrics VIPs care about, and connect the dots to performance for them, you will have a huge leg up on keeping your site fast in the long run.", "year": "2015", "author": "Lara Hogan", "author_slug": "larahogan", "published": "2015-12-08T00:00:00+00:00", "url": "https://24ways.org/2015/helping-vips-care-about-performance/", "topic": "business"} {"rowid": 60, "title": "What\u2019s Ahead for Your Data in 2016?", "contents": "Who owns your data? Who decides what can you do with it? Where can you store it? What guarantee do you have over your data\u2019s privacy? Where can you publish your work? Can you adapt software to accommodate your disability? Is your tiny agency subject to corporate regulation? Does another country have rights over your intellectual property?\nIf you aren\u2019t the kind of person who is interested in international politics, I hate to break it to you: in 2016 the legal foundations which underpin our work on the web are being revisited in not one but three major international political agreements, and every single one of those questions is up for grabs. These agreements \u2013 the draft EU Data Protection Regulation (EUDPR), the Trans-Pacific Partnership (TPP), and the draft Transatlantic Trade and Investment Partnership (TTIP) \u2013 stand poised to have a major impact on your data, your workflows, and your digital rights. While some proposed changes could protect the open web for the future, other provisions would set the internet back several decades.\nIn this article we will review the issues you need to be aware of as a digital professional. While each of these agreements covers dozens of topics ranging from climate change to food safety, we will focus solely on the aspects which pertain to the work we do on the web.\nThe Trans-Pacific Partnership\nThe Trans-Pacific Partnership (TPP) is a free trade agreement between the US, Japan, Malaysia, Vietnam, Singapore, Brunei, Australia, New Zealand, Canada, Mexico, Chile and Peru \u2013 a bloc comprising 40% of the world\u2019s economy. The agreement is expected to be signed by all parties, and thereby to come into effect, in 2016. This agreement is ostensibly about the bloc and its members working together for their common interests. However, the latest draft text of the TPP, which was formulated entirely in secret, has only been made publicly available on a Medium blog published by the U.S. Trade Representative which features a patriotic banner at the top proclaiming \u201cTPP: Made in America.\u201d The message sent about who holds the balance of power in this agreement, and whose interests it will benefit, is clear.\nBy far the most controversial area of the TPP has centred around the provisions on intellectual property. These include copyright terms of up to 120 years, mandatory takedowns of allegedly infringing content in response to just one complaint regardless of that complaint\u2019s validity, heavy and disproportionate penalties for alleged violations, and \u2013 most frightening of all \u2013 government seizures of equipment allegedly used for copyright violations. All of these provisions have been raised without regard for the fact that a trade agreement is not the appropriate venue to negotiate intellectual property law.\nOther draft TPP provisions would restrict the digital rights of people with disabilities by banning the workarounds they use every day. These include no exemptions for the adaptations of copywritten works for use in accessible technology (such as text-to-speech in ebook readers), a ban on circumventing DRM or digital locks in order to convert a file to an accessible format, and requiring the takedown of adapted works, such as a video with added subtitles, even if that adaptation would normally have fallen under the definition of fair use.\nThe e-commerce provisions would prohibit data localisation, the practice of requiring data to be physically stored on servers within a country\u2019s borders. Data localisation is growing in popularity following the Snowden revelations, and some of your own personal data may have been recently \u201clocalised\u201d in response to the Safe Harbor verdict. Prohibiting data localisation through the TPP would address the symptom but not the cause.\nThe Electronic Frontier Foundation has published an excellent summary of the digital rights issues raised by the agreement along with suggested actions American readers can take to speak out.\nTransatlantic Trade and Investment Partnership\nTTIP stands for the Transatlantic Trade and Investment Partnership, a draft free trade agreement between the United States and the EU. The plan has been hugely controversial and divisive, and the internet and digital provisions of the draft form just a small part of that contention.\nThe most striking digital provision of TTIP is an attempt to circumvent and override European data protection law. As EDRI, a European digital rights organisation, noted:\n\n\u201cthe US proposal would authorise the transfer of EU citizens\u2019 personal data to any country, trumping the EU data protection framework, which ensures that this data can only be transferred in clearly defined circumstances. For years, the US has been trying to bypass the default requirement for storage of personal data in the EU. It is therefore not surprising to see such a proposal being {introduced} in the context of the trade negotiations.\u201d\n\nThis draft provision was written before the Safe Harbor data protection agreement between the EU and US was invalidated by the Court of Justice of the European Union. In other words, there is no longer any protective agreement in place, and our data is as vulnerable as this political situation. However, data protection is a matter of its own law, the acting Data Protection Directive and the draft EU Data Protection Reform. A trade agreement, be it the TTIP or the TPP, is not the appropriate place to revamp a law on data protection.\nOther digital law issues raised by TTIP include the possibility of renegotiating standards on encryption (which in practice means lowering them) and renegotiating intellectual property rights such as copyright. The spectre of net neutrality has even put in an appearance, with an attempt to introduce rules on access to the internet itself being introduced as provisions.\nTTIP is still under discussion, and this month the EU trade representative said that \u201cwe agreed to further intensify our work during 2016 to help negotiations move forward rapidly.\u201d This has been cleverly worded: this means the agreement has little chance of being passed or coming into effect in 2016, which buys civil society more precious time to speak out.\nThe EU Data Protection Regulation\nOn 15 December 2015 the European Commission announced their agreement on the text of the draft General Data Protection Regulation. This law will replace its predecessor, the EU Data Protection Regulation of 1995, which has done a remarkable job of protecting data privacy across the continent throughout two decades of constant internet evolution.\nThe goal of the reform process has been to return power over data, and its uses, to citizens. Users will have more control over what data is captured about them, how it is used, how it is retained, and how it can be deleted. Businesses and digital professionals, in turn, will have to restructure their relationships with client and customer data. Compliance obligations will increase, and difficult choices will have to be made. However, this time should be seen as an opportunity to rethink our relationship with data. After Snowden, Schrems, and Safe Harbor, it is clear that we cannot go back to the way things were before. In an era of where every one of our heartbeats is recorded on a wearable device and uploaded to a surveilled data centre in another country, the need for reform has never been more acute.\nWhile texts of the draft GDPR are available, there is not enough mulled wine in the world that will help you get through them. Instead, the law firm Fieldfisher Waterhouse has produced this helpful infographic which will give you a good idea of the changes we can expect to see (view full size):\n\nThe most surprising outcome announced on 15 December was the new regulation\u2019s teeth. Under the new law, companies that fail to heed the updated data protection rules will face fines of up to 4% of their global turnover. Additionally, the law expands the liability for data protection to both the controller (the company hosting the data) and the data processor (the company using the data). The new law will also introduce a one-stop shop for resolving concerns over data misuse. Companies will no longer be able to headquarter their European operations in countries which are perceived to have relatively light-touch data protection enforcement (that means you, Ireland) as a means of automatically rejecting any complaints filed by citizens outside that country.\nFor digital professionals, the most immediate concern is analytics. In fact, I am going to make a prediction: in 2016 we will begin to see the same misguided war on analytics that we saw on cookies. By increasing the legal liabilities for both data processors and controllers \u2013 in other words, the company providing the analytics as well as the site administrator studying them \u2013 the new regulation risks creating disproportionate burdens as well as the same \u201cguilt by association\u201d risks we saw in 2012. There have already been statements made by some within the privacy community that analytics are tracking, and tracking is surveillance, therefore analytics are evil. Yet \u201cjust don\u2019t use analytics,\u201d as was suggested by one advocate, is simply not an option. European regulators should consult with the web community to gain a clear understanding of why analytics are vital to everyday site administrators, and must find a happy medium that protects users\u2019 data without criminalising every website by default. No one wants a repeat of the crisis of consent, as well as the scaremongering, caused by the cookie law.\nAssuming the text is adopted in 2016, the new EU Data Protection Regulation would not come into effect until 2018. We have a considerable challenge ahead, but we also have plenty of time to get it right.", "year": "2015", "author": "Heather Burns", "author_slug": "heatherburns", "published": "2015-12-21T00:00:00+00:00", "url": "https://24ways.org/2015/whats-ahead-for-your-data-in-2016/", "topic": "business"} {"rowid": 90, "title": "Monkey Business", "contents": "\u201cToo expensive.\u201d \u201cOver-priced.\u201d \u201cA bit rich.\u201d\n\nThey all mean the same thing.\n\nWhen you say that something\u2019s too expensive, you\u2019re doing much more than commenting on a price. You\u2019re questioning the explicit or implicit value of a product or a service. You\u2019re asking, \u201cWill I get out of it what you want me to pay for it?\u201d You\u2019re questioning the competency, judgement and possibly even integrity of the individual or company that gave you that price, even though you don\u2019t realise it. You might not be saying it explicitly, but what you\u2019re implying is, \u201cHave you made a mistake?\u201d, \u201cAm I getting the best deal?\u201d, \u201cAre you being honest with me?\u201d, \u201cCould I get this cheaper?\u201d\n\nFinally, you\u2019re being dishonest, because deep down you know all too well that there\u2019s no such thing as too expensive. \n\nWhy? \n\nIt doesn\u2019t matter what you\u2019re questioning the price of. It could be a product, a service or the cost of an hour, day or week of someone\u2019s time. Whatever you\u2019re buying, too expensive is always an excuse. Saying it shifts acceptability of a price back to the person who gave it. What you should say, but are too afraid to admit, is:\n\n\n\t\u201cIt\u2019s more money than I wanted to pay.\u201d\n\t\u201cIt\u2019s more than I estimated it would cost.\u201d\n\t\u201cIt\u2019s more than I can afford.\u201d\n\n\nEveryone who\u2019s given a price for a product or service will have been told at some point that it\u2019s too expensive. It\u2019s never comfortable to hear that. Thoughts come thick and fast: \u201cWhat do I do?\u201d \u201cHow do I react?\u201d \u201cDo I really want the business?\u201d \u201cAm I prepared to negotiate?\u201d \u201cHow much am I willing to compromise?\u201d\n\nIt\u2019s easy to be defensive when someone questions a price, but before you react, stay calm and remember that if someone says what you\u2019re offering is too expensive, they\u2019re saying more about themselves and their situation than they are about your price. Learn to read that situation and how to follow up with the right questions.\n\nImagine you\u2019ve quoted someone for a week of your time. \u201cThat\u2019s too expensive,\u201d they respond. How should you handle that? Think about what they might otherwise be saying.\n\n\n\n\u201cIt\u2019s more money than I want to pay\u201d may mean that they don\u2019t understand the value of your service. How could you respond?\n\nStart by asking what similar projects they\u2019ve worked on and the type of people they worked with. Find out what they paid and what they got for their money, because it\u2019s possible what you offer is different from what they had before. Ask if they saw a return on that previous investment. Maybe their problem isn\u2019t with your headline price, but the value they think they\u2019ll receive. Put the emphasis on value and shift the conversation to what they\u2019ll gain, rather than what they\u2019ll spend.\n\nIt\u2019s also possible they can\u2019t distinguish your service from those of your competitors, so now would be a great time to explain the differences. Do you work faster? Explain how that could help them launch faster, get customers faster, make money faster. Do you include more? Emphasise that, and how unique the experience of working with you will be.\n\n\n\n\u201cIt\u2019s more than I estimated it would cost\u201d could mean that your customer hasn\u2019t done their research properly. You\u2019d never suggest that to them, of course, but you should ask how they\u2019ve arrived at their estimate. Did they base it on work they\u2019ve purchased previously? How long ago was that? Does it come from comparable work or from a different sector?\n\nHelp your customer by explaining how you arrived at your estimate. Break down each element and while you\u2019re doing that, emphasise the parts of your process that you know will appeal to them. If you know that they\u2019ve had difficulty with something in the past, explain how your approach will benefit them. People almost always value a positive experience more than the money they\u2019ll save.\n\n\n\n\u201cIt\u2019s more than I can afford\u201d could mean they can\u2019t afford what you offer at all, but it could also mean they can\u2019t afford it right now or all at once. So ask if they could afford what you\u2019re asking if they spread payment over a longer period? Ask, \u201cWould that mean you\u2019ll give me the business?\u201d\n\nIt\u2019s possible they\u2019re asking for too much for what they can afford to pay. Will they compromise? Can you reach an agreement on something less? Ask, \u201cIf we can agree what\u2019s in and what\u2019s out, will you give me the business?\u201d\n\nWhat can they afford? When you know, you\u2019re in a good position to decide if the deal makes good business sense, for both of you. Ask, \u201cIf I can match that price, will you give me the business?\u201d\n\nThere\u2019s no such thing as \u201ca bit rich\u201d, only ways for you to get to know your customer better. There\u2019s no such thing as \u201cover-priced\u201d,\u00a0only opportunities for you to explain yourself better. You should relish those opportunities. There\u2019s really also no such thing as \u201ctoo expensive\u201d, just ways to set the tone for your relationship and help you develop that relationship to a point where money will be less of a deciding factor.\n\nUnfinished Business\n\nJoin me and my co-host Anna Debenham next year for Unfinished Business, a new discussion show about the business end of working in web, design and creative industries.", "year": "2012", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2012-12-23T00:00:00+00:00", "url": "https://24ways.org/2012/monkey-business/", "topic": "business"} {"rowid": 94, "title": "Using Questionnaires for Design Research", "contents": "How do you ask the right questions? \n\nIn this article, I share a bunch of tips and practical advice on how to write and use your own surveys for design research.\n\nI\u2019m an audience researcher \u2013 I\u2019m not a designer or developer. I\u2019ve spent much of the last thirteen years working with audience data both in creative agencies and on the client-side. I\u2019m also a member of the Market Research Society. I run user surveys and undertake user research for our clients at the design studio I run with my husband \u2013 Mark Boulton Design.\n\nSo let\u2019s get started!\n\nWho are you designing for?\n\nGood web designers and developers appreciate the importance of understanding the audience they are designing or building a website or app for. I\u2019m assuming that because you are reading a quality publication like 24 ways that you fall into this category, and so I won\u2019t begin this article with a lecture.\n\nSuffice it to say, it\u2019s a good idea to involve research of some sort during the life cycle of every project you undertake. I don\u2019t just mean visual or competitor research, which of course is also very important. I mean looking at or finding your own audience or user data. Whether that be auditing existing data or research available from the client, carrying out user interviews, A/B testing, or conducting a simple questionnaire with users, any research is better than none. If you create personas as a design tool, they should always be based on research, so you will need to have plenty of data to hand for that.\n\nWhere do I start?\n\nIn the initial kick-off stages of a project, it\u2019s a good idea to start by asking your client (when working in-house you still have a client \u2013 you might even be the client) what research or audience data they have available. Some will have loads \u2013 analytics, surveys, focus groups and insights \u2013 from talking to customers. Some won\u2019t have much at all and you\u2019ll be hard pressed to find out much about the audience. It\u2019s best to review existing research first without rushing headlong into doing new research. Get a picture of what the data tells you and perhaps get this into a document \u2013 who, what, why and how are they using this website or app? What gaps are there in existing research? What else do you need to know? Then you can decide what else you need to do to plug these gaps. Think about the information first before deciding on the methodology. The rest of my article talks mostly about running self-completion online surveys. You can of course do face-to-face surveys, self-completion written questionnaires or phone polls, but I won\u2019t cover those here. That\u2019s for another article.\n\nWhy run a survey?\n\nSurveys are great for getting a broad picture of your audience. As long as they are designed carefully, you can create an overview of them, how they use the site and their opinions of it, with an idea of which parts of this picture are more important than others. By using a limited amount of open-ended questions, you can also get some more qualitative feedback or insights on your website or app. The clients we work with surprisingly often don\u2019t have much in the way of audience research available, even basic analytics, so I will often suggest running a short survey, just to create a picture of who is out there.\n\nOK, what should I do first?\n\nBefore you rush into writing questions, stop and think about what you\u2019re trying to find out. Remember being in school when you studied science and you had to propose a hypothesis? This could be a starting point \u2013 something to prove or disprove. Or, even better, write a research brief. It doesn\u2019t have to be long; it can be just a sentence that encapsulates what you\u2019re trying to do, like a good creative brief. For the purposes of this article, I created a short, slightly silly survey on Christmas and beliefs in Father Christmas.\n\nMy research brief was:\n\n\n\tTo find out more about people\u2019s beliefs about Father Christmas and their experiences of Christmas.\n\n\nInevitably, as you start thinking of what questions to ask, you will find that you go off at tangents or your client will want you to add in everything but the kitchen sink. In order for your questionnaire not to get too long and lose focus, you could write lists of what it is and what it\u2019s not. This is how I\u2019d apply it to my Christmas questionnaire example:\n\nWhat it is about\n\n\n\tHow people communicate with Father Christmas\n\tIf someone\u2019s background has affected their likelihood of believing in Father Christmas\n\n\nWhat it is not about\n\n\n\tWhat colour to change Father Christmas\u2019s coat to\n\tFather Christmas\u2019s elves\n\n\nLet\u2019s get down to business: the questions. \n\nKinds of questions\n\nThere are two basic kinds of questions: open-ended and closed. Closed questions limit answers by giving the respondent a number of predefined lists of options to choose from. Typically, these are multiple-choice questions with a list of responses. You can either select one or tick all that apply. Another useful type of closed question I often use is a rating scale, where a respondent can assess a situation along a continuum of values. These can also be useful as a measure of advocacy or strength of feeling about something. There is a standard measure called the Net Promoter score, which measures how likely someone is to recommend your product or service to a friend or acquaintance. It\u2019s a useful benchmark as you can compare your scores to others in a similar sector.\n\n\n\nOpen-ended questions often take the form of a statement which requires a response. Generally, respondents are given a text box to fill in. It\u2019s useful to limit this in some way so that people have an idea of how long the expected response should be; for example, a single line for an email address (Q18), or a larger text area for a longer response (Q6).\n\nIf you plan to send your survey out to a large number of people, I would suggest using mostly closed questions, unless you want to spend a long time wading through comments and hand-coded responses. I\u2019d always advise adding a general request at the end of a survey (\u2018Is there anything else you\u2019d like to tell us?\u2019). You\u2019d be surprised how many interesting and insightful comments people will add.\n\nThere are times when it\u2019s better to provide an open-ended text box rather than a predefined list makes assumptions about your audience\u2019s groupings. For example, we ran a short survey for our Gridset beta testers and rather than assume we knew who they were, we decided to ask an open-ended question: \u201cWhat is your current job title?\u201d\n\n\n\nThe analysis took quite a bit longer than responses using a predefined list, but it meant that we were able to make sure we didn\u2019t miss anyone. And next time we run a survey for Gridset, I can use the responses gathered from this survey to help create a predefined list to make analysis easier.\n\nWhat to ask\n\nThe questions to ask depend on what you want to know, but your brief and lists of what the survey is and isn\u2019t should help here. I always ask the design team and client to give me ideas of what they are interested in finding out, and combine this with a mix of new and standard questions I have used in other surveys. I find Survey Monkey\u2019s question bank a very useful source of example questions and help with tricky wording.\n\nI always include simple demographics so I can compare my results to the population at large or internet users as a whole \u2013 just going on age, gender and location can be quite illuminating. For example, with the Christmas survey, I can see that the respondents were typical of the online design and dev community, mainly young and male.\n\nIf appropriate, I add questions on disability, ethnic background, religion and community of interest. Questions about ethnicity, religion, sexual preference, disability and other sensitive subjects can feel awkward and difficult to ask. This is not a good reason to not ask them. Perhaps you\u2019re working for a public sector client, like a local council, so it\u2019s likely you will need to consider groups of people who maybe under-represented, who may have differing views to others, or who you need to look at specifically as a subset.\n\nHow to ask\n\nAlthough they may seem clunky and wordy, it\u2019s often best to use the census wording or professional body wording for such demographic questions. For example, I used the UK census 2011 wording for Wales on my Christmas questionnaire in my questions on religion [PDF] (Q16) and ethnicity [PDF] (Q17). I had to adapt them slightly for the Survey Monkey format \u2013 self-completion online, rather than pen and paper \u2013 which is why \u201cWhite Welsh\u201d came up as the first option for the ethnicity question. For similar questions for US audiences, try the Census Bureau website.\n\nWhen conducting a survey for a project that has a global audience, you need to consider who your primary audience is. For example, I recently created a questionnaire for a global news website. A large proportion of its audience is based in the USA, so I was careful to word things in a way Americans would find familiar. I used the US ethnic background census question wording and options, and looked at data for US competitor news websites to decide which to include.\n\nYou should also consider people whose first language isn\u2019t English. Working as an audience researcher at BBC Wales, every survey we did was bilingual. I\u2019ve also recently run a user survey in Arabic using Google Forms. During this project, we found that while Survey Monkey supports different languages, including Arabic, the text ran left to right with no option to change it to right to left \u2013 an essential when it comes to reading Arabic! If research is a deliverable in a client project, and you know you\u2019ll need to conduct it in a foreign language, always build in extra time for translation at both the questionnaire design and analysis stages. Make sure you also allow for plenty of checks. In this case we had to change to Google Forms after initially creating our survey with Survey Monkey to get the functionality we needed.\n\nLook and feel\n\nThink about the survey as another way your audience will experience your brand. Take care getting the tone of voice right. There are plenty of great articles and books out there about tone of voice \u2013 try Letting Go of the Words by Ginny Redish for starters, or Brand Language by Liz Doig. The basic rule of thumb is to sound like a human, and use clear and friendly language. If, like me, you are lucky enough to work with journalists or copy editors, you should ask for their help, particularly in the preamble, linking text and closing statements. I find it helpful to break my questions down into sections and to have a page for each. I then have an introductory piece of text for each section to guide the respondent through the survey.\n\nYou should also make sure you check with your designers how your survey looks \u2013 use a company logo and branding, and make the typography legible. Many survey apps like Survey Monkey and Google Forms have a progress bar. This is helpful for users to see how far through your survey they are. I generally time the survey and give an indication in the preamble: \u201cThis survey will only take five minutes of your time.\u201d\n\nYou also need to think about how you will technically serve the questionnaire. For example, will it be via email, social media, a pop-up or lightbox on your website, or (not recommended but possible) in an ad space?\n\nEthical considerations\n\nSomething else to think about are any local laws that govern how you collect and store data, such as the Data Protection Act in the UK. As a member of the Market Research Society, I am also obliged to consider its guidelines, but even if you\u2019re not, it\u2019s always a good idea to deal with personal data ethically.\n\nIf you collect personal data that can identify individuals, you must ask their permission to share it with others, and store it securely for no longer than two years. If you want to contact people afterwards, you must ask for their permission. If you ask for email addresses, as I did in question 18, you have a ready-made sample for a further survey, interviews or focus groups. Remember, you shouldn\u2019t survey people under sixteen years old without the permission of their parents or legal guardians, so if you know your website is likely to be used by children, you must ask for verification of age early on, and your survey should close someone answers that they are under sixteen. The ESOMAR guidelines for online research [PDF] are well worth reading, as they go into detail about such issues, as well as privacy guidelines \u2013 using cookies, storing IP addresses, and so on.\n\nTools\n\nUnless you work in-house and have proprietary software, or at a market research agency and you\u2019re using specialist software such as Snap or IBM SPSS Statistics (previously just SPSS), you will need to use a good tool to run your survey, collect your responses and, ideally, help with the analysis. I like Survey Monkey because of the question bank and analysis tools. The software graphs your results and does simple cross-tabbing and filtering. What this means is you can slice the data in more interesting ways and delve a bit deeper. For example, in the Gridset questionnaire I mentioned earlier, I cross-tabbed responses to questions against whether a person worked in-house, for an agency or as a freelancer. \n\nOther well known online tools that I also use from time to time are Wufoo and Google Forms. Smart Surveys is a similar service to Survey Monkey and it\u2019s used by many leading brands in the UK. Snap Surveys mentioned above is a well-established player in the market research scene, used a lot for face-to-face surveys and also on tablets and smartphones.\n\nAnalysis\n\nAnalysis is often overlooked but is as important as the design of the questionnaire. Don\u2019t just rely on looking at the summary report and charts generated as standard by your form or survey software. Spend time with your data. Spend at least a week now and then if you can, looking at the data. Keep coming back to it and tweaking or cutting it a different way to see if there are any different pictures. Slice it up in different ways to reveal new insights. Here is the data from my dummy survey (apart from the open-ended responses). \n\nFor open-ended questions, you can analyse collaboratively. Print and cut out the open-ended responses and do a cluster analysis or affinity sort with a colleague. \n\n\n\nDiscussing the comments helps you to understand them. You will also find the design team are more likely to buy into the research as they have uncovered the insights for themselves. Always make sure to treat open-ended responses sensitively and don\u2019t share anything publicly in a way that identifies the respondent.\n\nWrite a report\n\nNever hand over a dataset to your client without a summary of the findings. Data on its own can be skewed to suit the reader\u2019s needs, and not everyone is able to find the story in a dataset. Even if it\u2019s not a deliverable, it\u2019s always a good idea to capture your findings in a report of some sort. Use graphs sparingly to show really interesting things or to aid the reader\u2019s understanding. I have written a quick dummy report using the data from the Christmas questionnaire so you can see how it\u2019s done.\n\nI highly recommend Brian Suda\u2019s book A Practical Guide to Designing with Data for tips on how to present data effectively, but that\u2019s a subject that benefits a whole article (indeed book) in itself. \n\nI am not a designer. I am a researcher, so I never write design recommendations in a report unless they have been talked about or suggested by the designers I work with. More often, I write up the results and we talk about them and what impact they have on the project or design. Often they lead to more questions or further research.\n\nSo that\u2019s it: a brief introduction to using questionnaires for design research. Here\u2019s a quick summary to remind you what I have talked about, and a list of resources if you\u2019re interested in reading further.\n\nTop 10 things to remember when using questionnaires for design research:\n\n\n\tStart by auditing existing research to identify gaps in data.\n\tWrite a research brief. Work out exactly what you\u2019re trying to find out \u2013 what is the survey about, and what is it not about?\n\tThe two basic kinds of questions are open-ended and closed.\n\tClosed questions limit responses by giving the respondent a number of predefined lists of options to choose from (multiple choice, rating scales, and so on).\n\tOpen-ended questions are often in the form of a statement which requires a response. Always ask one at the end of a questionnaire.\n\tAlways include simple demographics to enable you to compare your sample against the population in general.\n\tIt\u2019s best to use official census or professional body wording for questions on ethnicity, disability and religion.\n\tBe sure to think carefully about your tone of voice and the look of your questionnaire.\n\tPay attention to guidelines and laws on storing personal data, cookies and privacy.\n\tInvest plenty of time in analysis and report writing. Don\u2019t just look at the obvious \u2013 dig deep for more interesting insights.\n\n\nSome useful resources for further study\n\nOnline research\n\n\n\tDesign Research: Methods and Perspectives edited by Brenda Laurel\n\tOnline Research Essentials by Brenda Russell and John Purcell\n\tHandbook of Online and Social Media Research by Ray Poynter\n\tESOMAR guidelines for online research [PDF]\n\tOnline questionnaires\n\n\nMarket research books on questionnaire design\n\n\n\tUsing Questionnaires in Small-Scale Research: A Beginner\u2019s Guide by Pamela Munn\n\tQuestionnaire Design by A N Oppenheim\n\tDeveloping a Questionnaire by Bill Gillham", "year": "2012", "author": "Emma Boulton", "author_slug": "emmaboulton", "published": "2012-12-14T00:00:00+00:00", "url": "https://24ways.org/2012/using-questionnaires-for-design-research/", "topic": "business"} {"rowid": 103, "title": "Recession Tips For Web Designers", "contents": "For web designers, there are four keys to surviving bad economic times: do good work, charge a fair price, lower your overhead, and be sure you are communicating with your client. As a reader of 24 ways, you already do good work, so let\u2019s focus on the rest.\n\nI know something about surviving bad times, having started my agency, Happy Cog, at the dawn of the dot-com bust. Of course, the recession we\u2019re in now may end up making the dot-com bust look like the years of bling and gravy. But the bust was rough enough at the time. \n\nBad times are hard on overweight companies and over-leveraged start-ups, but can be kind to freelancers and small agencies. Clients who once had money to burn and big agencies to help them burn it suddenly consider the quality of work more important than the marquee value of the business card. Fancy offices and ten people at every meeting are out. A close relationship with an individual or small team that listens is in.\n\nThin is in\n\nIf you were good in client meetings when you were an employee, print business cards and pick a name for your new agency. Once some cash rolls in, see an accountant. \n\nIf the one-person entrepreneur model isn\u2019t you, it\u2019s no problem. Form a virtual agency with colleagues who complement your creative, technical, and business skills. Athletics is a Brooklyn-based multi-disciplinary \u201cart and design collective.\u201d Talk about low overhead: they don\u2019t have a president, a payroll, or a pension plan. But that hasn\u2019t stopped clients like adidas, Nike, MTV, HBO, Disney, DKNY, and Sundance Channel from knocking on their (virtual) doors.\n\nRunning a traditional business is like securing a political position in Chicago: it costs a fortune. That\u2019s why bad times crush so many companies. But you are a creature of the internets. You don\u2019t need an office to do great work. I ran Happy Cog out of my apartment for far longer than anyone realized. My clients, when they learned my secret, didn\u2019t care. \n\nKeep it lean: if you can budget your incoming freelance money, you don\u2019t have to pay yourself a traditional salary. Removing the overhead associated with payroll means more of the budget stays in your pocket, enabling you to price your projects competitively, while still within industry norms. (Underpricing is uncool, and clients who knowingly choose below-market-rate vendors tend not to treat those vendors with respect.)\n\nGetting gigs\n\nWeb design is a people business. If things are slow, email former clients. If you just lost your job, email former agency clients with whom you worked closely to inform them of your freelance business and find out how they\u2019re doing. Best practice: focus the email on wishing them a happy holiday and asking how they\u2019re doing. Let your email signature file tell them you\u2019re now the president of Your Name Design. Leading with the fact that you just lost your job may earn sympathy (or commiseration: the client may have lost her job, too) but it\u2019s not exactly a sure-fire project getter.\n\nThe qualities that help you land a web design project are the same in good times or bad. Have a story to tell about the kind of services you offer, and the business benefits they provide. (If you design with web standards, you already have one great story line. What are the others?) \n\nDon\u2019t be shy about sharing your story, but don\u2019t make it the focus of the meeting. The client is the focus. Before you meet her, learn as much as you can about her users, her business, and her competitors. At the very least, read her site\u2019s About pages, and spend some quality time with Google. \n\nMost importantly, go to the meeting knowing how much you don\u2019t know. Arrive curious, and armed with questions. Maintain eye contact and keep your ears open. If a point you raise causes two people to nod at each other, follow up on that point, don\u2019t just keep grinding through your Keynote presentation. \n\nIf you pay attention and think on your feet, it tells the potential client that they can expect you to listen and be flexible. (Clients are like unhappy spouses: they\u2019re dying for someone to finally listen.) If you stick to a prepared presentation, it might send the message that you are inflexible or nervous or both. \u201cNervous\u201d is an especially bad signal to send. It indicates that you are either dishonest or inexperienced. Neither quality invites a client to sign on. Web design is a people business for the client, too: they should feel that their interactions with you will be pleasant and illuminating. And that you\u2019ll listen. Did I mention that?\n\nGive it time\n\nSecuring clients takes longer and requires more effort in a recession. If two emails used to land you a gig, it will now take four, plus an in-person meeting, plus a couple of follow-up calls. This level of salesmanship is painful to geeks and designers, who would rather spend four hours kerning type or debugging a style sheet than five minutes talking business on the telephone. I know. I\u2019m the same way. But we must overcome our natural shyness and inwardness if we intend not to fish our next meal out of a neighbor\u2019s garbage can. \n\nAs a bonus, once the recession ends, your hard-won account management skills will help you take your business to the next level. By the time jobs are plentiful again, you may not want to work for anyone but yourself. You\u2019ll be a captain of our industry. And talented people will be emailing to ask you for a job.", "year": "2008", "author": "Jeffrey Zeldman", "author_slug": "jeffreyzeldman", "published": "2008-12-24T00:00:00+00:00", "url": "https://24ways.org/2008/recession-tips-for-web-designers/", "topic": "business"} {"rowid": 105, "title": "Contract Killer", "contents": "When times get tough, it can often feel like there are no good people left in the world, only people who haven\u2019t yet turned bad. These bad people will go back on their word, welch on a deal, put themselves first. You owe it to yourself to stay on top. You owe it to yourself to ensure that no matter how bad things get, you\u2019ll come away clean. You owe it yourself and your business not to be the guy lying bleeding in an alley with a slug in your gut.\n\nBut you\u2019re a professional, right? Nothing bad is going to happen to you.\n\nYou\u2019re a good guy. You do good work for good people.\n\nThink again chump.\n\nMaybe you\u2019re a gun for hire, a one man army with your back to the wall and nothing standing between you and the line at a soup kitchen but your wits. Maybe you work for the agency, or like me you run one of your own. Either way, when times get tough and people get nasty, you\u2019ll need more than a killer smile to save you. You\u2019ll need a killer contract too.\n\nIt was exactly ten years ago today that I first opened my doors for business. In that time I\u2019ve thumbed through enough contracts to fill a filing cabinet. I\u2019ve signed more contracts than I can remember, many so complicated that I should have hired a lawyer (or detective) to make sense of their complicated jargon and solve their cross-reference puzzles. These documents had not been written to be understood on first reading but to spin me around enough times so as to give the other player the upper-hand.\n\n\nIf signing a contract I didn\u2019t fully understand made me a stupid son-of-a-bitch, not asking my customers to sign one just makes me plain dumb. I\u2019ve not always been so careful about asking my customers to sign contracts with me as I am now. Somehow in the past I felt that insisting on a contract went against the friendly, trusting relationship that I like to build with my customers. Most of the time the game went my way. On rare the occasions when a fight broke out, I ended up bruised and bloodied. I learned that asking my customers to sign a contract matters to both sides, but what also matters to me is that these contracts should be more meaningful, understandable and less complicated than any of those that I have ever autographed.\n\n\nWriting a killer contract\n\nIf you are writing a contract between you and your customers it doesn\u2019t have to conform to the seemingly standard format of jargon and complicated legalese. You can be creative. A killer contract will clarify what is expected of both sides and it can also help you to communicate your approach to doing business. It will back-up your brand values and help you to build a great relationship between you and your customers. In other words, a creative contract can be a killer contract.\n\n\nYour killer contract should cover:\n\n\n\tA simple overview of who is hiring who, what they are being hired to do, when and for how much\n\tWhat both parties agree to do and what their respective responsibilities are\n\tThe specifics of the deal and what is or isn\u2019t included in the scope\n\tWhat happens when people change their minds (as they almost always do)\n\tA simple overview of liabilities and other legal matters\n\tYou might even include a few jokes\n\n\nTo help you along, I will illustrate those bullet points by pointing both barrels at the contract that I wrote and have been using at Stiffs & Nonsense for the past year. My contract has been worth its weight in lead and you are welcome to take all or any part of it to use for yourself. It\u2019s packing a creative-commons attribution share-a-like license. That means you are free to re-distribute it, translate it and otherwise re-use it in ways I never considered. In return I only ask you mention my name and link back to this article. As I am only an amateur detective, you should have it examined thoroughly by your own, trusted legal people if you use it.\n\nNB: The specific details of this killer contract work for me and my customers. That doesn\u2019t mean that they will work for you and yours. The ways that I handle design revisions, testing, copyright ownership and other specifics are not the main focus of this article. That you handle each of them carefully when you write your own killer contract is.\n\nKiss Me, Deadly\n\nSetting a tone and laying foundations for agreement\n\nThe first few paragraphs of a killer contract are the most important. Just like a well thought-out web page, these first few words should be simple, concise and include the key points in your contract. As this is the part of the contract that people absorb most easily, it is important that you make it count. Start by setting the overall tone and explaining how your killer contract is structured and why it is different.\n\n\n\n\tWe will always do our best to fulfill your needs and meet your goals, but sometimes it is best to have a few simple things written down so that we both know what is what, who should do what and what happens if stuff goes wrong. In this contract you won\u2019t find complicated legal terms or large passages of unreadable text. We have no desire to trick you into signing something that you might later regret. We do want what\u2019s best for the safety of both parties, now and in the future.\n\n\tIn short\n\n\tYou ([customer name]) are hiring us ([company name]) located at [address] to [design and develop a web site] for the estimated total price of [total] as outlined in our previous correspondence. Of course it\u2019s a little more complicated, but we\u2019ll get to that.\n\n\nThe Big Kill\n\nWhat both parties agree to do\n\nHave you ever done work on a project in good faith for a junior member of a customer\u2019s team, only to find out later that their spending hadn\u2019t been authorized? To make damn sure that does not happen to you, you should ask your customer to confirm that not only are they authorized to enter into your contract but that they will fulfill all of their obligations to help you meet yours. This will help you to avoid any gunfire if, as deadline day approaches, you have fulfilled your side of the bargain but your customer has not come up with the goods.\n\n\n\n\tAs our customer, you have the power and ability to enter into this contract on behalf of your company or organization. You agree to provide us with everything that we need to complete the project including text, images and other information as and when we need it, and in the format that we ask for. You agree to review our work, provide feedback and sign-off approval in a timely manner too. Deadlines work two ways and you will also be bound by any dates that we set together. You also agree to stick to the payment schedule set out at the end of this contract.\n\n\tWe have the experience and ability to perform the services you need from us and we will carry them out in a professional and timely manner. Along the way we will endeavor to meet all the deadlines set but we can\u2019t be responsible for a missed launch date or a deadline if you have been late in supplying materials or have not approved or signed off our work on-time at any stage. On top of this we will also maintain the confidentiality of any information that you give us.\n\n\nMy Gun Is Quick\n\nGetting down to the nitty gritty\n\nWhat appear at first to be a straight-forward projects can sometimes turn long and complicated and unless you play it straight from the beginning your relationship with your customer can suffer under the strain. Customers do, and should have the opportunity to, change their minds and give you new assignments. After-all, projects should be flexible and few customers know from the get-go exactly what they want to see. If you handle this well from the beginning you will help to keep yourself and your customers from becoming frustrated. You will also help yourself to dodge bullets in the event of a fire-fight.\n\n\n\n\tWe will create designs for the look-and-feel, layout and functionality of your web site. This contract includes one main design plus the opportunity for you to make up to two rounds of revisions. If you\u2019re not happy with the designs at this stage, you will pay us in full for all of the work that we have produced until that point and you may either cancel this contract or continue to commission us to make further design revisions at the daily rate set out in our original estimate.\n\n\tWe know from plenty of experience that fixed-price contracts are rarely beneficial to you, as they often limit you to your first idea about how something should look, or how it might work. We don\u2019t want to limit either your options or your opportunities to change your mind.\n\n\tThe estimate/quotation prices at the beginning of this document are based on the number of days that we estimate we\u2019ll need to accomplish everything that you have told us you want to achieve. If you do want to change your mind, add extra pages or templates or even add new functionality, that won\u2019t be a problem. You will be charged the daily rate set out in the estimate we gave you. Along the way we might ask you to put requests in writing so we can keep track of changes.\n\n\nAs I like to push my luck when it comes to CSS, it never hurts to head off the potential issue of progressive enrichment right from the start. You should do this too. But don\u2019t forget that when it comes to technical matters your customers may have different expectations or understanding, so be clear about what you will and won\u2019t do.\n\n\n\n\tIf the project includes XHTML or HTML markup and CSS templates, we will develop these using valid XHTML 1.0 Strict markup and CSS2.1 + 3 for styling. We will test all our markup and CSS in current versions of all major browsers including those made by Apple, Microsoft, Mozilla and Opera. We will also test to ensure that pages will display visually in a \u2018similar\u2019, albeit not necessarily an identical way, in Microsoft Internet Explorer 6 for Windows as this browser is now past it\u2019s sell-by date.\n\n\tWe will not test these templates in old or abandoned browsers, for example Microsoft Internet Explorer 5 or 5.5 for Windows or Mac, previous versions of Apple\u2019s Safari, Mozilla Firefox or Opera unless otherwise specified. If you need to show the same or similar visual design to visitors using these older browsers, we will charge you at the daily rate set out in our original estimate for any necessary additional code and its testing.\n\n\nThe Twisted Thing\n\nIt is not unheard of for customers to pass off stolen goods as their own. If this happens, make sure that you are not the one left holding the baby. You should also make it clear who owns the work that you make as customers often believe that because they pay for your time, that they own everything that you produce.\n\n\nCopyrights\n\n\n\tYou guarantee to us that any elements of text, graphics, photos, designs, trademarks, or other artwork that you provide us for inclusion in the web site are either owned by your good selfs, or that you have permission to use them. When we receive your final payment, copyright is automatically assigned as follows:\n\n\tYou own the graphics and other visual elements that we create for you for this project. We will give you a copy of all files and you should store them really safely as we are not required to keep them or provide any native source files that we used in making them.\n\n\tYou also own text content, photographs and other data you provided, unless someone else owns them. We own the XHTML markup, CSS and other code and we license it to you for use on only this project.\n\n\nVengeance Is Mine!\n\nThe fine print\n\nUnless your work is pro-bono, you should make sure that your customers keep you in shoe leather. It is important that your customers know from the outset that they must pay you on time if they want to stay on good terms.\n\n\n\tWe are sure you understand how important it is as a small business that you pay the invoices that we send you promptly. As we\u2019re also sure you\u2019ll want to stay friends, you agree to stick tight to the following payment schedule.\n\n\t[Payment schedule]\n\n\nNo killer contract would be complete without you making sure that you are watching your own back. Before you ask your customers to sign, make it clear-cut what your obligations are and what will happen if any part of your killer contract finds itself laying face down in the dirt.\n\n\n\n\tWe can\u2019t guarantee that the functions contained in any web page templates or in a completed web site will always be error-free and so we can\u2019t be liable to you or any third party for damages, including lost profits, lost savings or other incidental, consequential or special damages arising out of the operation of or inability to operate this web site and any other web pages, even if you have advised us of the possibilities of such damages.\n\n\tJust like a parking ticket, you cannot transfer this contract to anyone else without our permission. This contract stays in place and need not be renewed. If any provision of this agreement shall be unlawful, void, or for any reason unenforceable, then that provision shall be deemed severable from this agreement and shall not affect the validity and enforceability of any remaining provisions.\n\n\tPhew.\n\n\tAlthough the language is simple, the intentions are serious and this contract is a legal document under exclusive jurisdiction of [English] courts. Oh and don\u2019t forget those men with big dogs.\n\n\nSurvival\u2026 Zero!\n\nTake it from me, packing a killer contract will help to keep you safe when times get tough, but you must still keep your wits about you and stay on the right side of the law.\n\nDon\u2019t be a turkey this Christmas.\n\nBe a contract killer.\n\nUpdate, May 2010: For a follow-on to this article see Contract Killer: The Next Hit", "year": "2008", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2008-12-23T00:00:00+00:00", "url": "https://24ways.org/2008/contract-killer/", "topic": "business"} {"rowid": 113, "title": "What Your Turkey Can Teach You About Project Management", "contents": "The problem with project management is that everyone thinks it\u2019s boring. Well, that\u2019s not really the problem. The problem is that everyone thinks it\u2019s boring but it\u2019s still really important. Project management is what lets you deliver your art \u2013 whether that be design or development. \n\nIn the same way, a Christmas dinner cooked by a brilliant chef with no organizational skills is disastrous \u2013 courses arrive in the wrong order, some things are cold whilst others are raw and generally it\u2019s a trip to the ER waiting to happen. Continuing the Christmas dinner theme, here are my top tips for successful projects, wrapped up in a nice little festive analogy. Enjoy!\n\nTip 1: Know What You\u2019re Aiming For\n\n(Turkey? Ham? Both??)\n\nThe underlying cause for the failure of so many projects is mismatched expectations. Christmas dinner cannot be a success if you serve glazed ham and your guests view turkey as the essential Christmas dinner ingredient. It doesn\u2019t matter how delicious and well executed your glazed ham is, it\u2019s still fundamentally just not turkey. You might win one or two adventurous souls over, but the rest will go home disappointed.\n\nAdd to the mix the fact that most web design projects are nowhere near as emotive as Christmas dinner (trust me, a ham vs turkey debate will rage much longer than a fixed vs fluid debate in normal human circles) and the problem is compounded. In particular, as technologists, we forget that our ability to precisely imagine the outcome of a project, be it a website, a piece of software, or similar, is much more keenly developed than the average customer of such projects. \n\nSo what\u2019s the solution? Get very clear, from the very beginning, on exactly what the project is about. What are you trying to achieve? How will you measure success? Is the presence of turkey a critical success factor?\n\nSummarize all this information in some form of document (in PM-speak, it\u2019s called a Project Initiation Document typically). Ideally, get the people who are the real decision makers to sign their agreement to that summary in their own blood. Well, you get the picture, I suppose actual blood is not strictly necessary, but a bit of gothic music to set the tone can be useful!\n\nTip 2: Plan at the Right Level of Detail\n\nHugely detailed and useless Gantt charts are a personal bugbear of mine. For any project, you should plan at the appropriate level of detail (and in an appropriate format) for the project itself. In our Christmas dinner example, it may be perfectly fine to have a list of tasks for the preparation work, but for the intricate interplay of oven availability and cooking times, something more complex is usually due. Having cooked roast dinners for fourteen in a student house where only the top oven and two of the rings on the hob actually worked, I can attest to the need for sequence diagrams in some of these situations!\n\nThe mistake many small teams make is to end up with a project plan that is really the amalgamation of their individual todo lists. What is needed is a project plan that will:\n\n\n\treflect reality\n\tbe easy to update\n\thelp to track progress (i.e. are we on track or not?)\n\n\nA good approach is to break your project into stages (each representing something tangible) and then into deliverables (again, something tangible for each milestone, else you\u2019ll never know if you\u2019ve hit it or not!). \n\nMy personal rule of thumb is that the level of granularity needed on most projects is 2-3 days \u2013 i.e. we should never be more than two to three days from a definitive milestone which will either be complete or not. The added advantage of this approach is that if find yourself off track, you can only be two to three days off track\u2026 much easier to make up than if you went weeks or even months working hard but not actually delivering what was needed!\n\nIn our Christmas dinner example, there are a number of critical milestones \u2013 a tick list of questions. Do we have all the ingredients? Check. Has the turkey been basted? Check. On the actual day, the sequencing and timing will mean more specific questions: It\u2019s 12pm. Are the Brussels sprouts cooked to death yet? Check. (Allowing for the extra hour of boiling to go from soft and green to mushy and brown\u2026 Yeuch!) \n\nTip 3: Actively Manage Risks and Issues\n\nA risk is something that could go wrong. An issue is something that has already gone wrong. Risks and issues are where project management superstars are born. Anyone can manage things when everything is going according to plan; it\u2019s what you do when Cousin Jim refuses to eat anything but strawberry jam sandwiches that sorts the men from the boys. \n\nThe key with a Christmas dinner, as with any project, is to have contingency plans for the most likely and most damaging risks. These depend on your own particular situation, but some examples might be:\n\n \n\t\t\n\t\t\tRISK\n\t\t\tCONTINGENCY PLAN\n\t\t\n\t\t\n\t\t\tCousin Jim is a picky eater.\n\t\t\tHave strawberry jam and sliced white bread on hand to placate.\n\t\t\n\t\t\n\t\t\tPrime organic turkey might not be available at Waitrose on Christmas eve.\n\t\t\tShop in advance!\n\t\t\n\t\t\n\t\t\tYou live somewhere remote that seems to lose power around Christmas on a disturbingly regular basis.\n\t\t\t(number of options here depending on how far you want to go\u2026)\n\n\t\t\t\t\tBuy a backup generator.\n\n\t\t\t\t\tInvent a new cooking method using only candles.\n\n\t\t\t\t\tStock up on \u201cChristmas dinner in a tin\u201d.\n\t\t\n\t\t\n\t\t\tYour mother in law is likely to be annoying.\n\t\t\tBottle of sherry at the ready (whether it\u2019s for you or her, you can decide!).\n\t\t\n \n\n\nThe point of planning in advance is so that most of your issues don\u2019t blindside you \u2013 you can spring into action with the contingency plan immediately. This leaves you with plenty of ingenuity and ability to cope in reserve for those truly unexpected events. \n\nBack in your regular projects, you should have a risk management plan (developed at the beginning of the project and regularly reviewed) as well as an issue list, tracking open, in progress and closed issues. Importantly, your issue list should be separate from any kind of bug list \u2013 issues are at a project level, bugs are at a technical level.\n\nTip 4: Have a Project Board\n\nA project board consists of the overall sponsor of your project (often, but not always, the guy with the cheque book) and typically a business expert and a technical expert to help advise the sponsor. The project board is the entity that is meant to make the big, critical decisions. As a project manager, your role is to prepare a recommendation, but leave the actual decision up to the board. \n\nAdmittedly this is where our Christmas dinner analogy has to stretch the most, but if you imagine that instead of just cooking for your family you are the caterer preparing a Christmas feast for a company. In this case, you obviously want to please the diners who will be eating the food, but key decisions are likely to be taken by whoever is organizing the event. They, in turn, will involve the boss if there are really big decisions that would affect the project drastically \u2013 for instance, having to move it to January, or it exceeding the set budget by a significant amount.\n\nMost projects suffer from not having a project board to consult for these major decisions, or from having the wrong people selected. The first ailment is eased by ensuring that you have a functioning project board, with whom you either meet regularly to update on status, or where there is a special process for convening the board if they are needed. The second problem is a little more subtle. Key questions to ask yourself are:\n\n\n\tWho is funding this project?\n\tWho has the authority to stop the project if it was the right thing to do?\n\tWho are the right business and technical advisors?\n\tWho are the folks who don\u2019t look like they are powerful on the org chart, but in fact might scupper this project? (e.g. administrators, tech support, personal assistants\u2026)\n\n\nTip 5: Finish Unequivocably and Well\n\nNo one is ever uncertain as to when Christmas dinner ends. Once the flaming pudding has been consumed and the cheese tray picked at, the end of the dinner is heralded by groaning and everyone collapsing in their chairs. Different households have different rituals, so you might only open your presents after Christmas dinner (unlikely if you have small children!), or you might round off the afternoon watching the Queen\u2019s speech (in Britland, certainly) or if you live in warmer climes you might round off Christmas dinner with a swim (which was our tradition in Cape Town \u2013 after 30 mins of food settling so you didn\u2019t get cramp, of course!). \n\nThe problem with projects is that they are one time efforts and so nowhere near as ritualized. Unless you have been incredibly lucky, you\u2019ve probably worked on a project where you thought you were finished but seemed unable to lose your \u201czombie customers\u201d \u2013 those folks who just didn\u2019t realise it was over and kept coming back with more and more requests. You might even have fallen prey to this yourself, believing that the website going live was the end of the project and not realising that a number of things still needed to be wrapped up.\n\nThe essence of this final tip is to inject some of that end-of-Christmas finality ritual into your projects. Find your own ritual for closing down projects \u2013 more than just sending the customer the invoice and archiving the files. Consider things like documentation, support structure handover and training to make sure that those zombies are going to the right people (hopefully not you!). \n\nSo, to summarise:\n\n\n\tMake sure you start your projects well \u2013 with an agreed (written) vision of what you\u2019re trying to achieve.\n\tPlan your projects at the right level of detail and in an appropriate format \u2013 never be more than a few days away from knowing for sure whether you\u2019re on track or not.\n\tPlan for likely and important risks and make sure you track and resolve those you actually encounter.\n\tInstitute a project board, made up of the people with the real power over your project.\n\tCreate rituals for closing projects well \u2013 don\u2019t leave anyone in doubt that the project has been delivered, or of who they should go to for further help.", "year": "2008", "author": "Meri Williams", "author_slug": "meriwilliams", "published": "2008-12-16T00:00:00+00:00", "url": "https://24ways.org/2008/what-your-turkey-can-teach-you-about-project-management/", "topic": "business"} {"rowid": 114, "title": "How To Create Rockband'ism", "contents": "There are mysteries happening in the world of business these days. We want something else by now. The business of business has to become more than business. We want to be able to identify ourselves with the brands we purchase and we want them to do good things. We want to feel cool because we buy stuff, and we don\u2019t just want a shopping experience \u2013 we want an engagement with a company we can relate to.\n\nLet me get back to \u201cfeeling cool\u201d \u2013 if we want to feel cool, we might get the companies we buy from to support that. That\u2019s why I am on a mission to make companies into rockbands.\n\nNow when I say rockbands \u2013 I don\u2019t mean the puke-y, drunky, nasty stuff that some people would highlight is also a part of rockbands. Therefore I have created my own word \u201crockband\u2019ism\u201d. This word is the definition of a childhood dream version of being in a rockband \u2013 the feeling of being more respected and loved and cool, than a cockroach or a suit on the floor of a company.\n\nRockband\u2019ism\n\nRockband\u2019ism is what we aspire to, to feel cool and happy.\n\nSo basically what I am arguing is that companies should look upon themselves as rockbands. Because the world has changed, so business needs to change as well.\n\nI have listed a couple of things you could do today to become a rockband, as a person or as a company.\n\n1 \u2013 Give your support to companies that make a difference to their surroundings \u2013 if you are buying electronics look up what the electronic producers are doing of good in the world (check out the Greenpeace Guide to Greener Electronics).\n\n2 \u2013 Implement good karma in your everyday life (and do well by doing good). What you give out you get back at some point in some shape \u2013 this can also be implemented for business.\n\n3 \u2013 WWRD? \u2013 \u201cwhat would a rockband do\u201d? or if you are into Kenny Rogers \u2013 what would he do in any given situation? This will also show yourself where your business or personal integrity lies because you actually act as a person or a rockband you admire.\n\n4 \u2013 Start leading instead of managing \u2013 If we can measure stuff why should we manage it? Leadership is key here instead of management. When you lead you tell people how to reach the stars, when you manage you keep them on the ground.\n\n5 \u2013 Respect and confide in, that people are the best at what they do. If they aren\u2019t, they won\u2019t be around for long. If they are and you keep on buggin\u2019 them, they won\u2019t be around for long either.\n\n6 \u2013 Don\u2019t be arrogant \u2013 Because audiences can\u2019t stand it \u2013 talk to people as a person not as a company.\n\n7 \u2013 Focus on your return on involvement \u2013 know that you get a return on, what you involve yourself in. No matter if it\u2019s bingo, communities, talks, ornithology or un-conferences.\n\n8 \u2013 Find out where you can make a difference and do it. Don\u2019t leave it up to everybody else to save the world.\n\n9 \u2013 Find out what you can do to become an authentic, trustworthy and remarkable company. Maybe you could even think about this a lot and make these thoughts into an actionplan.\n\n10 \u2013 Last but not least \u2013 if you\u2019re not happy \u2013 do something else, become another type of rockband, maybe a soloist of a sort, or an orchestra.\n\nNo more business as usual\n\nThis really isn\u2019t time for more business as usual, our environment (digital, natural, work or any other kind of environment) is changing. You are going to have to change too.\n\nThis article actually sprang from a talk I did at the Shift08 conference in Lisbon in October. In addition to this article for 24 ways I have turned the talk into an eBook that you can get on Toothless Tiger Press for free.\n\nMay you all have a sustainable and great Christmas full of great moments with your loved ones. December is a month for gratitude, enjoyment and love.", "year": "2008", "author": "Henriette Weber", "author_slug": "henrietteweber", "published": "2008-12-07T00:00:00+00:00", "url": "https://24ways.org/2008/how-to-create-rockbandism/", "topic": "business"} {"rowid": 115, "title": "Charm Clients, Win Pitches", "contents": "Over the years I have picked up a number of sales techniques that have lead to us doing pretty well in the pitches we go for. Of course, up until now, these top secret practices have remained firmly locked in the company vault but now I am going to share them with you. They are cunningly hidden within the following paragraphs so I\u2019m afraid you\u2019re going to have to read the whole thing.\n\nOk, so where to start? I guess a good place would be getting invited to pitch for work in the first place.\n\nShameless self promotion\n\nWhat not to do\n\nYou\u2019re as keen as mustard to \u2018sell\u2019 what you do, but you have no idea as to the right approach. From personal experience (sometimes bitter!), the following methods are as useful as the proverbial chocolate teapot:\n\n\n\tCold calling\n\tAdvertising\n\tBidding websites\n\tSales people\n\tNetworking events\n\n\nOk, I\u2019m exaggerating; sometimes these things work. For example, cold calling can work if you have a story \u2013 a reason to call and introduce yourself other than \u201cwe do web design and you have a website\u201d. \u201cWe do web design and we\u2019ve just moved in next door to you\u201d would be fine. \n\nAdvertising can work if your offering is highly specialist. However, paying oodles of dollars a day to Google Ads to appear under the search term \u2018web design\u2019 is probably not the best use of your budget. \n\nSpecialising is, in fact, probably a good way to go. Though it can feel counter intuitive in that you are not spreading yourself as widely as you might, you will eventually become an expert and therefore gain a reputation in your field. Specialism doesn\u2019t necessarily have to be in a particular skillset or technology, it could just as easily be in a particular supply chain or across a market.\n\nTarget audience\n\n\u2018Who to target?\u2019 is the next question. If you\u2019re starting out then do tap-up your family and friends. Anything that comes your way from them will almost certainly come with a strong recommendation. Also, there\u2019s nothing wrong with calling clients you had dealings with in previous employment (though beware of any contractual terms that may prevent this). You are informing your previous clients that your situation has changed; leave it up to them to make any move towards working with you. After all, you\u2019re simply asking to be included on the list of agencies invited to tender for any new work.\n\nLook to target clients similar to those you have worked with previously. Again, you have a story \u2013 hopefully a good one!\n\nSo how do you reach these people?\n\n\n\tMailing lists\n\tForums\n\tWriting articles\n\tConferences / Meetups\n\tSpeaking opportunities\n\tSharing Expertise\n\n\nIn essence: blog, chat, talk, enthuse, show off (a little)\u2026 share.\n\nThere are many ways you can do this. There\u2019s the traditional portfolio, almost obligatory blog (regularly updated of course), podcast, \u2018giveaways\u2019 like Wordpress templates, CSS galleries and testimonials. Testimonials are your greatest friend. Always ask clients for quotes (write them and ask for their permission to use) and even better, film them talking about how great you are.\n\nFinally, social networking sites can offer a way to reach your target audiences. You do have to be careful here though. You are looking to build a reputation by contributing value. Do not self promote or spam!\n\nWriting proposals\n\nIs it worth it?\n\nOk, so you have been invited to respond to a tender or brief in the form of a proposal. Good proposals take time to put together so you need to be sure that you are not wasting your time. There are two fundamental questions that you need to ask prior to getting started on your proposal:\n\n\n\tCan I deliver within the client\u2019s timescales?\n\tDoes the client\u2019s budget match my price?\n\n\nThe timescales that clients set are often plucked from the air and a little explanation about how long projects usually take can be enough to change expectations with regard to delivery. However, if a deadline is set in stone ask yourself if you can realistically meet it. Agreeing to a deadline that you know you cannot meet just to win a project is a recipe for an unhappy client, no chance of repeat business and no chance of any recommendations to other potential clients.\n\nPrice is another thing altogether. So why do we need to know?\n\nThe first reason, and most honest reason, is that we don\u2019t want to do a lot of unpaid pitch work when there is no chance that our price will be accepted. Who would? But this goes both ways \u2013 the client\u2019s time is also being wasted. It may only be the time to read the proposal and reject it, but what if all the bids are too expensive? Then the client needs to go through the whole process again.\n\nThe second reason why we need to know budgets relates to what we would like to include in a proposal over what we need to include. For example, take usability testing. We always highly recommend that a client pays for at least one round of usability testing because it will definitely improve their new site \u2013 no question. But, not doing it doesn\u2019t mean they\u2019ll end up with an unusable turkey. It\u2019s just more likely that any usability issues will crop up after launch.\n\nI have found that the best way to discover a budget is to simply provide a ballpark total, usually accompanied by a list of \u2018likely tasks for this type of project\u2019, in an initial email or telephone response. Expect a lot of people to dismiss you out of hand. This is good. Don\u2019t be tempted to \u2018just go for it\u2019 anyway because you like the client or work is short \u2013 you will regret it.\n\nOthers will say that the ballpark is ok. This is not as good as getting into a proper discussion about what priorities they might have but it does mean that you are not wasting your time and you do have a chance of winning the work. The only real risk with this approach is that you misinterpret the requirements and produce an inaccurate ballpark.\n\nFinally, there is a less confrontational approach that I sometimes use that involves modular pricing. We break down our pricing into quite detailed tasks for all proposals but when I really do not have a clue about a client\u2019s budget, I will often separate pricing into \u2018core\u2019 items and \u2018optional\u2019 items. This has proved to be a very effective method of presenting price.\n\nWhat to include\n\nSo, what should go into a proposal? It does depend on the size of the piece of work. If it\u2019s a quick update for an existing client then they don\u2019t want to read through all your blurb about why they should choose to work with you \u2013 a simple email will suffice.\n\nBut, for a potential new client I would look to include the following:\n\n\n\tYour suitability\n\tSummary of tasks\n\tTimescales\n\tProject management methodology\n\tPricing\n\tTesting methodology\n\tHosting options\n\tTechnologies\n\tImagery\n\tReferences\n\tFinancial information\n\tBiographies\n\n\nHowever, probably the most important aspect of any proposal is that you respond fully to the brief. In other words, don\u2019t ignore the bits that either don\u2019t make sense to you or you think irrelevant. If something is questionable, cover it and explain why you don\u2019t think it is something that warrants inclusion in the project.\n\nShould you provide speculative designs? If the brief doesn\u2019t ask for any, then certainly not. If it does, then speak to the client about why you don\u2019t like to do speculative designs. Explain that any designs included as part of a proposal are created to impress the client and not the website\u2019s target audience. Producing good web design is a partnership between client and agency. This can often impress and promote you as a professional. However, if they insist then you need to make a decision because not delivering any mock-ups will mean that all your other work will be a waste of time.\n\nWalking away\n\nAs I have already mentioned, all of this takes a lot of work. So, when should you be prepared to walk away from a potential job? I have already covered unrealistic deadlines and insufficient budget but there are a couple of other reasons. Firstly, would this new client damage your reputation, particularly within current sectors you are working in? Secondly, can you work with this client? A difficult client will almost certainly lead to a loss-making project.\n\nPerfect pitch\n\nRequirements\n\nIf the original brief didn\u2019t spell out what is expected of you at a presentation then make sure you ask beforehand. The critical element is how much time you have. It seems that panels are providing less and less time these days.\n\nThe usual formula is that you get an hour; half of which should be a presentation of your ideas followed by 30 minutes of questions. This isn\u2019t that much time, particularly for a big project that covers all aspect of web design and production. Don\u2019t be afraid to ask for more time, though it is very rare that you will be granted any.\n\nAsk if there any areas that a) they particularly want you to cover and b) if there are any areas of your proposal that were weak.\n\nAsk who will be attending. The main reason for this is to see if the decision maker(s) will be present but it\u2019s also good to know if you\u2019re presenting to 3 or 30 people.\n\nWho should be there\n\nGenerally speaking, I think two is the ideal number. Though I have done many presentations on my own, I always feel having two people to bounce ideas around with and have a bit of banter with, works well. You are not only trying to sell your ideas and expertise but also yourselves. One of the main things in the panels minds will be \u2013 \u201ccan I work with these people?\u201d\n\nHaving more than two people at a presentation often looks like you\u2019re wheeling people out just to demonstrate that they exist.\n\nWhat makes a client want to hire you?\n\nIn a nutshell: Confidence, Personality, Enthusiasm.\n\nYou can impart confidence by being well prepared and professional, providing examples and demonstrations and talking about your processes. You may find project management boring but pretty much every potential client will want to feel reassured that you manage your projects effectively.\n\nAs well as demonstrating that you know what you\u2019re talking about, it is important to encourage, and be part of, discussion about the project. Be prepared to suggest and challenge and be willing to say \u201cI don\u2019t know\u201d.\n\nAlso, no-one likes a show-off so don\u2019t over promote yourself; encourage them to contact your existing clients.\n\nWhat makes a client like you?\n\nEngaging with a potential client is tricky and it\u2019s probably the area where you need to be most on your toes and try to gauge the reaction of the client. We recommend the following:\n\n\n\tEncourage questions throughout\n\tAsk if you make sense \u2013 which encourages questions if you\u2019re not getting any\n\tHumour \u2013 though don\u2019t keep trying to be funny if you\u2019re not getting any laughs!\n\tBe willing to go off track\n\tRead your audience\n\tEmpathise with the process \u2013 chances are, most of the people in front of you would rather be doing something else\n\tThink about what you wear \u2013 this sounds daft but do you want to be seen as either the \u2018stiff in the suit\u2019 or the \u2018scruffy art student\u2019? Chances are neither character would get hired.\n\n\nDifferentiation\n\nSometimes, especially if you think you are an outsider, it\u2019s worth taking a few risks. I remember my colleague Paul starting off a presentation once with the line (backed up on screen) \u2013 \u201cHeadscape is not a usability consultancy\u201d. This was in response to the clients request to engage a usability consultancy. The thrust of Paul\u2019s argument was that we are a lot more than that.\n\nThis really worked. We were the outside choice but they ended up hiring us. Basically, this differentiated us from the crowd. It showed that we are prepared to take risks and think, dare I say it, outside of the box.\n\nDealing with difficult characters \n\nHow you react to tricky questioning is likely to be what determines whether you have a good or bad presentation. Here are a few of those characters that so often turn up in panels:\n\nThe techie \u2013 this is likely to be the situation where you need to say \u201cI don\u2019t know\u201d. Don\u2019t bluff as you are likely to dig yourself a great big embarrassment-filled hole. Promise to follow up with more information and make sure that you do so as quickly as possible after the pitch. \n\nThe \u2018hard man\u2019 MD \u2013 this the guy who thinks it is his duty to throw \u2018curve ball\u2019 questions to see how you react. Focus on your track record (big name clients will impress this guy) and emphasise your processes.\n\nThe \u2018no clue\u2019 client \u2013 you need to take control and be the expert though you do need to explain the reasoning behind any suggestions you make. This person will be judging you on how much you are prepared to help them deliver the project.\n\nThe price negotiator \u2013 be prepared to discuss price but do not reduce your rate or the effort associated with your proposal. Fall back on modular pricing and try to reduce scope to come within budget. You may wish to offer a one-off discount to win a new piece of work but don\u2019t get into detail at the pitch.\n\nDon\u2019t panic\u2026\n\nIf you go into a presentation thinking \u2018we must win this\u2019 then, chances are, you won\u2019t. Relax and be yourself. If you\u2019re not hitting it off with the panel then so be it. You have to remember that quite often you will be making up the numbers in a tendering process. This is massively frustrating but, unfortunately, part of it. If it\u2019s not going well, concentrate on what you are offering and try to demonstrate your professionalism rather than your personality. Finally, be on your toes, watch people\u2019s reactions and pay attention to what they say and try to react accordingly.\n\nSo where are the secret techniques I hear you ask? Well, using the words \u2018secret\u2019 and \u2018technique\u2019 was probably a bit naughty. Most of this stuff is about being keen, using your brain and believing in yourself and what you are selling rather than following a strict set of rules.", "year": "2008", "author": "Marcus Lillington", "author_slug": "marcuslillington", "published": "2008-12-09T00:00:00+00:00", "url": "https://24ways.org/2008/charm-clients-win-pitches/", "topic": "business"} {"rowid": 156, "title": "Mobile 2.0", "contents": "Thinking 2.0\n\nAs web geeks, we have a thick skin towards jargon. We all know that \u201cWeb 2.0\u201d has been done to death. At Blue Flavor we even have a jargon bucket to penalize those who utter such painfully overused jargon with a cash deposit. But Web 2.0 is a term that has lodged itself into the conscience of the masses. This is actually a good thing.\n\nThe 2.0 suffix was able to succinctly summarize all that was wrong with the Web during the dot-com era as well as the next evolution of an evolving media. While the core technologies actually stayed basically the same, the principles, concepts, interactions and contexts were radically different.\n\nWith that in mind, this Christmas I want to introduce to you the concept of Mobile 2.0. While not exactly a new concept in the mobile community, it is relatively unknown in the web community. And since the foundation of Mobile 2.0 is the web, I figured it was about time for you to get to know each other.\n\nIt\u2019s the Carriers\u2019 world. We just live in it.\n\nBefore getting into Mobile 2.0, I thought first I should introduce you to its older brother. You know the kind, the kid with emotional problems that likes to beat up on you and your friends for absolutely no reason. That is the mobile of today.\n\nThe mobile ecosystem is a very complicated space often and incorrectly compared to the Web. If the Web was a freewheeling hippie \u2014 believing in freedom of information and the unity of man through communities \u2014 then Mobile is the cutthroat capitalist \u2014 out to pillage and plunder for the sake of the almighty dollar. Where the Web is relatively easy to publish to and ultimately make a buck, Mobile is wrought with layers of complexity, politics and obstacles. \n\nI can think of no better way to summarize these challenges than the testimony of Jason Devitt to the United States Congress in what is now being referred to as the \u201ciPhone Hearing.\u201d Jason is the co-founder and CEO of SkyDeck a new wireless startup and former CEO of Vindigo an early pioneer in mobile content.\n\n\n\nAs Jason points out, the mobile ecosystem is a closed door environment controlled by the carriers, forcing the independent publisher to compete or succumb to the will of corporate behemoths.\n\nBut that is all about to change.\n\nIntroducing Mobile 2.0\n\nMobile 2.0 is term used by the mobile community to describe the current revolution happening in mobile. It describes the convergence of mobile and web services, adding portability, ubiquitous connectivity and location-aware services to add physical context to information found on the Web.\n\nIt\u2019s an important term that looks toward the future. Allowing us to imagine the possibilities that mobile technology has long promised but has yet to deliver. It imagines a world where developers can publish mobile content without the current constraints of the mobile ecosystem.\n\nLike the transition from Web 1.0 to 2.0, it signifies the shift away from corporate or brand-centered experiences to user-centered experiences. A focus on richer interactions, driven by user goals. Moving away from proprietary technologies to more open and standard ones, more akin to the Web. And most importantly (from our perspective as web geeks) a shift away from kludgy one-off mobile applications toward using the Web as a platform for content and services.\n\nThis means the world of the Web and the world of Mobile are coming together faster than you can say ARPU (Average Revenue Per User, a staple mobile term to you webbies). And this couldn\u2019t come at a better time. The importance of understanding and addressing user context is quickly becoming a crucial consideration to every interactive experience as the number of ways we access information on the Web increases.\n\nMobile enables the power of the Web, the collective information of millions of people, inherit payment channels and access to just about every other mass media to literally be overlaid on top of the physical world, in context to the person viewing it. \n\nAnyone who can\u2019t imagine how the influence of mobile technology can\u2019t transform how we perform even the simplest of daily tasks needs to get away from their desktop and see the new evolution of information.\n\nThe Instigators\n\nBut what will make Mobile 2.0 move from idillic concept to a hardened market reality in 2008 will be four key technologies. Its my guess that you know each them already.\n\n1. Opera\n\nOpera is like the little train that could. They have been a driving force on moving the Web as we know it on to mobile handsets. Opera technology has proven itself to be highly adaptable, finding itself preloaded on over 40 million handsets, available on televisions sets through Nintendo Wii or via the Nintendo DS.\n\n2. WebKit\n\nMany were surprised when Apple chose to use KHTML instead of Gecko (the guts of Firefox) to power their Safari rendering engine. But WebKit has quickly evolved to be a powerful and flexible browser in the mobile context. WebKit has been in Nokia smartphones for a few years now, is the technology behind Mobile Safari in the iPhone and the iPod Touch and is the default web technology in Google\u2019s open mobile platform effort, Android.\n\n3. The iPhone\n\nThe iPhone has finally brought the concepts and principles of Mobile 2.0 into the forefront of consumers minds and therefore developers\u2019 minds as well. Over 500 web applications have been written specifically for the iPhone since its launch. It\u2019s completely unheard of to see so many applications built for the mobile context in such a short period of time.\n\n4. CSS & Javascript\n\nWeb 2.0 could not exist without the rich interactions offered by CSS and Javascript, and Mobile 2.0 is no different. CSS and Javascript support across multiple phones historically has been, well\u2026 to put it positively\u2026 utter crap.\n\nJavascript finally allows developers to create interesting interactions that support user goals and the mobile context. Specially, AJAX allows us to finally shed the days of bloated Java applications and focus on portable and flexible web applications. While CSS \u2014 namely CSS3 \u2014 allows us to create designs that are as beautiful as they are economical with bandwidth and load times.\n\nWith Leaflets, a collection of iPhone optimized web apps we created, we heavily relied on CSS3 to cache and reuse design elements over and over, minimizing download times while providing an elegant and user-centered design.\n\n\n\nIn Conclusion\n\nIt is the combination of all these instigators that is significantly decreasing the bar to mobile publishing. The market as Jason Devitt describes it, will begin to fade into the background. And maybe the world of mobile will finally start looking more like the Web that we all know and love.\n\nSo after the merriment and celebration of the holiday is over and you look toward the new year to refresh and renew, I hope that you take a seriously consider the mobile medium. \n\nBy this time next year, it is predicted that one-third of humanity will be using mobile devices to access the Web.", "year": "2007", "author": "Brian Fling", "author_slug": "brianfling", "published": "2007-12-21T00:00:00+00:00", "url": "https://24ways.org/2007/mobile-2-0/", "topic": "business"} {"rowid": 158, "title": "10 Ways To Get Design Approval", "contents": "One of the most challenging parts of the web design process is getting design sign off. It can prove time consuming, demoralizing and if you are not careful can lead to a dissatisfied client. What is more you can end up with a design that you are ashamed to include in your portfolio.\n\nHow then can you ensure that the design you produce is the one that gets built? How can you get the client to sign off on your design? Below are 10 tips learnt from years of bitter experience.\n\n1. Define the role of the client and designer\n\nMany of the clients you work with will not have been involved in a web project before. Even if they have they may have worked in a very different way to what you would expect. Take the time at the beginning of the project to explain their role in the design of the site.\n\nThe best approach is to emphasis that their job is to focus on the needs of their users and business. They should concentrate on the broad issues, while you worry about the details of layout, typography and colour scheme.\n\nBy clarifying what you expect from the client, you help them to provide the right kind of input throughout the process.\n\n2. Understand the business\n\nBefore you open up Photoshop or put pen to paper, take the time to make sure you properly understand not only the brief but the organization behind the site. By understanding their business objectives, organizational structure and marketing strategy your design decisions will be better informed.\n\nYou cannot rely upon the brief to provide all of the information you need. It is important to dig deeper and get as good an understanding of their business as possible. This information will prove invaluable when justifying your design decisions.\n\n3. Understand the users\n\nWe all like to think of ourselves as user centric designers, but exactly how much effort do you put into knowing your users before beginning the design process?\n\nTake the time to really understand them the best you can. Try to meet with some real prospective users and get to know their needs. Failing that work with the client to produce user personas to help picture exactly what kind of people they are. \n\nUnderstanding your users not only improves the quality of your work, but also helps move the discussion away from the personal preferences of the client, to the people who\u2019s opinion really matters.\n\n4. Avoid multiple concepts\n\nMany clients like the idea of having the option to choose between multiple design concepts. However, although on the surface this might appear to be a good idea it can ultimately be counterproductive for design sign off.\n\nIn a world of limited budgets it is unwise to waste money on producing designs that are ultimately going to be thrown away. The resources would be better spent refining a single design through multiple iterations.\n\nWhat is more, multiple concepts often cause confusion rather than clarity. It is common for a client to request one element from one design and another from the second. As any designer knows this seldom works.\n\n5. Use mood boards\n\nClients are often better at expressing what they don\u2019t like than what they do. This is one of the reasons why they favour producing multiple design concepts. An alternative less costly approach is to create a series of mood boards. These boards contain a collection of colours, typography and imagery which represent different \u201cmoods\u201d or directions, which the design could take. \n\nMood boards are quick and easy to produce allowing you to try out various design approaches with the client without investing the time needed to produce complete design concepts. This means that by the time you develop a concept the client and designer have already established an understanding about the direction of the design.\n\n6. Say what you like\n\nIt is not uncommon for a client to ask for a design that looks similar to another site they like. The problem is that it can often be hard to establish exactly what it is about the site that attracts them. Also in many cases the sites they like are not something you are keen to emulate!\n\nA better approach that was suggested to me by Andy Budd is to show them sites that you think the design should emulate. Keep a collection of screen captures from well designed sites and pick out a few that are relevant to that particular client. Explain why you feel these designs might suit their project and ask for their feedback. If they don\u2019t like your choices then expose them to more of your collection and see what they pick out.\n\n7. Wireframe the homepage\n\nOften clients find it hard to distinguish between design and content and so sometimes reject a design on the basis that the content is not right. This is particularly true when signing off the homepage.\n\nYou may therefore find it useful to establish the homepage content before producing the design. That way once they see the design they will not be distracted by the content. One of the best ways to do this is by producing a basic wireframe consisting of a series of content boxes. Once this has been approved you will find the sign off of design much easier.\n\n8. Present your designs\n\nAlthough it is true that a good design should speak for itself it still needs presenting to the client. The client needs to understand why you have made the design decisions you have, otherwise they will judge the design purely on personal preference. \n\nTalk them through the design explaining how it meets the needs of their users and business objectives. Refer to the mood boards and preferred sites the client approved and explain how the design is a continuation of those. Never simply email the design through and hope the client interprets your work correctly!\n\n9. Provide written supporting material\n\nUnfortunately, no matter how well you justify the design to the client he is almost certain to want to show it to others. He may need his bosses approval or require internal buy in. At the very least he is going to want to get a second opinion from a friend or colleague.\n\nThe problem with this is that you are not going to be there to present to these people in the same way you did for the client. You cannot expect the client to present your ideas as well as you did. The reality is that you have lost control of how the design is perceived.\n\nOne way to minimize this problem is to provide written documentation supporting the design. This can be a summary of the presentation you gave to the client and allows him to distribute this along with the design. By putting a written explanation with the design you ensure that everybody who sees it gets the same message.\n\n10. Control the feedback\n\nMy final piece of advice for managing design sign off is to control the way you receive feedback. A clients natural inclination will be to give you his personal opinion on the design. This is reinforced because you ask them what they think of the design. Instead ask them what their users will think of the design. Encourage them to think from the users perspective.\n\nAlso encourage them to keep that overarching focus I talked about in my first tip. Their tendency will be to try to improve the design, however that should be your problem not theirs. The role of a client should be to defend the needs of their users and business not do the design. Encourage the client to make comments such as \u201cI am not sure that my female users will like the masculine colours\u201d rather than \u201ccan we make the whole design pink.\u201d It is down to them to identify the problems and for you as the designer to find the most appropriate solution.\n\nSo there you have it. My 10 tips to improve design sign off. Will this ensure design approval every time? Unfortunately not. However it should certainly help smooth the way.", "year": "2007", "author": "Paul Boag", "author_slug": "paulboag", "published": "2007-12-10T00:00:00+00:00", "url": "https://24ways.org/2007/10-ways-to-get-design-approval/", "topic": "business"} {"rowid": 170, "title": "A Pet Project is For Life, Not Just for Christmas", "contents": "I\u2019m excited: as December rolls on, I\u2019m winding down from client work and indulging in a big pet project I\u2019ve been dreaming up for quite some time, with the aim of releasing it early next year. I\u2019ve always been a bit of a sucker for pet projects and currently have a few in the works: the big one, two collaborations with friends, and my continuing (and completely un-web-related) attempt at music. But when I think about the other designers and developers out there whose work I admire, one thing becomes obvious: they\u2019ve all got pet projects! Look around the web and you\u2019ll see that anyone worth their salt has some sort of side project on the go. If you don\u2019t have yours yet, now\u2019s the time!\n\nHave a pet project to collaborate with your friends\n\nIt\u2019s not uncommon to find me staring at my screen, looking at beautiful websites my friends have made, grinning inanely because I feel so honoured to know such talented individuals. But one thing really frustrates me: I hardly ever get to work with these people! Sure, there are times when it\u2019s possible to do so, but due to various project situations, it\u2019s a rarity.\n\nSo, in order to work with my friends, I\u2019ve found the best way is to instigate the collaboration outside of client work; in other words, have a pet project together! Free from the hard realities of budgets, time restraints, and client demands, you and your friends can come up with something purely for your own pleasures. If you\u2019ve been looking for an excuse to work with other designers or developers whose work you love, the pet project is that excuse. They don\u2019t necessarily have to be friends, either: if the respect is mutual, it can be a great way of breaking the ice and getting to know someone. \n\n Figure 1: A forthcoming secret love-child from myself and Tim Van Damme\n\nHave a pet project to escape from your day job\n\nWe all like to moan about our clients and bosses, don\u2019t we? But if leaving your job or firing your evil client just isn\u2019t an option, why not escape from all that and pour your creative energies into something you genuinely enjoy? \n\nIt\u2019s not just about reacting to negativity, either: a pet project is a great way to give yourself a bit of variety. As web designers, our day-to-day work forces us to work within a set of web-related contraints and sometimes it can be demoralising to spend so many hours fixing IE bugs. The perfect antidote? Go and do some print design! If it\u2019s not possible in your day job or client work, the pet project is the perfect place to exercise your other creative muscles. Yes, print design (or your chosen alternative) has its own constraints, but if they\u2019re different to those you experience on a daily basis, it\u2019ll be a welcome relief and you\u2019ll return to your regular work feeling refreshed.\n\n Figure 2: Ligature, Loop & Stem, from Scott Boms & Luke Dorny\n\nHave a pet project to fulfill your own needs\n\nMany pet projects come into being because the designers and/or developers behind them are looking for a tool to accomplish a task and find that it doesn\u2019t exist, thus prompting them to create their own solution. In fact, the very app I\u2019m using to write this article \u2014 Ommwriter, from Herraiz Soto & Co \u2014 was originally a tool they\u2019d created for their internal staff, before releasing it to the public so that it could be enjoyed by others.\n\nJust last week, Tina Roth Eisenberg launched Teux Deux, a pet project she\u2019d designed to meet her own requirements for a to-do list, having found that no existing apps fulfilled her needs. Oh, and it was a collaboration with her studio mate Cameron. Remember what I was saying about working with your friends?\n\n Figure 3: Teux Deux, the GTD pet project that launched just last week\n\nHave a pet project to help people out\n\nOmmwriter and Teux Deux are free for anyone to use. Let\u2019s just think about that for a moment: the creators have invested their time and effort in the project, and then given it away to be used by others. That\u2019s very cool and something we\u2019re used to seeing a lot of in the web community (how lucky we are)! People love free stuff and giving away the fruits of your labour will earn you major kudos. Of course, there\u2019s nothing wrong with making some money, either \u2014 more on that in a second.\n\n Figure 4: Dan Rubin\u2018s extremely helpful Make Photoshop Faster\n\nHave a pet project to raise your profile\n\nSo, giving away free stuff earns you kudos. And kudos usually helps you raise your profile in the industry. We all like a bit of shameless fame, don\u2019t we? But seriously, if you want to become well known, make something cool. It could be free (to buy you the love and respect of the community) or it could be purchasable (if you\u2019ve made something that\u2019s cool enough to deserve hard-earned cash), but ultimately it needs to be something that people will love. \n\n Figure 5: Type designer Jos Buivenga has shot to fame thanks to his beautiful typefaces and \u2018freemium\u2019 business model\n\nIf you\u2019re a developer with no design skills, team up with a good designer so that the design community appreciate its aesthetic. If you\u2019re a designer with no development skills, team up with a good developer so that it works. Oh, and not that I\u2019d recommend you ever do this for selfish reasons, but collaborating with someone you admire \u2014 whose work is well-respected by the community \u2014 will also help raise your profile.\n\nHave a pet project to make money\n\nIn spite of our best hippy-esque intentions to give away free stuff to the masses, there\u2019s also nothing wrong with making a bit of money from your pet project. In fact, if your project involves you having to make a considerable financial investment, it\u2019s probably a good idea to try and recoup those costs in some way.\n\n Figure 6: The success of Shaun Inman\u2018s various pet projects \u2014 Mint, Fever, Horror Vacui, etc. \u2014 have allowed him to give up client work entirely.\n\nA very common way to do that in both the online and offline worlds is to get some sort of advertising. For a slightly different approach, try contacting a company who are relevant to your audience and ask them if they\u2019d be interesting in sponsoring your project, which would usually just mean having their brand associated with yours in some way. This is still a form of advertising but tends to allow for a more tasteful implementation, so it\u2019s worth pursuing. \n\nAdvertising is a great way to cover your own costs and keep things free for your audience, but when costs are considerably higher (like if you\u2019re producing a magazine with high production values, for instance), there\u2019s nothing wrong with charging people for your product. But, as I mentioned above, you\u2019ve got to be positive that it\u2019s worth paying for!\n\nHave a pet project just for fun\n\nSometimes there\u2019s a very good reason for having a pet project \u2014 and sometimes even a viable business reason \u2014 but actually you don\u2019t need any reason at all. Wanting to have fun is just as worthy a motivation, and if you\u2019re not going to have fun doing it, then what\u2019s the point? Assuming that almost all pet projects are designed, developed, written, printed, marketed and supported in our free time, why not do something enjoyable?\n\n Figure 7: Jessica Hische\u2018s beautiful Daily Drop Cap\n\nIn conclusion\n\nThe fact that you\u2019re reading 24 ways shows that you have a passion for the web, and that\u2019s something I\u2019m happy to see in abundance throughout our community. Passion is a term that\u2019s thrown about all over the place, but it really is evident in the work that people do. It\u2019s perhaps most evident, however, in the pet projects that people create. Don\u2019t forget that the very site you\u2019re reading this article on is\u2026 a pet project.\n\nIf you\u2019ve yet to do so, make it a new year\u2019s resolution for 2010 to have your own pet project so that you can collaborate with your friends, escape from your day job, fulfil your own needs, help people out, raise your profile, make money, and \u2014 above all \u2014 have fun.", "year": "2009", "author": "Elliot Jay Stocks", "author_slug": "elliotjaystocks", "published": "2009-12-18T00:00:00+00:00", "url": "https://24ways.org/2009/a-pet-project-is-for-life-not-just-for-christmas/", "topic": "business"} {"rowid": 176, "title": "What makes a website successful? It might not be what you expect!", "contents": "What makes some sites succeed and others fail? Put another way, when you are asked to redesign an existing website, what problems are you looking out for and where do you concentrate your efforts?\n\nI would argue that as web designers we spend too much time looking at the wrong kind of problem.\n\nI recently ran a free open door consultancy clinic to celebrate the launch of my new book (yes I know, two shameless plugs in one sentence). This involved various website owners volunteering their sites for review. Both myself and the audience then provided feedback.\n\nWhat quickly became apparent is that the feedback being given by the audience was biased towards design and development.\n\nAlthough their comments were excellent it focused almost exclusively on the quality of code, site aesthetics and usability. To address these issues in isolation is similar to treating symptoms and ignoring the underlying illness.\n\nCure the illness not the symptoms\n\nPoor design, bad usability and terribly written code are symptoms of bigger problems. Often when we endeavour to address these symptoms, we meet resistance from our clients and become frustrated. This is because our clients are still struggling with fundamental concepts we take for granted.\n\nBefore we can address issues of aesthetics, usability and code, we need to tackle business objectives, calls to action and user tasks. Without dealing with these fundamental principles our clients\u2019 website will fail.\n\nLet me address each in turn:\n\nUnderstand the business objectives\n\nDo you ask your clients why they have a website? It feels like an obvious question. However, it is surprising how many clients do not have an answer.\n\nWithout having a clear idea of the site\u02bcs business objectives, the client has no way to know whether it is succeeding. This means they have no justification for further investment and that leads to quibbling over every penny.\n\nHowever most importantly, without clearly defined business aims they have no standard against which to base their decisions. Everything becomes subjective and that will inevitably lead to problems.\n\nBefore we start discussing design, usability and development, we need to focus our clients on establishing concrete business objectives. This will provide a framework for decision making during the development phase.\n\nThis will not only help the client make decisions, it will also focus them on the business and away from micro managing the design.\n\nEstablish clear calls to action\n\nOnce business objectives have been set this opens up the possibility to establish clear calls to action.\n\nI am amazed at how few website owners can name their calls to action. However, I am even more staggered at how few web designers ask about them.\n\nCalls to action are not just limited to ecommerce sites. Whether you are asking people to sign up for a newsletter or complete a contact us form, every site should have a desired objective for users.\n\nWhat is more, each page of a site should have micro calls to action that always draw users on and never leave them at a dead end.\n\nWithout clearly defined calls to action you cannot successfully design a site, structure the user experience or measure its success. They bring focus to the site and encourage the client to concentrate their efforts on helping people reach those goals.\n\nOf course in order to know if a call to action is going to work, it is necessary to do some user testing.\n\nTest against the right tasks\n\nAs web designers we all like to boast about being \u02bbuser centric\u02bc whatever that means! However, in reality I think many of us are paying lip service to the subject.\n\nSure, we ask our clients about who their users are and maybe even do some usability testing. However, usability testing is no good if we are not asking the right questions.\n\nAgain we find ourselves working on a superficial level rather than tackling the deeper issues.\n\nClients find it relatively easy to tell you who their target audience is. Admittedly the list they come back with is often overly long and contains a lot of edge cases. However, where they begin to struggle is articulating what these users will want to achieve on the website. They know who they want to reach. However, they cannot always tell you why those people would be interested in the site.\n\nThese user tasks are another fundamental building block for any successful website. Although it is important for a website owner to understand what their objectives are and what they want users to do, it is even more important that they understand the users objectives as well.\n\nAgain, this provides context for the decisions they are making about design, usability and functionality. Without it the site will become self serving, largely ignoring the needs of users.\n\nUser tasks help to focus the client\u02bcs mind on the needs of their user, rather than what they can get out of them.\n\nSo am I claiming that design, usability and code do not matter? Well the shocking truth is that to some extent I am!\n\nThe shocking truth\n\nWhether we like it or not there is significant evidence that you can create a successful website with bad design, terrible code and without ever running a usability test session.\n\nYou only need to look at the design of Craigslist or the code of Amazon to see that this is true.\n\nHowever, I do not believe it is possible to build a successful website without business objectives, calls to action and a clear idea of user tasks.\n\nDo not misunderstand me. I do believe design, usability and code matters. I just believe that they only matter if the fundamentals are already in place. These things improve a solid foundation but are no use in their own right.\n\nAs web designers it is our responsibility to ensure fundamental questions are being asked, before we start exploring other issues. If we do not, our websites will look great, be well coded and have gone through endless usability tests, however it will not be truly successful.", "year": "2009", "author": "Paul Boag", "author_slug": "paulboag", "published": "2009-12-04T00:00:00+00:00", "url": "https://24ways.org/2009/what-makes-a-website-successful/", "topic": "business"} {"rowid": 178, "title": "Make Out Like a Bandit", "contents": "If you are anything like me, you are a professional juggler. No, we don\u2019t juggle bowling pins or anything like that (or do you? Hey, that\u2019s pretty rad!). I\u2019m talking about the work that we juggle daily. In my case, I\u2019m a full-time designer, a half-time graduate student, a sometimes author and conference speaker, and an all-the-time social networker. Only two of these \u201cpositions\u201d have actually put any money in my pocket (and, well, the second one takes a lot of money out). Still, this is all part of the work that I do. Your work situation is probably similar. We are workaholics.\n\nSo if we work so much in our daily lives, shouldn\u2019t we be making out like bandits? Umm, honestly, I\u2019m not hitting on you, silly. I\u2019m talking about our success. We work and work and work. Shouldn\u2019t we be filthy, stinking rich? Well\u2026 okay, that\u2019s not quite what I mean either. I\u2019m not necessarily talking about money (though that could potentially be a part of it). I\u2019m talking about success \u2014 as in feeling a true sense of accomplishment and feeling happy about what we do and why we do it.\n\nIt\u2019s important to feel accomplished and a general happiness in our work. To make out like a bandit (or have an incredible amount of success), you can either get lucky or work hard for it. And if you\u2019re going to work hard for it, you might as well make it all meaningful and worthwhile. This is what I strive for in my own work and my life, and the following points I\u2019m sharing with you are the steps I am taking to work toward this.\n\n\n\tI know the price of success: dedication, hard work & an unremitting devotion to the things you want to see happen. \u2014 Frank Lloyd Wright\n\n\nLearn. Participate. Do.\n\nThe best way to get good at something is to keep doing whatever it is you\u2019re doing that you want to be good at. For example, a sushi-enthusiast might take a sushi-making class because she wants to learn to make sushi for herself. It totally makes sense while the teacher demonstrates all the procedures, materials, and methods needed to make good, beautiful sushi. Later, the student goes home and tries to make sushi on her own, she gets totally confused and lost. Okay, I\u2019m not even going to hide it, I\u2019m talking about myself (this happened to me). As much as I love sushi, I couldn\u2019t even begin to make good sushi because I\u2019ve never really practiced.\n\nTake advantage of learning opportunities where possible. Whether you\u2019re learning CSS, Actionscript, or visual design, the best way to grasp how to do things is to participate, practice, do. Apply what you learn in your work. Participation is so vital to your success. If you have problems, let people know, and ask. But definitely practice on your own. And as clich\u00e9 as it may sound, believe in yourself because if you don\u2019t think you can do it, no one else will think you can either.\n\nMaintain momentum\n\nWith whatever it is you\u2019re doing, if you find yourself \u201con a roll\u201d, you should take advantage of that momentum and keep moving. Sure, you\u2019ll definitely want to take breaks here or there, but remember that momentum can be very difficult to obtain again once you\u2019ve lost it. Get it done!\n\nDeal with people\n\nWhether you love or hate people, the fact is, you gotta deal with them \u2014 even the difficult ones. If you\u2019re in a management position, then you know pretty well that most people don\u2019t like being told what to do (even if that\u2019s their job). Find ways to get people excited about what they\u2019re doing. Make people feel that they (and what they do) are needed \u2014 people respond better if they\u2019re valued, not commanded. Even if you\u2019re not in a management position, this still applies to the way you work with your coworkers, clients, vendors, etc.\n\nResolve any conflicts right away. Conflicts will inevitably happen. Move on to how you can improve the situation, and do it as quickly as possible. Don\u2019t spend too much time focusing on whose screw up it is \u2014 nobody feels good in this situation. Also, try to keep people informed on whatever it is you need or what it is you\u2019re doing. If you\u2019re waiting on something from someone, and it\u2019s been a while, don\u2019t be afraid to say something (tactfully). Sometimes people are forgetful \u2014 or just slacking. Hey, it happens!\n\nHelp yourself by helping others\n\nWhat are some of the small, simple things you can do when you\u2019re working that will help the people you work with (and in most cases, will end up helping yourself)? For example: if you\u2019re a designer, perhaps taking a couple minutes now to organize and name your Photoshop layers will end up saving time later (since it will be easier to find things). This is going to help both you and your team. Or, developers: taking some time to write some documentation (even if it\u2019s as simple as a comment in the code, or a well-written commit message) could potentially save valuable time for both you and your team later. Maybe you have to take a little time to sit down with a coworker and explain why something works the way it does. This helps them out tremendously \u2014 and will most likely lead to them respecting you a little more. This is a benefit.\n\nIf you make little things like this a habit, people will notice. People will enjoy working with you. People will trust you and rely on you. Sure, it might seem beneficial at any given moment to be \u201cin it for yourself\u201d (and therefore only helping yourself), but that won\u2019t last very long. Helping others (whether it be a small or large feat) will cause a positive impact in the long run \u2014 and that is what will be more valuable to you and your career.\n\nDo work that is meaningful\n\nOne of the best ways to feel successful about what you do is to feel good and happy about it. And a great way to feel good and happy about what you\u2019re doing is to actually do good. This could be purpose-driven work that focuses on sustainability and environmentalism, or work that helps support causes and charity. Perhaps the work simply inspires people. Or maybe the work is just something you are very passionate about. Whatever the work may be, try working on projects that are meaningful to you. You\u2019ll do well simply by being more motivated and interested. And it\u2019s a double-win if the project is meaningful to others as well.\n\nI feel very fortunate to work at a place like Crush + Lovely, where we have found quite frequently that the projects that inspire people, focus on global and social good, and create some sort of positive impact are the very projects that bring us more paid projects. But more importantly, we are happy and excited to do it. You might not work at a company that takes on those types of projects. But perhaps you have your own personal endeavors that create this excitement for you. Elliot Jay Stocks wrote about having pet projects. Do you take on side projects? What are those projects?\n\nOver the last couple years, I\u2019ve seen some really fantastic side projects come out that are great examples of meaningful work. These projects reflect the passions and goals of the respective designers and developers involved, and therefore become quite successful (because the people involved simply love what they are doing while they\u2019re doing it). Some of these projects include:\n\n\n\tTypedia is a shared encyclopedia of typefaces which serves as a resource to classify, categorize, and connect typefaces. It was founded by Jason Santa Maria, a graphic designer with a love and passion for typography. He created it as a solution to a problem he faced as a designer: finding the right typeface.\n\tHuffduffer was created by Jeremy Keith, a web developer who wanted to create a podcast of inspirational talks \u2014 but after he found that this could be tedious, he decided to create a tool to automate this.\n\tLevel & Tap was created by passionate photographer and web developer, Tom Watson. It began as a photography print store for Tom\u2019s best personal photography. Over time, more photographers were added to the site and the site has grown to become quite a great collection of beautiful photography.\n\tHeat Eat Review is a review blog created by information architect and user experience designer, Abi Jones. As a foodie, she is able to use this passion for this blog, as it focuses on reviewing TV Dinners, Frozen Meals, and Microwavable Foods.\n\tArt in My Coffee, a favorite personal project of my own, is a photo blog of coffee art I created, after I found that my friends and I were frequently posting coffee art photos to Flickr, Twitter, and other websites. After the blog became more popular, I teamed up with Meagan Fisher on the project, who has just as much a passion for coffee art, if not more.\n\n\nSo, what\u2019s important to you?\n\nThis is the very, very important question here. What really matters to you most? Beyond just working on meaningful projects you are passionate about, is the work you\u2019re doing the right work for you, so that you can live a good lifestyle? Scott Boms wrote an excellent article, Burnout, in which he shares his own experience in battling stress and exhaustion, and what he learned from it. You should definitely read the article in its entirety, but a couple of his points that are particularly excellent are:\n\n\n\tMake time for numero uno, in which you make time for the things in life that make you happy\n\tExamine your values, goals, and measures of success, in which you work toward the things you are passionate about, your own personal development, and focusing on the things that matter.\n\n\nA solid work-life balance can be a challenging struggle to obtain. Of course, you can cheat this by finding ways to combine the things you love with the things you do (so then it doesn\u2019t even feel like you\u2019re working \u2014 oh, you sneaky little bandit!). However, there are other factors to consider beyond your general love for the work you\u2019re doing. Take proper care of yourself physically, mentally, and socially.\n\nSo, are you making out like a bandit?\n\nDo you feel accomplished and generally happy with your work? If not, perhaps that is something to focus on for the next year. Consider your work (both in your job as well as any side projects you may take on) and how it benefits you \u2014 present and future. Take any steps necessary to get you to where you need to be. If you are miserable, fix it!\n\nFinally, it\u2019s important to be thankful for the things that matter to you and make you happy. Pass it along everyday. Thank people. It\u2019s a simple thing, really. Saying \u201cthank you\u201d can and will have enormous impact on the people around you. Oh. And, I apologize if the title of this article led you to thinking it would teach you how to be an amazing kisser. That\u2019s a different article entirely for 24 ways to impress your friends!", "year": "2009", "author": "Jina Anne", "author_slug": "jina", "published": "2009-12-21T00:00:00+00:00", "url": "https://24ways.org/2009/make-out-like-a-bandit/", "topic": "business"} {"rowid": 187, "title": "A New Year's Resolution", "contents": "The end of 2009 is fast approaching. Yet another year has passed in a split second. Our Web Designing careers are one year older and it\u2019s time to reflect on the highs and lows of 2009. What was your greatest achievement and what could you have done better? Perhaps, even more importantly, what are your goals for 2010?\n\nSomething that I noticed in 2009 is that being a web designer 24/7; it\u2019s easy to get consumed by the web. It\u2019s easy to get caught up in the blog posts, CSS galleries, web trends and Twitter! Living in this bubble can lead to one\u2019s work becoming stale, boring and basically like everyone else\u2019s work on the web. No designer wants this.\n\nSo, I say on 1st January 2010 let\u2019s make it our New Year\u2019s resolution to create something different, something special or even ground-breaking! Make it your goal to break the mold of current web design trends and light the way for your fellow web designer comrades!\n\nOf course I wouldn\u2019t let you embark on the New Year empty handed. To help you on your way I\u2019ve compiled a few thoughts and ideas to get your brains ticking!\n\nDon\u2019t design for the web, just design\n\nA key factor in creating something original and fresh for the web is to stop thinking in terms of web design. The first thing we need to do is forget the notion of headers, footers, side bars etc. A website doesn\u2019t necessarily need any of these, so even before we\u2019ve started we\u2019ve already limited our design possibilities by thinking in these very conventional and generally accepted web terms. The browser window is a 2D canvas like any other and we can do with it what we like. \n\nWith this in mind we can approach web design from a fresh perspective. We can take inspiration for web design from editorial design, packaging design, comics, poster design, album artwork, motion design, street signage and anything else you can think of. Web design is way more than the just the web and by taking this more wide angled view of what web design is and can be you\u2019ll find there are a thousand more exiting design possibilities.\n\nNote: Try leaving the wire framing till after you\u2019ve gone to town with some initial design concepts. You might find it helps keep your head out of that \u2018web space\u2019 a little bit longer, thus enabling you to think more freely about your design. Really go crazy with these as you can always pull it back into line later. The key is to think big initially and then work backwards. There\u2019s no point restricting your creativity early on because your technical knowledge can foresee problems down the line. You can always sort these problems out later on\u2026 let your creative juices flow!\n\n Inspiration can come from anywhere! (Photo: modomatic)\n\nTry something new!\n\nProgress in web design or in any design discipline is a sort of evolution. Design trends and solutions merge and mutate to create new design trends and hopefully better solutions. This is fine but the real leaps are made when someone has the guts to do something different. \n\nDon\u2019t be afraid to challenge the status quo. To create truly original work you have to be prepared to get it wrong and that\u2019s hard to do. When you\u2019re faced with this challenge just remind yourself that in web design there is rarely a \u2018best way to do something\u2019, or why would we ever do it any other way? \n\nIf you do this and get it right the pay off can be immense. Not only will you work stand out from the crowd by a mile, you will have become a trend setter as opposed to a trend follower.\n\nTell a story with your design\n\nGreat web design is way more than just the aesthetics, functionality or usability. Great web design goes beyond the pixels on the screen. For your website to make a real impact on it\u2019s users it has to connect with them emotionally. So, whether your website is promoting your own company or selling cheese it needs to move people. You need to weave a story into your design. It\u2019s this story that your users will connect with. \n\nTo do this the main ingredients of your design need to be strongly connected. In my head those main ingredients are Copy, Graphic Design, Typography, imagery and colour. \n\nCopy\n\nStrong meaningful copy is the backbone to most great web design work. Pay special attention to strap lines and headlines as these are often the sparks that start the fire. All the other elements can be inspired by this backbone of strong copy.\n\nGraphic Design\n\nUse the copy to influence how you treat the page with your graphic design. Let the design echo the words.\n\nTypography\n\nWhat really excites me about typography isn\u2019t the general text presentation on a page, most half decent web designer have a grasp of this already. What excites me is the potential there is to base a whole design on words and letters. Using the strong copy you already have, one has the opportunity the customise, distort, build and arrange words and letters to create beautiful and powerful compositions that can be the basis for an entire site design.\n\n Get creative with Typography (Photo: Pam Sattler)\n\nImagery and Colour\n\nWith clever use of imagery (photographs or illustrations) and colour you further have the chance to deepen the story you are weaving into your design. The key is to use meaningful imagery, don\u2019t to insert generic imagery for the sake of filling space\u2026 it\u2019s just a wasted opportunity.\n\nRemember, the main elements of your design combined are greater than the sum of their parts. Whatever design decisions you make on a page, make them for a good reason. It\u2019s not good enough to try and seduce your users with slick and shiny web pages. For your site to leave a lasting impression on the user you need to make that emotional connection.\n\n Telling the Story (Advertising Agency: Tita, Milano, Italy, Art Director: Emanuele Basso)\n\nGo one step further\n\nSo you\u2019ve almost finished your latest website design. You\u2019ve fulfilled the brief, you\u2019re happy with the result and you\u2019re pretty sure your client will be too. It\u2019s at this point we should ask ourselves \u201cCan I push this further\u201d? What touches could you add to the site that\u2019ll take it beyond what was required and into something exceptional? The truth is, to produce exceptional work we need to do more than is required of us. We need to answer the brief and then some!\n\nGo back through your site and make a note of what enhancements could be made to make the site not just good but outstanding. It might be revisiting a couple of pages that were neglected in the design process, it might be adding some CSS 3 gloss for the users that can benefit from it or it might just be adding some clever little easter eggs to show that you care. These touches will soon add up and make a massive difference to the finished product.\n\nSo, go one step further\u2026 take it further than you anyone else will. Then your work will stand out for sure.\n\nParting message\n\nI love being a designer for many of reasons but the main one being that with every new project we embark on we have the chance to express ourselves. We have the chance to create something special, something that people will talk about. It\u2019s this chance that drives us onwards day after day, year after year. So in 2010 shout louder than you ever have before, take chances, try something new and above all design your socks off!", "year": "2009", "author": "Mike Kus", "author_slug": "mikekus", "published": "2009-12-10T00:00:00+00:00", "url": "https://24ways.org/2009/a-new-years-resolution/", "topic": "business"} {"rowid": 189, "title": "Ignorance Is Bliss", "contents": "This is a true story.\n\nMeet Mike \n\nMike\u2019s a smart guy. He knows a great browser when he sees one. He uses Firefox on his Windows PC at work and Safari on his Mac at home. Mike asked us to design a Web site for his business. So we did.\n\nWe wanted to make the best Web site for Mike that we could, so we used all of the CSS tools that are available today. That meant using RGBa colour to layer elements, border-radius to add subtle rounded corners and (possibly most experimental of all new CSS), generated gradients.\n\n The home page Mike sees in Safari on his Mac\n\nMike loves what he sees.\n\nMeet Sam\n\nSam works with Mike. She uses Internet Explorer 7 because it came on the Windows laptop that the company bought her when she joined. \n\n The home page Sam sees in Internet Explorer 7 on her PC\n\nSam loves the new Web site too.\n\nHow could both of them be happy when they experienced the Web site differently?\n\nThe new WYSIWYG\n\nWhen I first presented my designs to Mike and Sam, I showed them a Web page made with HTML and CSS in their respective browsers and not a picture of a Web page. By showing neither a static image of my design, I set none of the false expectations that, by definition, a static Photoshop or Fireworks visual would have established.\n\nMike saw rounded corners and subtle shadows in Firefox and Safari. Sam saw something equally as nice, just a little different, in Internet Explorer. Both were very happy because they saw something that they liked.\n\nNeither knew, or needed to know, about the subtle differences between browsers. Their users don\u2019t need to know either.\n\nThat\u2019s because in the real world, people using the Web don\u2019t find a Web site that they like, then open up another browser to check that it looks they same. They simply buy what they came to buy, read what what they came to read, do what they came to do, then get on with their lives in blissful ignorance of what they might be seeing in another browser.\n\nOften when I talk or write about using progressive CSS, people ask me, \u201cHow do you convince clients to let you work that way? What\u2019s your secret?\u201d Secret? I tell them what they need to know, on a need-to-know basis.\n\nEpilogue\n\nSam has a new iPhone that Mike bought for her as a reward for achieving her sales targets. She loves her iPhone and was surprised at just how fast and good-looking the company Web site appears on that. So she asked,\n\n\n\t\u201cAndy, I didn\u2019t know you optimised our site for mobile. I don\u2019t remember seeing an invoice for that.\u201d\n\n\nI smiled.\n\n\n\t\u201cThat one was on the house.\u201d", "year": "2009", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2009-12-23T00:00:00+00:00", "url": "https://24ways.org/2009/ignorance-is-bliss/", "topic": "business"} {"rowid": 196, "title": "Designing a Remote Project", "contents": "I came across an article recently, which I have to admit made my blood boil a little. Yes, I know it\u2019s the season of goodwill and all that, and I\u2019m going to risk sounding a little Scrooge-like, but I couldn\u2019t help it. It was written by someone who\u2019d tried out \u2018telecommuting\u2019 (big sigh) a.k.a. remote or distributed working. They\u2019d tested it in their company and decided it didn\u2019t work. \nWhy did it enrage me so much? Well, this person sounded like they\u2019d almost set it up to fail. To them, it was the latest buzzword, and they wanted to offer their employees a \u2018perk\u2019. But it was going to be risky, because, well, they just couldn\u2019t trust their employees not to be lazy and sit around in their pyjamas at home, watching TV, occasionally flicking their mousepad to \u2018appear online\u2019. Sounds about right, doesn\u2019t it?\nWell, no. This attitude towards remote working is baked in the past, where working from one office and people all sitting around together in a cosy circle singing kum-by-yah* was a necessity not an option. We all know the reasons remote working and flexibility can happen more easily now: fast internet, numerous communication channels, and so on. But why are companies like Yahoo! and IBM backtracking on this? Why is there still such a negative perception of this way of working when it has so much real potential for the future?\n*this might not have ever really happened in an office.\nSo what is remote working? It can come in various formats. It\u2019s actually not just the typical office worker, working from home on a specific day. The nature of digital projects has been changing over a number of years. In this era where organisations are squeezing budgets and trying to find the best value wherever they can, it seems that the days of whole projects being tackled by one team, in the same place, is fast becoming the past. What I\u2019ve noticed more recently is a much more fragmented way of putting together a project \u2013 a mixture of in-house and agency, or multiple agencies or organisations, or working with an offshore team. In the past we might have done the full integrated project from beginning to end, now, it\u2019s a piece of the pie. \nWhich means that everyone is having to work with people who aren\u2019t sat next to them even more than before. Whether that\u2019s a freelancer you\u2019re working with who\u2019s not in the office, an offshore agency doing development or a partner company in another city tackling UX\u2026 the future is looking more and more like a distributed workplace.\nSo why the negativity, man?\nAs I\u2019ve seen from this article, and from examples of large corporations changing their entire philosophy away from remote working, there\u2019s a lot of negativity towards this way of working. Of course if you decide to let everyone work from home when they want, set them off and then expect them all to check in at the right time or be available 24/7 it\u2019s going to be a bit of a mess. Equally if you just jump into work with a team on the other side of the world without any setup, should you expect anything less than a problematic project?\nOkay, okay so what about these people who are going to sit on Facebook all day if we let them work from home? It\u2019s the age old response to the idea of working from home. I can\u2019t see the person, so how do I know what they are doing?\nThis comes up regularly as one of the biggest fears of letting people work remotely. There\u2019s also the perceived lack of productivity and distractions at home. The limited collaboration and communication with distributed workers. The lack of availability. The lower response times. \nHang on a second, can\u2019t these all still be problems even if you\u2019ve got your whole team sat in the same place? \u201cThey won\u2019t focus on work.\u201d How many people will go on Facebook or Twitter whilst sat in an office? \u201cThey won\u2019t collaborate as much.\u201d How many people sit in the office with headphones on to block out distractions? I think we have to move away from the idea that being sat next to people automatically makes them work harder. If the work is satisfying, challenging, and relevant to a person \u2013 surely we should trust them to do it, wherever they are sat?\nThere\u2019s actually a lot of benefits to remote working, and having distributed teams. Offering this as a way of working can attract and retain employees, due to the improved flexibility. There can actually be fewer distractions and disruptions at home, which leads to increased productivity. To paraphrase Jason Fried in his talk \u2018Why work doesn\u2019t happen at work\u2019, at home there are voluntary distractions where you have to choose to distract yourself with something. At the office these distractions become involuntary. Impromptu meetings and people coming to talk to you all the time are actually a lot more disruptive. Often, people find it easier to focus away from the office environment. \nThere\u2019s also the big benefit for a lot of people of the time saved commuting. The employee can actually do a lot that\u2019s beneficial to them in this time, rather than standing squeezed into people\u2019s armpits on public transport. Hence increased job satisfaction. With a distributed team, say if you\u2019re working with an off-shore team, there could be a wider range of talent to pick from and it also encourages diversity. There can be a wider range of cultural differences and opinions brought to a project, which encourages more diverse ways of thinking.\nTackling the issues - or, how to set up a project with a remote team\nBut that isn\u2019t to say running projects with a distributed team or being a remote worker is easy, and can just happen, like that. It needs work \u2013 and good groundwork \u2013 to ensure you don\u2019t set it up to fail. So how do you help create a smoother remote project?\nStart with trust\nFirst of all, the basis of the team needs to be trust. Yes I\u2019m going to sound a little like a cheesy, self-help guru here (perhaps in an attempt to seem less Scrooge-like and inject some Christmas cheer) but you do need to trust the people working remotely as well as them trusting you. This extends to a distributed team. You can\u2019t just tell the offshore team what to do, and micromanage them, scared they won\u2019t do what you want, how you want it because you can\u2019t see them. You need to give them ownership and let them manage the tasks. Remember, people are less likely to criticise their own work. Make them own the work and they are more likely to be engaged and productive.\nSet a structure\nDistributed teams and remote workers can fail when there is no structure \u2013 just as much as teams sitting together fail without it too. It\u2019s not so much setting rules, as having a framework to work within. Eliminate blockers before they happen. Think about what could cause issues for the team, and think of ways to solve this. For example, what do you do if you won\u2019t be able to get hold of someone for a few hours because of a time difference? Put together a contingency, e.g. is there someone else on your time zone you could go to with queries after assessing the priority? Would it be put aside until that person is back in? Define team roles and responsibilities clearly. Sit down at the beginning of the project and clearly set out expectations. Also ask the team, what are their expectations of you?\nThere won\u2019t be a one size fits all framework either. Think about your team, the people in it, the type of project you\u2019re working with, the type of client and stakeholder. This should give you an idea of what sort of communications you\u2019ll need on the project. Daily calls, video calls, Slack channels, the choice is yours.\nDecide on the tools\nTo be honest, I could spend hours talking about the different tools you can use for communication. But you know them, right? And in the end it\u2019s not the tool that\u2019s important here - it\u2019s the communication that\u2019s being done on the tool. Tools need to match the type of communications needed for your team. One caveat here though, never rely solely on email! Emails are silos, and can become beasts to manage communications on.\nTransparency in communication\nGood communication is key. Make sure there are clear objectives for communication. Set up one time during the week where those people meet together, discuss all the work during that week that they\u2019ve done. If decisions are made between team members who are together, make sure everyone knows what these are. But try to make collective decisions where you can, when it doesn\u2019t impact on people\u2019s time.\nHave a face-to-face kick off\nYes, I know this might seem to counter my argument, but face-to-face comms are still really important. If it\u2019s feasible, have an in-person meeting to kick off your project, and to kick off your team working together. An initial meeting, to break the ice, discuss ways of working, set the goals, can go a long way to making working with distributed teams successful. If this is really not viable, then hold a video call with the team. Try to make this a little more informal. I know, I know, not the dreaded cringey icebreakers\u2026 but something to make everyone relax and get to know each other is really important. Bring everybody together physically on a regular basis if you can, for example with quarterly meetings. You\u2019ve got to really make sure people still feel part of a team, and it often takes a little more work with a remote team. Connect with new team members, one-on-one first, then you can have more of a \u2018remote\u2019 relationship. \nGet visual\nVisual communication is often a lot better tool to use than just a written sentence, and can help bring ideas to life. Encourage people to sketch things, take a photo and add this to your written communications. Or use a mockup tool to sketch ideas.\nBut what about Agile projects?\nThe whole premise of Agile projects is to have face-to-face contact I hear you cry. The Agile Manifesto itself states \u201cThe most efficient and effective method of conveying information to and within a development team is face-to-face conversation\u201d. However, this doesn\u2019t mean the death of remote working. In fact loads of successful companies still run Agile projects, whilst having a distributed team. With all the collaborative tools you can use for centralising code, tracking tasks, visualising products, it\u2019s not difficult to still communicate in a way that works. Just think about how to replicate the principles of Agile remotely - working together daily, a supportive environment, trust, and simplicity. How can you translate these to your remote or distributed team? \nOne last thought to leave you with before you run off to eat your mince pies (in your pyjamas, whilst working). A common mistake in working with a remote project team or working remotely yourself, is replacing distance with time. If you\u2019re away from the office you think you need to always be \u2018on\u2019 \u2013 messaging, being online, replying to requests. If you have a distributed team, you might think a lot of meetings, calls, and messages will be good to foster communication. But don\u2019t overload these meetings, calls, and communication. This can be disruptive in itself. Give people the gift of some uninterrupted time to actually do some work, and not feel like they have to check in every second.", "year": "2017", "author": "Suzanna Haworth", "author_slug": "suzannahaworth", "published": "2017-12-06T00:00:00+00:00", "url": "https://24ways.org/2017/designing-a-remote-project/", "topic": "business"} {"rowid": 208, "title": "All That Glisters", "contents": "Tradition has it that at this time of year, families gather together, sit, eat and share stories. It\u2019s an opportunity for the wisdom of the elders to be passed down to the younger members of the tribe. Tradition also has it that we should chase cheese downhill and dunk the nice lady to prove she\u2019s a witch, so maybe let\u2019s not put too much stock in that.\nI\u2019ve been building things on the web professionally for about twenty years, and although the web has changed immeasurably, it\u2019s probably not changed as much as I have. While I can happily say I\u2019m not the young (always right, always arrogant) developer that I once was, unfortunately I\u2019m now an approaching-middle-age developer who thinks he\u2019s always right and on top of it is extremely pompous. What can you do? Nature has devised this system with the distinct advantage of allowing us to always be right, and only ever wrong in the future or in the past. So let\u2019s roll with it.\nIncreasingly, there seems to be a sense of fatigue within our industry. Just when you think you\u2019ve got a handle on whatever the latest tool or technology is, something new comes out to replace it. Suddenly you find that you\u2019ve invested precious time learning something new and it\u2019s already old hat. The pace of change is so rapid, that new developers don\u2019t know where to start, and experienced developers don\u2019t know where it ends. With that in mind, here\u2019s some fireside thoughts from a pompous old developer, that I hope might bring some Christmas comfort.\nReliable and boring beats shiny and new\nThere are so many new tools, frameworks, techniques, styles and libraries to learn. You know what? You don\u2019t have to use them. You\u2019re not a bad developer if you use Grunt even though others have switched to Gulp or Brunch or Webpack or Banana Sandwich. It\u2019s probably misguided to spend lots of project time messing around with build tool fashions when your so last year build tool is already doing what you need.\nJust a little reminder that it\u2019s about 100 times more important what you build than how you build it.\u2014 Chris Coyier (@chriscoyier) December 10, 2017\n\nI think it helps if we understand why so many new solutions exist. Most developers are predisposed to enjoy creating new things more than improving established systems. It\u2019s natural, because it\u2019s actually much easier and more exciting to create something new that works exactly how you think it should be than to improve an existing, imperfect solution. Improving and refactoring a system is hard, and it takes real chops, much more than just building something new.\nThe consequence of this is that new tools appear all the time. A developer will get a fresh new idea of how to tackle a problem \u2013 usually out of dissatisfaction with an existing solution, and figure the best way to implement that idea is to build something new around it. Often, that something new will do the same job as something old that already exists; it will just do it in a different way. Sometimes in a better way. Sometimes, just different.\nxkcd: Standards\nThat\u2019s not to say new tools are bad, and it\u2019s not bad that they exist. We shouldn\u2019t be crushing new ideas, and it\u2019s not wrong to adopt a new solution over an old one, but you know what? There\u2019s no imperative to switch right away. The next time you hit a pain point with your current solution, or have time to re-evaluate, check out what\u2019s new and see how the latest generation of tools and technologies can help. There\u2019s no prize for solving problems you don\u2019t have yet, and heading further into the desert in search of water is a survival tactic, not an aspiration.\nNew is better, but also worse\nSoftware, much like people, is born with a whole lot of potential and not much utility. Newborns \u2014 both digital and meaty \u2014 are exciting and cute but they also lead to sleepless nights and pools of vomit.\nNew technology contains lots of useful new features, but it\u2019s also more likely to contain bugs and be subject to more rapid change. Jumping on a new framework is great, right until there are API changes and you need to refactor your entire project to be able to update. More mature solutions have a higher weight of existing projects on their shoulders, and so the need to maintain backward compatibility is stronger. Things still move forward, but in a more controlled way.\nSo how do we balance the need to move technology forward with the need to provide mature and stable solutions for the projects we work on? I think there\u2019s a couple of good ways to do that.\nGet personal\nUse all the new shiny tools on your side-projects, personal projects, seasonal throw-aways and anywhere where the stakes are low. If you know you can patch around problems without much consequence, go for it. Build your personal blog on a CMS that stores data in the woven bark of a silver birch. Find where it breaks. Find where it excels. Find yourself if you like. When it comes to high-stakes projects, you\u2019ll hopefully have enough experience to know what you\u2019re getting into.\nFocus on the unique problem\nThat\u2019s not to say you should never risk using a new technology for \u2018real\u2019 work. Instead, distinguish the areas of your project where a new technology solves a specifically identified, measurable business objective, verses those where it won\u2019t. \nA brand new web application framework might be fun to use, but are you in the business of solving a web application framework problem? That new web server made of taffeta might increase static file throughput slightly, but are you in the business of serving static assets, or would it be better to just run up nginx and never have to think about that problem again. (Clue: it\u2019s the nginx one.)\nBut when it comes to building that live sports interface for keeping fans up to date with the blow-by-blow of the big game, that\u2019s where it might make sense to take a risk on an amazing-looking new JavaScript realtime interface framework. That\u2019s the time to run up a breakthrough new message queue server that can deliver jobs to workers via extrasensory perception and keep the score updates flowing instantaneously. \nThose are the risks worth taking, as those new technologies have the potential to help you solve your core problems in a markedly improved way. Unproven technology is worth the risk if it solves a specific business objective. If it doesn\u2019t, don\u2019t make work for yourself - use something mature and stable.\nPick the right tools\nOur job as developers is to solve problems using code, and do so in an effective and responsible way. You\u2019ve been hired to use your expertise in picking the right tools for the job, and a big part of that is weighing up the risk verse the reward of each part of the system. The best tools for the job might be something cutting edge, but \u2018best\u2019 can also mean most stable, reliable or easy-to-hire-for.\nGo out and learn (and create!) new tools and experiment with them. Understand what problems they solve and what the pitfalls are. Use them in production for low-stakes projects to get real experience, and then once you really know their character, then think about using them when the stakes are higher.\nThe rest of the time? The tools you\u2019re using now are solid and proven and you know their capabilities and pitfalls well. They might not always be the fashionable candidate, but they often make for a very solid choice.", "year": "2017", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2017-12-24T00:00:00+00:00", "url": "https://24ways.org/2017/all-that-glisters/", "topic": "business"} {"rowid": 224, "title": "Go Forth and Make Awesomeness", "contents": "We\u2019ve all dreamed of being a superhero: maybe that\u2019s why we\u2019ve ended up on the web\u2014a place where we can do good deeds and celebrate them on a daily basis. \n\nWear your dreams\n\nAt age four, I wore my Wonder Woman Underoos around my house, my grandparents\u2019 house, our neighbor\u2019s house, and even around the yard. I wanted to be a superhero when I grew up. I was crushed to learn that there is no school for superheroes\u2014no place to earn a degree in how to save the world from looming evil. Instead, I\u2014like everyone else\u2014was destined to go to ordinary school to focus on ABCs and 123s. Even still, I want to save the world.\n\nIntend your goodness\n\nRandom acts of kindness make a difference. Books, films, and advertising campaigns tout random acts of kindness and the positive influence they can have on the world. But why do acts of kindness have to be so random? Why can\u2019t we intend to be kind? A true superhero wakes each morning intending to perform selfless acts for the community. Why can\u2019t we do the same thing?\n\nAs a child, my mother taught me to plan to do at least three good deeds each day. And even now, years later, I put on my invisible cape looking for ways to do good.\n\nHere are some examples:\n\n\tslowing down to allow another driver in before me from the highway on-ramp\n\tbringing a co-worker their favorite kind of coffee or tea\n\tsharing my umbrella on a rainy day\n\tholding a door open for someone with full hands\n\tlistening intently when someone shares a story\n\tcomplimenting someone on a job well done\n\tthanking someone for a job well done\n\tleaving a constructive, or even supportive comment on someone\u2019s blog\n\n\nAs you can see, these acts are simple. Doing good and being kind is partially about being aware\u2014aware of the words we speak and the actions we take. Like superheroes, we create our own code of conduct to live by. Hopefully, we choose to put the community before ourselves (within reason) and to do our best not to damage it as we move through our lives.\n\nTake a bite out of the Apple\n\nWith some thought, we can weave this type of thinking and action into our business choices. We can take the simple acts of kindness concept and amplify it a bit. With this amplification, we can be a new kind of superhero.\n\nIn 1997, during a presentation, Steve Jobs stated Apple\u2019s core value in a simple, yet powerful, sentence:\n\n\n\tWe believe that people with passion can change the world for the better.\n\n\nApple fan or not, those are powerful words.\n\nDefine your core\n\nEvery organization must define its core values. Core values help us to frame, recognize, and understand the principles our organization embodies and practices. It doesn\u2019t matter if you\u2019re starting a new organization or you want to define values within an existing organization. Even if you\u2019re a freelancer, defining core values will help guide your decisions and actions.\n\nIf you can, work as a team to define core values. Gather the people who are your support system\u2014your business partners, your colleagues, and maybe even a trusted client\u2014this is now your core value creation team. Have a brainstorming session with your team. Let ideas flow. Give equal weight to the things people say. You may not hear everything you thought you might hear\u2014that\u2019s OK. You want the session to be free-flowing and honest. Ask yourself and your team questions like:\n\n\n\tWhat do you think my/our/your core values are?\n\tWhat do you think my/our/your priorities are?\n\tWhat do you think my/our/your core values should be?\n\tWhat do you think my/our/your priorities should be?\n\tHow do you think I/we should treat customers, clients, and each other?\n\tHow do we want others to treat us?\n\tWhat are my/our/your success stories?\n\tWhat has defined these experiences as successful?\n\n\nFrom this brainstorming session, you will craft your superhero code of conduct. You will decide what you will and will not do. You will determine how you will and will not act. You\u2019re setting the standards that you will live and work by\u2014so don\u2019t take this exercise lightly. Take your time. Use the exercise as a way to open a discussion about values. Find out what you and your team believe in. Set these values and keep them in place. Write them down and share these with your team and with the world. By sharing your core values, you hold yourself more accountable to them. You also send a strong message to the rest of the world about what type of organization you are and what you believe in. Other organizations and people may decide to align or not to align themselves with you because of your core values. This is good. Chances are, you\u2019ll be happier and more profitable if you work with other organizations and people who share similar core values.\n\n Photo: Laura Winn\n\nDuring your brainstorming session, list keywords. Don\u2019t edit. Allow things to take their course. Some examples of keywords might be:\n\nAbility \u00b7 Achievement \u00b7 Adventure \u00b7 Ambition \u00b7 Altruism \u00b7 Awareness \u00b7 Balance \u00b7 Caring \u00b7 Charity \u00b7 Citizenship \u00b7 Collaboration \u00b7 Commitment \u00b7 Community \u00b7 Compassion \u00b7 Consideration \u00b7 Cooperation \u00b7 Courage \u00b7 Courtesy \u00b7 Creativity \u00b7 Democracy \u00b7 Dignity \u00b7 Diplomacy \u00b7 Discipline \u00b7 Diversity \u00b7 Education \u00b7 Efficiency \u00b7 Energy \u00b7 Equality \u00b7 Excellence \u00b7 Excitement \u00b7 Fairness \u00b7 Family \u00b7 Freedom \u00b7 Fun \u00b7 Goodness \u00b7 Gratefulness \u00b7 Growth \u00b7 Happiness \u00b7 Harmony \u00b7 Helping \u00b7 Honor \u00b7 Hope \u00b7 Humility \u00b7 Humor \u00b7 Imagination \u00b7 Individuality \u00b7 Innovation \u00b7 Integrity \u00b7 Intelligence \u00b7 Joy \u00b7 Justice \u00b7 Kindness \u00b7 Knowledge \u00b7 Leadership \u00b7 Learning \u00b7 Loyalty \u00b7 Meaning \u00b7 Mindfulness \u00b7 Moderation \u00b7 Modesty \u00b7 Nurture \u00b7 Openness \u00b7 Organization \u00b7 Passion \u00b7 Patience \u00b7 Peace \u00b7 Planning \u00b7 Principles \u00b7 Productivity \u00b7 Purpose \u00b7 Quality \u00b7 Reliability \u00b7 Respectfulness \u00b7 Responsibility \u00b7 Security \u00b7 Sensitivity \u00b7 Service \u00b7 Sharing \u00b7 Simplicity \u00b7 Stability \u00b7 Tolerance \u00b7 Transparency \u00b7 Trust \u00b7 Truthfulness \u00b7 Understanding \u00b7 Unity \u00b7 Variety \u00b7 Vision \u00b7 Wisdom\n\nAfter you have a list of keywords, create your core values statement using the themes from your brainstorming session. There are no rules: while above, Steve Jobs summed up Apple\u2019s core values in one sentence, Zappos has ten core values:\n\n\n\tDeliver WOW Through Service\n\tEmbrace and Drive Change\n\tCreate Fun and A Little Weirdness\n\tBe Adventurous, Creative, and Open-Minded\n\tPursue Growth and Learning\n\tBuild Open and Honest Relationships With Communication\n\tBuild a Positive Team and Family Spirit\n\tDo More With Less\n\tBe Passionate and Determined\n\tBe Humble\n\n\nTo see how Zappos\u2019 employees embrace these core values, watch the video they created and posted on their website.\n\nDog food is yummy\n\nAlthough I find merit in every keyword listed, I\u2019ve distilled my core values to their simplest form:\n\nMake awesomeness. Do good.\n\nHow do you make awesomeness and do good? You need ambition, balance, collaboration, commitment, fun, and you need every keyword listed to support these actions. Again, there are no rules: your core values can be one sentence or a bulleted list. What matters is being true to yourself and creating core values that others can understand. Before I start any project I ask myself: is there a way to make awesomeness and to do good? If the answer is \u201cyes,\u201d I embrace the endeavor because it aligns with my core values. If the answer is \u201cno,\u201d I move on to a project that supports my core values.\n\nUnleash your powers\n\nAlthough every organization will craft different core values, I imagine that you want to be a superhero and that you will define \u201cdoing good\u201d (or something similar) as one of your core values. Whether you work by yourself or with a team, you can use the web as a tool to help do good. It can be as simple as giving a free hug, or something a little more complex to help others and help your organization meet the bottom line. Some interesting initiatives that use the web to do good are:\n\n\n\tYahoo!: How Good Grows\n\tDesigual: Happy Hunters\n\tEdge Shave Gel: Anti-irritation campaign\n\n\n\n\nKnowing your underlying desire to return to your Underoos-and-cape-sporting childhood and knowing that you don\u2019t always have the opportunity to develop an entire initiative to \u201cdo good,\u201d remember that as writers, designers, and developers, we can perform superhero acts on a daily basis by making content, design, and development accessible to the greatest number of people. By considering other people\u2019s needs, we are intentionally performing acts of kindness\u2014we\u2019re doing good. There are many ways to write, design, and develop websites\u2014many of which will be discussed in other 24ways.org articles. As we make content, design, and development decisions\u2014as we develop campaigns and initiatives\u2014we need to keep our core values in mind. It\u2019s easy to make a positive difference in the world. Just be the superhero you\u2019ve always wanted to be. Go forth and make awesomeness.\n\nIf you would like to do good today, support The United Nations Children\u2019s Fund, an organization that works for children\u2019s rights, their survival, development and protection, by purchasing this year\u2019s 24 ways Annual 2010 created by Five Simple Steps. All proceeds go to UNICEF.", "year": "2010", "author": "Leslie Jensen-Inman", "author_slug": "lesliejenseninman", "published": "2010-12-04T00:00:00+00:00", "url": "https://24ways.org/2010/go-forth-and-make-awesomeness/", "topic": "business"} {"rowid": 228, "title": "The Great Unveiling", "contents": "The moment of unveiling our designs should be among our proudest, but it never seems to work out that way. Instead of a chance to show how we can bring our clients\u2019 visions to life, critique can be a tense, worrying ordeal. And yes, the stakes are high: a superb design is only superb if it goes live. Mismanage the feedback process and your research, creativity and hard work can be wasted, and your client may wonder whether you\u2019ve been worth the investment.\n\nThe great unveiling is a pivotal part of the design process, but it needn\u2019t be a negative one. Just as usability testing teaches us whether our designs meet user needs, presenting our work to clients tells us whether we\u2019ve met important business goals. So how can we turn the tide to make presenting designs a constructive experience, and to give good designs a chance to shine through?\n\nTiming is everything\n\nFirst, consider when you should seek others\u2019 opinions. Your personal style will influence whether you show early sketches or wait to demonstrate something more complete. Some designers thrive at low fidelity, sketching out ideas that, despite their rudimentary nature, easily spark debate. Other designers take time to create more fully-realised versions. Some even argue that the great unveiling should be eliminated altogether by working directly alongside the client throughout, collaborating on the design to reach its full potential. \n\nWhatever your individual preference, you\u2019ll rarely have the chance to do it entirely your own way. Contracts, clients, and deadlines will affect how early and often you share your work. However, try to avoid the trap of presenting too late and at too high fidelity. My experience has taught me that skilled designers tend to present their work earlier and allow longer for iteration than novices do. More aware of the potential flaws in their solutions, these designers cling less tightly to their initial efforts. Working roughly and seeking early feedback gives you the flexibility to respond more fully to nuances you may have missed until now.\n\nPlanning design reviews\n\nPresent design ideas face-to-face, or at least via video conference. Asynchronous methods like e-mail and Basecamp are slow, easily ignored, and deny you the opportunity to guide your colleagues through your work. In person, you profit from both the well-known benefits of non-verbal communication, and the chance to immediately respond to questions and elaborate on rationale.\n\nBe sure to watch the numbers at your design review sessions, however. Any more than a handful of attendees and the meeting could quickly spiral into fruitless debate. Ask your project sponsor to appoint a representative to speak on behalf of each business function, rather than inviting too many cooks.\n\nWhere possible, show your work in its native format. Photocopy hand-drawn sketches to reinforce their disposability (the defining quality of a sketch) and encourage others to scribble their own thoughts on top. Show digital deliverables \u2013 wireframes, design concepts, rich interactions \u2013 on screen. The experience of a design is very different on screen than on paper. A monitor has appropriate dimensions and viewport size, presenting an accurate picture of the design\u2019s visual hierarchy, and putting interactive elements in the right context. On paper, a link is merely underlined text. On screen, it is another step along the user\u2019s journey.\n\nDon\u2019t waste time presenting multiple concepts. Not only is it costly to work up multiple concepts to the level required for fair appraisal, but the practice demonstrates a sorry abdication of responsibility. Designers should be custodians of design. Asking for feedback on multiple designs turns the critique process into a beauty pageant, relinquishing a designer\u2019s authority. Instead of rational choices that meet genuine user and business needs, you may be stuck with a Frankensteinian monstrosity, assembled from incompatible parts: \u201cThis header plus the whizzy bit from Version C\u201d.\n\nThis isn\u2019t to say that you shouldn\u2019t explore lots of ideas yourself. Divergent thinking early in the design process is the only way to break free of the clich\u00e9d patterns and fads that so often litter mediocre sites. But you must act as a design curator, choosing the best of your work and explaining its rationale clearly and succinctly. Attitude, then, is central to successful critique. It can be difficult to tread the fine line between the harmful extremes of doormat passivity and prima donna arrogance. Remember that you are the professional, but be mindful that even experts make mistakes, particularly when \u2013 as with all design projects \u2013 they don\u2019t possess all the relevant information in advance. Present your case with open-minded confidence, while accepting that positive critique will make your design (and ultimately your skills) stronger.\n\nThe courage of your convictions\n\nUltimately, your success in the feedback process, and indeed in the entire design process, hinges upon the rationale you provide for your work. Ideally, you should be able to refer to your research \u2013 personas, usability test findings, analytics \u2013 to support your decisions. To keep this evidence in mind, print it out to share at the design review, or include it in your presentation. Explain the rationale behind the most important decisions before showing the design, so that you can be sure of the full attention of your audience.\n\nOnce you\u2019ve covered these points, display your design and walk through the specific features of the page. A little honesty goes a long way here: state your case as strongly as your rationale demands. Sure of your reasoning? Be strong. Speculating an approach based on a hunch? Say so, and encourage your colleagues to explore the idea with you and see where it leads.\n\nOf course, none of these approaches should be sacrosanct. A proficient designer must be able to bend his or her way of working to suit the situation at hand. So sometimes you\u2019ll want to ignore these rules of thumb and explore your own hunches as required. More power to you. As long as you think as clearly about the feedback process as you have about the design itself, you\u2019ll be able to enjoy the great unveiling as a moment to be savoured, not feared.", "year": "2010", "author": "Cennydd Bowles", "author_slug": "cennyddbowles", "published": "2010-12-12T00:00:00+00:00", "url": "https://24ways.org/2010/the-great-unveiling/", "topic": "business"} {"rowid": 229, "title": "Sketching to Communicate", "contents": "As a web designer I\u2019ve always felt that I\u2019d somehow cheated the system, having been absent on the day God handed out the ability to draw. I didn\u2019t study fine art, I don\u2019t have a natural talent to effortlessly knock out a realistic bowl of fruit beside a water jug, and yet somehow I\u2019ve still managed to blag my way this far. I\u2019m sure many of you may feel the same.\n\nI had no intention of becoming an artist, but to have enough skill to convey an idea in a drawing would be useful. Instead, my inadequate instrument would doodle drunkenly across the page leaving a web of unintelligible paths instead of the refined illustration I\u2019d seen in my mind\u2019s eye. This \u2013 and the natural scrawl of my handwriting \u2013 is fine (if somewhat frustrating) when it\u2019s for my eyes only but, when sketching to communicate a concept to a client, such amateur art would be offered with a sense of embarrassment. So when I had the opportunity to take part in some sketching classes whilst at Clearleft I jumped at the chance.\n\nWhy sketch?\n\nIn UX workshops early on in a project\u2019s life, sketching is a useful and efficient way to convey and record ideas. It\u2019s disposable and inexpensive, but needn\u2019t look amateur. A picture may be worth a thousand words, but a well executed sketch of how you\u2019ll combine funny YouTube videos with elephants to make Lolephants.com could be worth millions in venture capital. Actually, that\u2019s not bad\u2026 ;-)\n\nAlthough (as you will see) the basics of sketching are easy to master, the kudos you will receive from clients for being a \u2018proper designer\u2019 makes it worthwhile!\n\nWhere to begin?\n\nStart by not buying yourself a sketch pad. If you were the type of child who ripped the first page out of a school exercise book and started again if you made even a tiny mistake (you\u2019re not alone!), Wreck This Journal may offer a helping hand. Practicing on plain A4 paper instead of any \u2018special\u2019 notepad will make the process a whole lot easier, no matter how deliciously edible those Moleskines look.\n\nDo buy yourself a black fine-liner pen and a set of grey Pro Markers for shading. These pens are unlike any you will have used before, and look like blended watercolours once the ink is dry. Although multiple strokes won\u2019t create unsightly blotches of heavy ink on the page, they will go right through your top sheet so always remember to keep a rough sheet in the second position as an ink blotter.\n\n photo by Tom Harrison\n\nDon\u2019t buy pencils to sketch with, as they lack the confidence afforded by the heavy black ink strokes of marker pens and fine-liners.\n\nIf you\u2019re going to be sketching with clients then invest in some black markers and larger sheets of paper. At the risk of sounding like a stationery brand whore, Sharpies are ideal, and these comedy-sized Post-Its do the job far better than cheaper, less sticky alternatives. Although they\u2019re thicker than most standard paper, be sure to double-layer them if you\u2019re writing on them on a wall, unless you fancy a weekend redecorating your client\u2019s swanky boardroom.\n\nThe best way to build confidence and improve your sketching technique is, obviously, to practise. Reading this article will be of no help unless you repeat the following examples several times each. Go grab a pen and some paper now, and notice how you improve within even a short period of time.\n\nSketching web UI\n\nMost elements of any website can be drawn as a combination of geometric shapes.\n\n photo by Nathanael Boehm\n\nCircles\n\nTo draw a circle, get in position and start by resting your hand on the page and making the circular motion a few times without putting pen to paper. As you lower your pen whilst continuing the motion, you should notice the resulting shape is more regular than it otherwise would have been.\n\nSquares and rectangles\n\nDraw one pair of parallel lines first, followed by the others to complete the shapes. Slightly overlap the ends of the lines to make corners feel more solid than if you were to leave gaps. If you\u2019re drawing a container, always draw the contents first, that way it won\u2019t be a squash to fit them in. If you\u2019re drawing a grid (of thumbnails, for instance), draw all parallel lines first as a series of long dashes to help keep line lengths and angles consistent.\n\n\n\nShadows\n\nTo lift elements from the page for emphasis, add a subtle shadow with a grey marker. For the most convincing look, assume the light source to be at the top left of the page \u2013 the shadow should simply be a thick grey line along the bottom and up the right edge of your shape. If the shape is irregular, the shadow should follow its outline. This is a good way to emphasise featured items, speech bubbles, form buttons, and so on.\n\n\n\nSketching ideas\n\nArrows\n\nUse arrows to show steps in a process or direction of movement. Giving shadows a 3-D feel, or adding a single colour, will help separate them from the rest of the sketch.\n\n\n\nFaces\n\nStart by drawing the circle. The direction of the nose (merely a point) indicates the direction of the person\u2019s gaze. The eyes and mouth show emotion: more open and curvy for happy thoughts; more closed and jagged for angry thoughts. Try out a few shapes and see what emotions they convey.\n\n\n\nPeople\n\nRemember, we\u2019re aiming for communication rather than realism here. A stick man would be fine. Give him a solid body, as shown in this example, and it becomes easier to pose him.\n\n\n\nI know you think hands are hard, but they\u2019re quite important to convey some ideas, and for our purposes we don\u2019t need to draw hands with any detail. An oval with a stick does the job of a pointing hand. Close-ups might need more fingers showing, but still don\u2019t require any degree of realism.\n\nSignage\n\nDon\u2019t be afraid to use words. We\u2019re sketching to communicate, so if the easiest way to show an office block is a building with a big \u2018office\u2019 sign on the roof, that\u2019s fine!\n\n\n\nLabels\n\nLikewise, feel free to label interactions. Use upper-case letters for legibility and slightly angle the horizontal bars upwards to create a more positive feel.\n\nClich\u00e9s\n\nClich\u00e9s are your friend! Someone\u2019s having an idea? Light bulb above the head. Computer\u2019s crashed? Cloud of smoke with \u201c$\u00a3%*!\u201d\n\n\n\n\n\nIt\u2019s good to practise regularly. Try applying these principles to still life, too. Look around you now and draw the cup on the table, or the books on the shelf. Think of it as a combination of shapes and aim for symbolism rather than realism, and it\u2019s not as hard as you\u2019d think.\n\nI hope this has given you the confidence to give it a shot, and the ability to at least not be mortified with the results!\n\nTip: If you\u2019re involving clients in design games like Leisa Reichelt\u2019s \u2018Design Consequences\u2019 it may be wise to tone down the quality of your drawings at that point so they don\u2019t feel intimidated. Remember, it\u2019s important for them to feel at ease with the idea of wireframing in front of you and their colleagues, no matter how bad their line work.\n\nFor more information see davegrayinfo.com \u2013 Dave Gray taught me everything I know :-)", "year": "2010", "author": "Paul Annett", "author_slug": "paulannett", "published": "2010-12-19T00:00:00+00:00", "url": "https://24ways.org/2010/sketching-to-communicate/", "topic": "business"} {"rowid": 250, "title": "Build up Your Leadership Toolbox", "contents": "Leadership. It can mean different things to different people and vary widely between companies. Leadership is more than just a job title. You won\u2019t wake up one day and magically be imbued with all you need to do a good job at leading. If we don\u2019t have a shared understanding of what a Good Leader looks like, how can we work on ourselves towards becoming one? How do you know if you even could be a leader? Can you be a leader without the title?\nWhat even is it?\nI got very frustrated way back in my days as a senior developer when I was given \u201cadvice\u201d about my leadership style; at the time I didn\u2019t have the words to describe the styles and ways in which I was leading to be able to push back. I heard these phrases a lot:\n\nyou need to step up\nyou need to take charge\nyou need to grab the bull by its horns\nyou need to have thicker skin\nyou need to just be more confident in your leading\nyou need to just make it happen\n\nI appreciate some people\u2019s intent was to help me, but honestly it did my head in. WAT?! What did any of this even mean. How exactly do you \u201cstep up\u201d and how are you evaluating what step I\u2019m on? I am confident, what does being even more confident help achieve with leading? Does that not lead you down the path of becoming an arrogant door knob? >___<\nWhile there is no One True Way to Lead, there is an overwhelming pattern of people in positions of leadership within tech industry being held by men. It felt a lot like what people were fundamentally telling me to do was to be more like an extroverted man. I was being asked to demonstrate more masculine associated qualities (#notallmen). I\u2019ll leave the gendered nature of leadership qualities as an exercise in googling for the reader.\nI\u2019ve never had a good manager and at the time had no one else to ask for help, so I turned to my trusted best friends. Books.\nI <3 books\nI refused to buy into that style of leadership as being the only accepted way to be. There had to be room for different kinds of people to be leaders and have different leadership styles.\nThere are three books that changed me forever in how I approach and think about leadership.\n\nPrimal leadership, by Daniel Goleman, Richard Boyatzis and Annie McKee\nQuiet, by Susan Cain\nDaring Greatly - How the Courage to be Vulnerable transforms the way we live, love, parent and Lead, by Bren\u00e9 Brown\n\nI recommend you read them. Ignore the slightly cheesy titles and trust me, just read them.\nPrimal leadership helped to give me the vocabulary and understanding I needed about the different styles of leadership there are, how and when to apply them.\nQuiet really helped me realise how much I was being undervalued and misunderstood in an extroverted world. If I\u2019d had managers or support from someone who valued introverts\u2019 strengths, things would\u2019ve been very different. I would\u2019ve had someone telling others to step down and shut up for a change rather than pushing on me to step up and talk louder over everyone else. It\u2019s OK to be different and needing different things like time to recharge or time to think before speaking. It also improved my ability to work alongside my more extroverted colleagues by giving me an understanding of their world so I could communicate my needs in a language they would get.\nBren\u00e9 Brown\u2019s book I am forever in debt to. Her work gave me the courage to stand up and be my own kind of leader. Even when no-one around me looked or sounded like me, I found my own voice.\nIt takes great courage to be vulnerable and open about what you can and can\u2019t do. Open about your mistakes. Vocalise what you don\u2019t know and asking for help. In some lights, these are seen as weaknesses and many have tried to use them against me, to pull me down and exclude me for talking about them. Dear reader, it did not work, they failed. The truth is, they are my greatest strengths. The privileges I have, I use for good as best and often as I can.\nJust like gender, leadership is not binary\nIf you google for what a leader is, you\u2019ll get many different answers. I personally think Bren\u00e9\u2019s version is the best as it is one that can apply to a wider range of people, irrespective of job title or function.\n\nI define a leader as anyone who takes responsibility for finding potential in people and processes, and who has the courage to develop that potential.\nBren\u00e9 Brown\n\nBeing a leader isn\u2019t about being the loudest in a room, having veto power, talking over people or ignoring everyone else\u2019s ideas. It\u2019s not about \u201ctelling people what to do\u201d. It\u2019s not about an elevated status that you\u2019re better than others. Nor is it about creating a hand wavey far away vision and forgetting to help support people in how to get there.\nBeing a Good Leader is about having a toolbox of leadership styles and skills to choose from depending on the situation. Knowing how and when to apply them is part of the challenge and difficulty in becoming good at it. It is something you will have to continuously work on, forever. There is no Done.\nLeaders are Made, they are not Born.\nBe flexible in your leadership style\n\nTypically, the best, most effective leaders act according to one or more of six distinct approaches to leadership and skillfully switch between the various styles depending on the situation.\n\nFrom the book, Primal Leadership, it gives a summary of 6 leadership styles which are:\n\nVisionary\nCoaching\nAffiliative\nDemocratic\nPacesetting\nCommanding\n\nVisionary, moves people toward a shared dream or future. When change requires a new vision or a clear direction is needed, using a visionary style of leadership helps communicate that picture. By learning how to effectively communicate a story you can help people to move in that direction and give them clarity on why they\u2019re doing what they\u2019re doing.\nCoaching, is about connecting what a person wants and helping to align that with organisation\u2019s goals. It\u2019s a balance of helping someone improve their performance to fulfil their role and their potential beyond.\nAffiliative, creates harmony by connecting people to each other and requires effective communication to aid facilitation of those connections. This style can be very impactful in healing rifts in a team or to help strengthen connections within and across teams. During stressful times having a positive and supportive connection to those around us really helps see us through those times.\nDemocratic, values people\u2019s input and gets commitment through participation. Taking this approach can help build buy-in or consensus and is a great way to get valuable input from people. The tricky part about this style, I find, is that when I gather and listen to everyone\u2019s input, that doesn\u2019t mean the end result is that I have to please everyone.\nThe next two, sadly, are the ones wielded far too often and have the greatest negative impact. It\u2019s where the \u201ctelling people what to do\u201d comes from. When used sparingly and in the right situations, they can be a force for good. However, they must not be your default style.\nPacesetting, when used well, it is about meeting challenging and exciting goals. When you need to get high-quality results from a motivated and well performing team, this can be great to help achieve real focus and drive. Sadly it is so overused and poorly executed it becomes the \u201cjust make it happen\u201d and driver of unrealistic workload which contributes to burnout.\nCommanding, when used appropriately soothes fears by giving clear direction in an emergency or crisis. When shit is on fire, you want to know that your leadership ability can help kick-start a turnaround and bring clarity. Then switch to another style. This approach is also required when dealing with problematic employees or unacceptable behaviour.\nCommanding style seems to be what a lot of people think being a leader is, taking control and commanding a situation. It should be used sparingly and only when absolutely necessary.\nBe responsible for the power you wield\nIf reading through those you find yourself feeling a bit guilty that maybe you overuse some of the styles, or overwhelmed that you haven\u2019t got all of these down and ready to use in your toolbox\u2026\nTake a breath. Take responsibility. Take action.\nNo one is perfect, and it\u2019s OK. You can start right now working on those. You can have a conversation with your team and try being open about how you\u2019re going to try some different styles. You can be vulnerable and own up to mistakes you might\u2019ve made followed with an apology. You can order those books and read them. Those books will give you more examples on those leadership styles and help you to find your own voice.\nThe impact you can have on the lives of those around you when you\u2019re a leader, is huge. You can help be that positive impact, help discover and develop potential in someone.\n\nTime spent understanding people is never wasted.\nCate Huston.\n\nI believe in you. <3 Mazz.", "year": "2018", "author": "Mazz Mosley", "author_slug": "mazzmosley", "published": "2018-12-10T00:00:00+00:00", "url": "https://24ways.org/2018/build-up-your-leadership-toolbox/", "topic": "business"} {"rowid": 254, "title": "What I Learned in Six Years at GDS", "contents": "When I joined the Government Digital Service in April 2012, GOV.UK was just going into public beta. GDS was a completely new organisation, part of the Cabinet Office, with a mission to stop wasting government money on over-complicated and underperforming big IT projects and instead deliver simple, useful services for the public.\nLots of people who were experts in their fields were drawn in by this inspiring mission, and I learned loads from working with some true leaders. Here are three of the main things I learned.\n1. What is the user need?\n\u2028The main discipline I learned from my time at GDS was to always ask \u2018what is the user need?\u2019 It\u2019s very easy to build something that seems like a good idea, but until you\u2019ve identified what problem you are solving for the user, you can\u2019t be sure that you are building something that is going to help solve an actual problem.\nA really good example of this is GOV.UK Notify. This service was originally conceived of as a status tracker; a \u201cwhere\u2019s my stuff\u201d for government services. For example, if you apply for a passport online, it can take up to six weeks to arrive. After a few weeks, you might feel anxious and phone the Home Office to ask what\u2019s happening. The idea of the status tracker was to allow you to get this information online, saving your time and saving government money on call centres.\nThe project started, as all GDS projects do, with a discovery. The main purpose of a discovery is to identify the users\u2019 needs. At the end of this discovery, the team realised that a status tracker wasn\u2019t the way to address the problem. As they wrote in this blog post: \n\nStatus tracking tools are often just \u2018channel shift\u2019 for anxiety. They solve the symptom and not the problem. They do make it more convenient for people to reduce their anxiety, but they still require them to get anxious enough to request an update in the first place.\n\nWhat would actually address the user need would be to give you the information before you get anxious about where your passport is. For example, when your application is received, email you to let you know when to expect it, and perhaps text you at various points in the process to let you know how it\u2019s going. So instead of a status tracker, the team built GOV.UK Notify, to make it easy for government services to incorporate text, email and even letter notifications into their processes.\nMaking sure you know your user\nAt GDS user needs were taken very seriously. We had a user research lab on site and everyone was required to spend two hours observing user research every six weeks. Ideally you\u2019d observe users working with things you\u2019d built, but even if they weren\u2019t, it was an incredibly valuable experience, and something you should seek out if you are able to.\nEven if we think we understand our users very well, it is very enlightening to see how users actually use your stuff. Partly because in technology we tend to be power users and the average user doesn\u2019t use technology the same way we do. But even if you are building things for other developers, someone who is unfamiliar with it will interact with it in a way that may be very different to what you have envisaged.\nUser needs is not just about building things\nAsking the question \u201cwhat is the user need?\u201d really helps focus on why you are doing what you are doing. It keeps things on track, and helps the team think about what the actual desired end goal is (and should be). \nThinking about user needs has helped me with lots of things, not just building services. For example, you are raising a pull request. What\u2019s the user need? The reviewer needs to be able to easily understand what the change you are proposing is, why you are proposing that change and any areas you need particular help on with the review. \nOr you are writing an email to a colleague. What\u2019s the user need? What are you hoping the reader will learn, understand or do as a result of your email?\n2. Make things open: it makes things better\nThe second important thing I learned at GDS was \u2018make things open: it makes things better\u2019. This works on many levels: being open about your strategy, blogging about what you are doing and what you\u2019ve learned (including mistakes), and \u2013 the part that I got most involved in \u2013 coding in the open.\nTalking about your work helps clarify it\nOne thing we did really well at GDS was blogging \u2013 a lot \u2013 about what we were working on. Blogging about what you are working on is is really valuable for the writer because it forces you to think logically about what you are doing in order to tell a good story. If you are blogging about upcoming work, it makes you think clearly about why you\u2019re doing it; and it also means that people can comment on the blog post. Often people had really useful suggestions or clarifying questions.\nIt\u2019s also really valuable to blog about what you\u2019ve learned, especially if you\u2019ve made a mistake. It makes sure you\u2019ve learned the lesson and helps others avoid making the same mistakes. As well as blogging about lessons learned, GOV.UK also publishes incident reports when there is an outage or service degradation. Being open about things like this really engenders an atmosphere of trust and safe learning; which helps make things better.\nCoding in the open has a lot of benefits\nIn my last year at GDS I was the Open Source Lead, and one of the things I focused on was the requirement that all new government source code should be open. From the start, GDS coded in the open (the GitHub organisation still has the non-intuitive name alphagov, because it was created by the team doing the original Alpha of GOV.UK, before GDS was even formed).\nWhen I first joined GDS I was a little nervous about the fact that anyone could see my code. I worried about people seeing my mistakes, or receiving critical code reviews. (Setting people\u2019s mind at rest about these things is why it\u2019s crucial to have good standards around communication and positive behaviour - even a critical code review should be considerately given). \nBut I quickly realised there were huge advantages to coding in the open. In the same way as blogging your decisions makes you think carefully about whether they are good ones and what evidence you have, the fact that anyone in the world could see your code (even if, in practice, they probably won\u2019t be looking) makes everyone raise their game slightly. The very fact that you know it\u2019s open, makes you make it a bit better.\nIt helps with lots of other things as well, for example it makes it easier to collaborate with people and share your work. And now that I\u2019ve left GDS, it\u2019s so useful to be able to look back at code I worked on to remember how things worked.\nShare what you learn\nIt\u2019s sometimes hard to know where to start with being open about things, but it gets easier and becomes more natural as you practice. It helps you clarify your thoughts and follow through on what you\u2019ve decided to do. Working at GDS when this was a very important principle really helped me learn how to do this well.\n3. Do the hard work to make it simple (tech edition)\n\u2018Start with user needs\u2019 and \u2018Make things open: it makes things better\u2019 are two of the excellent government design principles. They are all good, but the third thing that I want to talk about is number 4: \u2018Do the hard work to make it simple\u2019, and specifically, how this manifests itself in the way we build technology.\nAt GDS, we worked very hard to do the hard work to make the code, systems and technology we built simple for those who came after us. For example, writing good commit messages is taken very seriously. There is commit message guidance, and it was not unusual for a pull request review to ask for a commit message to be rewritten to make a commit message clearer.\nWe worked very hard on making pull requests good, keeping the reviewer in mind and making it clear to the user how best to review it.\nReviewing others\u2019 pull requests is the highest priority so that no-one is blocked, and teams have screens showing the status of open pull requests (using fourth wall) and we even had a \u2018pull request seal\u2019, a bot that publishes pull requests to Slack and gets angry if they are uncommented on for more than two days.\nMaking it easier for developers to support the site\nAnother example of doing the hard work to make it simple was the opsmanual. I spent two years on the web operations team on GOV.UK, and one of the things I loved about that team was the huge efforts everyone went to to be open and inclusive to developers.\nThe team had some people who were really expert in web ops, but they were all incredibly helpful when bringing me on board as a developer with no previous experience of web ops, and also patiently explaining things whenever other devs in similar positions came with questions. \nThe main artefact of this was the opsmanual, which contained write-ups of how to do lots of things. One of the best things was that every alert that might lead to someone being woken up in the middle of the night had a link to documentation on the opsmanual which detailed what the alert meant and some suggested actions that could be taken to address it.\nThis was important because most of the devs on GOV.UK were on the on-call rota, so if they were woken at 3am by an alert they\u2019d never seen before, the opsmanual information might give them everything they needed to solve it, without the years of web ops training and the deep familiarity with the GOV.UK infrastructure that came with working on it every day.\nDevelopers are users too\nDoing the hard work to make it simple means that users can do what they need to do, and this applies even when the users are your developer peers. At GDS I really learned how to focus on simplicity for the user, and how much better this makes things work.\nThese three principles help us make great things\nI learned so much more in my six years at GDS. For example, the civil service has a very fair way of interviewing. I learned about the importance of good comms, working late, responsibly and the value of content design.\nAnd the real heart of what I learned, the guiding principles that help us deliver great products, is encapsulated by the three things I\u2019ve talked about here: think about the user need, make things open, and do the hard work to make it simple.", "year": "2018", "author": "Anna Shipman", "author_slug": "annashipman", "published": "2018-12-08T00:00:00+00:00", "url": "https://24ways.org/2018/what-i-learned-in-six-years-at-gds/", "topic": "business"} {"rowid": 266, "title": "Collaborative Development for a Responsively Designed Web", "contents": "In responsive web design we\u2019ve found a technique that allows us to design for the web as a medium in its own right: one that presents a fluid, adaptable and ever changing canvas.\n\nUntil this point, we gave little thought to the environment in which users will experience our work, caring more about the aggregate than the individual. The applications we use encourage rigid layouts, whilst linear processes focus on clients signing off paintings of websites that have little regard for behaviour and interactions. The handover of pristine, pixel-perfect creations to developers isn\u2019t dissimilar to farting before exiting a crowded lift, leaving front-end developers scratching their heads as they fill in the inevitable gaps. If you haven\u2019t already, I recommend reading Drew\u2019s checklist of things to consider before handing over a design.\n\nSomehow, this broken methodology has survived for the last fifteen years or so. Even the advent of web standards has had little impact. Now, as we face an onslaught of different devices, the true universality of the web can no longer be ignored.\n\nResponsive web design is just the thin end of the wedge. Largely concerned with layout, its underlying philosophy could ignite a trend towards interfaces that adapt to any number of different variables: input methods, bandwidth availability, user preference \u2013 you name it!\n\nWith such adaptability, a collaborative and iterative process is required. Ethan Marcotte, who worked with the team behind the responsive redesign of the Boston Globe website, talked about such an approach in his book:\n\n\n\tThe responsive projects I\u2019ve worked on have had a lot of success combining design and development into one hybrid phase, bringing the two teams into one highly collaborative group.\n\n\nWhilst their process still involved the creation of desktop-centric mock-ups, these were presented to the entire team early on, where questions about how pages might adapt and behave at different sizes were asked. Mock-ups were quickly converted into HTML prototypes, meaning further decisions could be based on usage rather than guesswork (and endless hours spent in Photoshop).\n\nRegardless of the exact process, it\u2019s clear that the relationship between our two disciplines is more crucial than ever. Yet, historically, it seems a wedge has been driven between us \u2013 perhaps a result of segregation and waterfall-style processes \u2013 resulting in animosity.\n\nSo how can we improve this relationship? Ultimately, we\u2019ll need to adapt, but even within existing workflows we can start to overlap. Simply adjusting our attitude can effect change, and bring design and development teams closer together.\n\n\n\tGood design is constant contact.\n\n\tMark Otto\n\n\nThe way we work needs to be more open and inclusive. For example, ensuring members of the development team attend initial kick-off meetings and design workshops will not only ensure technical concerns are raised, but mean that those implementing our designs better understand the problems we\u2019re trying to solve.\n\nIt can also be useful at this stage to explain how you work and the sort of deliverables you expect to produce. This will give developers a chance to make recommendations on how these can be optimized for their own needs.\n\nYou may even find opportunities to share the load. On a recent project I worked on, our development partners offered to produce the interactive prototypes needed for user testing. This allowed us to concentrate on refining the experience, whilst they were able to get a head start on building the product.\n\nWhile developers should be involved at the beginning of projects, it\u2019s also important that designers are able to review and contribute to a product as it\u2019s being built. Any handover should be done in person, and ideally you\u2019ll have a day set aside to do so. Having additional budget available for follow-up design reviews is also recommended. Learning how to use version control tools like Subversion or Git will allow you to work within the same environment as developers, and allow you to contribute code or graphic assets directly to a project if needed.\n\nDon\u2019t underestimate the benefits of designer and developer sitting next to each other. Subtle nuances can be explored far more easily than if they were conducted over email or phone. As Ethan writes, \u201c\u2018Design\u2019 is the means, not merely the end; the path we walk over the course of a project, the choices we make\u201d.\n\nIt\u2019s from collaboration like this that I\u2019ve become fond of producing visual style guides. These demonstrate typographic treatments for common markup and patterns (blockquotes, lists, pagination, basic form controls and so on). Thinking in terms of components rather than individual pages not only fits in better with how a developer will implement a site, but can also ensure your design works as a coherent whole.\n\nDespite the amount of research and design produced, when it comes to the crunch, there will always be a need for compromise. As the old saying goes, \u2018fast, cheap and good \u2013 pick two.\u2019 It\u2019s important that you know which pieces are crucial to a design and which areas can allow for movement. Pick your battles wisely. Having an agreed set of design principles can be useful when making such decisions, as they help everyone focus on the goals of the project.\n\n\n\tThe best compromises are reached when both sides understand the issues of the other.\n\n\tRichard Rutter\n\n\nUltimately, better collaboration comes through a shared understanding of the different competencies required to build a website. Instead of viewing ourselves in terms of discrete roles, we should instead look to emphasize our range of abilities, and work with others whose skills are complementary.\n\nPerhaps somebody who actively seeks to broaden their knowledge is the mark of a professional. Seek these people out.\n\nThe best developers I\u2019ve worked with have a respect for design, probably having attempted to do some themselves! Having wrangled with a few MySQL databases myself, I certainly believe the obverse is true. While knowing HTML won\u2019t necessarily make you a better designer, it will help you understand the issues being faced by a front-end developer and, more importantly, allow you to offer solutions or alternative approaches.\n\nSo take a moment to think about how you work with developers and how you could improve your relationship with them. What are you doing to ease the path towards our collaborative future?", "year": "2011", "author": "Paul Lloyd", "author_slug": "paulrobertlloyd", "published": "2011-12-05T00:00:00+00:00", "url": "https://24ways.org/2011/collaborative-development-for-a-responsively-designed-web/", "topic": "business"} {"rowid": 268, "title": "Getting the Most Out of Google Analytics", "contents": "Something a bit different for today\u2019s 24 ways article. For starters, I\u2019m not a designer or a developer. I\u2019m an evil man who sells things to people on the internet. Second, this article will likely be a little more nebulous than you\u2019re used to, since it covers quite a number of points in a relatively short space. \n\nThis isn\u2019t going to be the complete Google Analytics Conversion University IQ course compressed into a single article, obviously. What it will be, however, is a primer on setting up and using Google Analytics in real life, and a great deal of what I\u2019ve learned using Google Analytics nearly every working day for the past six (crikey!) years.\n\nAlso, to be clear, I\u2019ll be referencing new Google Analytics here; old Google Analytics is for loooosers (and those who want reliable e-commerce conversion data per site search term, natch).\n\nYou may have been running your Analytics account for several years now, dipping in and out, checking traffic levels, seeing what\u2019s popular\u2026 and that\u2019s about it. Google Analytics provides so much more than that, but the number of reports available can often intimidate users, and documentation and case studies on their use are minimal at best. \n\nLet\u2019s start! Setting up your Analytics profile\n\nBefore we plough on, I just want to run through a quick checklist that some basic settings have been enabled for your profile. If you haven\u2019t clicked it, click the big cog on the top-right of Google Analytics and we\u2019ll have a poke about.\n\n\n\tIf you have an e-commerce site, e-commerce tracking has been enabled\u2028\n\tIf your site has a search function, site search tracking has been enabled.\n\tQuery string parameters that you do not want tracked as separate pages have been excluded (for example, any parameters needed for your platform to function, otherwise you\u2019ll get multiple entries for the same page appearing in your reports)\n\tFilters have been enabled on your main profile to exclude your office IP address and any IPs of people who frequently access the site for work purposes. In decent numbers they tend to throw data off a tad.\u2028\n\tYou may also find the need to set up multiple profiles prefiltered for specific audience segments. For example, at Lovehoney we have seventeen separate profiles that allow me quick access to certain countries, devices and traffic sources without having to segment first. You\u2019ll also find load time for any complex reports much improved. Use the same filter screen as above to set up a series of profiles that only include, say, mobile visits, or UK visitors, so you can quickly analyse important segments.\n\n\nMatt, what\u2019s a segment?\n\nA segment is a subsection of your visitor base, which you define and then call on in reports to see specific data for that subsection. For example, in this report I\u2019ve defined two segments, the first for IE6 users and the second for IE7.\n\n\n\nSegments are easily created by clicking the Advanced Segments tabs at the top of any report and clicking +New Custom Segment.\n\n\n\nWhat does your site do?\n\nUnderstanding the goals of your site is an oft-covered topic, but it\u2019s necessary not just to form a better understand of your business and prioritize your time. Understanding what you wish visitors to do on your site translates well into a goal-driven analytics package like Google Analytics. \n\nEvery site exists essentially to sell something, either financially through e-commerce, or to sell an idea or impart information, get people to download a CV or enquire about service, or to sell space on that website to advertisers. If the site did not provide a positive benefit to its owners, it would not have a reason for being. \n\nOnce you have understood the reason why you have a site, you can map that reason on to one of the three goal types Google Analytics provides. \n\nE-commerce \n\nThis conversion type registers transactions as part of a sales process which requires a monetary value, what products have been bought, an SKU (stock keeping unit), affiliation (if you\u2019re then attributing the sale to a third party or franchise) and so on.\n\nThe benefit of e-commerce tracking is not only assigning non-arbitrary monetary value to behaviour of visitors on your site, as well as being able to see ancillary costs such as shipping, but seeing product-level information, like which products are preferred from various channels, popular categories, and so on.\n\n\n\nHowever, I find the e-commerce tracking options also useful for non-e-commerce sites. For example, if you\u2019re offering downloads or subscriptions and having an email address or user\u2019s details is worth something to you, you can set up e-commerce tracking to understand how much value your site is bringing. For example, an email address might be worth 20p to you, but if it also includes a name it\u2019s worth 50p. A contact telephone number is worth \u00a32, and so on.\n\nPage goals\n\nPage goals, unsurprisingly, track a visit to a page (often with a sequence of pages leading up to that page). This is what\u2019s referred to as a goal funnel, and is generally used to track how visitors behave in a multistep checkout. \n\n\n\nInterestingly, the page doesn\u2019t have to actually exist. For example, if you have a single page checkout, you can register virtual page views using trackPageview() when a visitor clicks into a particular section of the checkout or other form. If your site is geared towards getting someone to a particular page, but where there isn\u2019t a transaction (for example, a subscription page) this is for you.\n\nThere are also behavioural goals, such as time on site and number of pages viewed, which are geared towards sites that make money from advertising.\n\nBut, going back to the page goals, these can be abstracted using regular expressions, meaning that you can define a funnel based on page type rather than having to set individual folders.\n\n\n\nIn this example, I\u2019ve created regexes for the main page types on my site, so I can create a wide funnel that captures visitors from where they enter through to checkout.\n\nEvents\n\nEvent tracking registers a predefined event, such as playing a video, or some interaction that can trigger JavaScript, such as a Tweet This button. Events can then be triggered using the trackEvent() call. If you want someone to complete watching a video, you would code your player to fire trackEvent() upon completion. \n\nWhile I don\u2019t use events as goals, I use events elsewhere to see how well a video play aids to conversion. This not only helps me justify the additional spend on creating video content, but also quickly highlights which videos are underperforming as sales tools.\n\n\n\nWhat a visitor can tell you\n\n\u2028Now you have some proper goals set up, we can start to see how changes in content (on-site and external) affect those goals. \n\nUltimately, when a visitor comes to your site, they bring information with them:\n\n\n\twhere they came from (a search engine \u2013 including: keyword searched for; a referral; direct; affiliate; or ad campaign)\n\tdemographics (country; whether they\u2019re new or returning, within thirty days)\n\ttechnical information (browser; screen size; device; bandwidth)\n\tsite-specific information (landing page; next click; previous values assigned to them as custom variables*)\n\n\n * A note about custom variables. There\u2019s no hope in hell that I can cover custom variables in this article. Go research them. Custom variables are the single best way to hack Google Analytics and bend it to your will. Custom variables allow you to record anything you want about a visitor, which that visitor will then carry around with them between visits. It\u2019s also great for plugging other services into Google Analytics (as shown by the marvelous way Visual Website Optimizer allows you to track and segment tests within the GA interface). Just make sure not to breach the terms of service, eh?\n\nCSI your website\n\nPolice procedural TV shows are all the same: the investigators are called to a crime and come across a clue; there\u2019s then an autopsy; new evidence leads them to a new location; they find a new clue; they put two and two together; they solve the mystery.\n\nThis is your life now. Exciting!\n\nSo, now you\u2019re gathering a wealth of information about what sort of people visit your site, what they do when they\u2019re there, and what eventually gets them to drive value to you. It\u2019s now your job to investigate all these little clues to see which types of people drive the most value, and what you can change to improve it.\n\nMaybe not that exciting.\n\nHowever, Google Analytics comes pre-armed with extensive reports for you to delve into. As an e-commerce guy (as opposed to a page goal guy) my day pretty much follows the pattern below.\n\n\n\tLook at e-commerce conversion rate by traffic source compared to the same day in the previous week and previous month. As ours is an e-commerce site, we have weekly and monthly trends. A big spike on Sundays and Mondays, and payday towards the end of the month is always good; on the third week of a month there tends to be a lull. Spend time letting your Google Analytics data brew, understand your own trends and patterns, and you\u2019ll start to get a feel for when something isn\u2019t quite right.\n\t\n\t\tTraffic Sources \u2192 Sources \u2192 All Traffic\n\t\n\tLook at the conversion rate by landing page for any traffic source that feels significantly different to what\u2019s expected. Check bounce rates, drill down to likely landing pages and check search keyword or referral site to see if it\u2019s a particular subset of visitor. You can do this by clicking Secondary Dimension and choosing Keyword or Source. If it\u2019s direct, choose Visitor Type to break down by new or returning visitor.\n\t\n\t\tContent \u2192 Site Content \u2192 Landing Pages\n\t\n\tI then tend to flip into Content Drilldown to see what the next clicks were from those landing pages, and whether they changed significantly to the date I\u2019m comparing with. If they have, that\u2019s usually an indicator of changed content (or its relevancy). Remember, if a bunch of people have found their way to your page via a method you\u2019re not expecting (such as a mention on a Spanish radio station \u2013 this actually happened to me once), while the content hasn\u2019t changed, the relevancy of it to the audience may have.\n\t\n\t\tContent \u2192 Site Content \u2192 Content Drilldown\n\t\n\tOnce I have an idea of what content was consumed, and whether it was relevant to the user, I then look at the visitor specifics, such as browser or demographic data, to see again whether the change was limited to a specific subset. Site speed, for example, is normally a good factor towards bounce rate, so compare that with previous data as well.\n\n\nNow, to be investigating at this level you still need a serious amount of data, in order to tell what\u2019s a significant change or not. If you\u2019re struggling with a small number of visitors, you might find reporting on a weekly or fortnightly basis more appropriate. \n\nHowever, once you\u2019ve looked into the basics of why changes happen to the value of your site, you\u2019ll soon find yourself limited by the reports offered in Standard Reporting. So, it\u2019s time to build your own. Hooray!\n\nCustom reporting\n\nGoogle Analytics provides the tools to build reports specific to the types of investigations you frequently perform. \n\n\n\nWelcome to my world.\n\nCustom reports are quite simple to build: first, you determine the metric you want the report to cover (number of visitors, bounce rate, conversion rate, and so on), then choose a set of dimensions that you\u2019d like to segment the report by (say, the source of the traffic, and whether they were new or returning users). You can filter the report, including or excluding particular dimension values, and you can assign the report to any of the profiles you created earlier. \n\nIn the example below, I\u2019ve created a report that shows me visits and conversion rate for any Google traffic that landed directly only on a product page. I can then drill down on each product page to see the complete phrases use to search. I can use this information in two ways:\n\n\n\tI can see which products aren\u2019t converting, which shows me where I need to work harder on merchandising.\n\tI can give this information to my content team, showing them the actual phrases visitors used to reach our product content, helping them write better targeted product descriptions.\n\n\n\n\nThe possibilities here are nearly endless, but here are a few examples of reports I find useful:\n\n\n\tNon-brand inbound search\nBy creating a report that shows inbound search traffic which doesn\u2019t include your brand, you can see more clearly the behaviour of visitors most likely to be unfamiliar with your site and brand values, without having to rely on the clumsy new or returning demographic date.\n\tTraffic/conversion/sales by hour\nThis is pure stats porn, but actually more useful than real-time data. By seeing this data broken down at an hourly level, you can not only compare the current day to previous days, but also see the best performing times for email broadcasts and tweets.\n\tVisits, load time, conversion and sales by page and browser\nPage speed can often kill conversion rates, but it\u2019s difficult to prove the value of focusing on speed in monetary terms. Having this report to hand helps me drive Operation Greenbelt, our effort to get into the sub-1.5 second band in Google Webmaster Tools.\n\n\nUseful things you can\u2019t do in custom reporting\n\nIf you have a search function on your website, then Conversion Rate and Products Bought by Site Search Term is an incredibly useful report that allows you to measure the effectiveness of your site\u2019s search engine at returning products and content related to the search term used. By including the products actually bought by visitors who searched for each term, you can use this information to better searchandise these results, escalating high propensity and high value products to the top of the results.\n\nHowever, it\u2019s not possible to get this information out of new Google Analytics. \n\nTry it, select the following in the report builder:\n\n\n\tMetrics: total unique searches; e-commerce or goal conversion rate\n\tDimensions: search term; product\n\n\nYou\u2019ll see that the data returned is a little nonsensical, though a 2,000% conversion rate would be nice. However, you can get more accurate information using advanced segments. By creating individual segments to define users who have searched for a particular term, you can run the sales performance and product performance reports as normal. It\u2019s laborious, but it teaches a good lesson: data that seems inaccessible can normally be found another way!\n\nReporting infrastructure\n\nNow that you have a series of reports that you can refer to on a daily or weekly basis, it\u2019s time to put together a regular reporting infrastructure. \n\nEven if you\u2019re not reporting to someone, having a set of key performance indicators that you can use to see how your performance is improving over time allows you to set yourself business goals on a monthly and annual basis.\n\nFor my own reporting, I take some high-level metrics (such as visitors, conversion rate and average order value), and segment them by traffic source and, separately, landing page. These statistics I record weekly and report:\n\n\n\tcurrent week compared with previous week\n\tsame week previous year (if available)\n\t4 week average\n\t13 week average\n\t52 week average (if available)\n\n\nThis takes into account weekly, monthly, seasonal and annual trends, and gives you a much clearer view of your performance.\n\nGetting data in other ways\n\nIf you\u2019re using Google Analytics frequently, with any large site you\u2019ll come to a couple of conclusions:\n\n\n\tDoing any kind of practical comparative analysis is unwieldy.\n\tBoy, Google Analytics is slow!\n\n\nAs you work with bigger datasets and put together more complex queries, you\u2019ll see the loading graphic more than you\u2019ll see actual data. So when you reach that level, there are ways to completely bypass the Google Analytics interface altogether, and get data into your own spreadsheet application for manipulation.\n\nData Feed Query Explorer\n\nIf you just want to pull down some quick statistics but still use complex filters and exotic metric and dimension combinations, the Data Feed Query Explorer is the quickest way of doing so. Authenticate with your Google Analytics account, select a profile, and you can start selecting metrics and dimensions to be generated in a handy, selectable tabulated format.\n\nGoogle Analytics API\n\nIf you\u2019re feeling clever, you can bypass having to copy and paste data by pulling in directly into Excel, Google Docs or your own application using the Google Analytics API. There are several scripts and plugins available to do this. I use Automate Analytics Google Docs code (there\u2019s also a paid version that simplifies setup and creates some handy reports for you).\n\nNew shiny things\n\nWell, now that that\u2019s over, I can show you some cool stuff. Well, at least it\u2019s cool to me. Google Analytics is being constantly improved and new functionality is introduced nearly every month. Here are a couple of my favourites.\n\nMultichannel attribution\n\nNot every visitor converts on your site on the first visit. They may not even do so on the second visit, or third. If they convert on the fourth visit, but each time they visit they do so via a different channel (for example, Search PPC, Search Organic, Direct, Email), which channel do you attribute the conversion to? The last channel, or the first? Dilemma! \n\nGoogle now has a Multichannel Attribution report, available in the Conversion category, which shows how each channel assists in converting, the overlap between channels, and where in the process that channel was important. \n\n\n\nFor example, you may have analysed your blog traffic from Twitter and become disheartened that not many people were subscribing after visiting from Twitter links, but instead your high-value subscribers were coming from natural search. On the face of it, you\u2019d spend less time tweeting, but a multichannel report may tell you that visitors first arrived via a Twitter link and didn\u2019t subscribe, but then came back later after searching for your blog name on Google, after which they did. Don\u2019t pack Twitter in yet!\n\nVisitor and goal flow\n\nVisitor and goal flow are amazing reports that help you visualize the flow of traffic through your site and, ultimately, into your checkout funnel or similar goal path. Flow reports are perfect for understanding drop-off points in your process, as well as what the big draws are on each page. \n\n\n\nPreviously, if you wanted to visualize this data you had to set up several abstracted microgoals and chain them together in custom reports. Frankly, it was a pain in the arse and burned through your precious and limited goal allocation.\n\nVisitor flow bypasses all that and produces the report in an interactive flow diagram. While it doesn\u2019t show you the holy grail of conversion likelihood by each path, you can segment visitor flow so that you can see very specifically how different segments of your visitor base behave.\n\nGo play with it now!", "year": "2011", "author": "Matt Curry", "author_slug": "mattcurry", "published": "2011-12-18T00:00:00+00:00", "url": "https://24ways.org/2011/getting-the-most-out-of-google-analytics/", "topic": "business"} {"rowid": 270, "title": "From Side Project to Not So Side Project", "contents": "In the last article I wrote for 24 ways, back in 2009, I enthused about the benefits of having a pet project, suggesting that we should all have at least one so that we could collaborate with our friends, escape our day jobs, fulfil our own needs, help others out, raise our profiles, make money, and \u2014 most importantly \u2014 have fun. I don\u2019t think I need to offer any further persuasions: it seems that designers and developers are launching their own pet projects left, right and centre. This makes me very happy.\n\nHowever, there still seems to be something of a disconnect between having a side project and turning it into something that is moderately successful; in particular, the challenge of making enough money to sustain the project and perhaps even elevating it from the sidelines so that it becomes something not so on the side at all.\n\nBefore we even begin this, let\u2019s spend a moment talking about money, also known as\u2026\n\nEvil, nasty, filthy money\n\nOver the last couple of years, I\u2019ve started referring to myself as an accidental businessman. I say accidental because my view of the typical businessman is someone who is driven by money, and I usually can\u2019t stand such people. Those who are motivated by profit, obsessed with growth, and take an active interest in the world\u2019s financial systems don\u2019t tend to be folks with whom I share a beer, unless it\u2019s to pour it over them. Especially if they\u2019re wearing pinstriped suits.\n\nThat said, we all want to make money, don\u2019t we? And most of us want to make a relatively decent amount, too. I don\u2019t think there\u2019s any harm in admitting that, is there? Hello, I\u2019m Elliot and I\u2019m a capitalist.\n\nThe key is making money from doing what we love. For most people I know in our community, we\u2019ve already achieved that \u2014 I\u2019m hard-pressed to think of anyone who isn\u2019t extremely passionate about working in our industry and I think it\u2019s one of the most positive, unifying benefits we enjoy as a group of like-minded people \u2014 but side projects usually arise from another kind of passion: a passion for something other than what we do as our day jobs. Perhaps it\u2019s because your clients are driving you mental and you need a break; perhaps it\u2019s because you want to create something that is truly your own; perhaps it\u2019s because you\u2019re sick of seeing your online work disappear so fast and you want to try your hand at print in order to make a more permanent mark.\n\nThe three factors I listed there led me to create 8 Faces, a printed magazine about typography that started as a side project and is now a very significant part of my yearly output and income.\n\nLike many things that prove fruitful, 8 Faces\u2019 success was something of an accident, too. For a start, the magazine was never meant to be profitable; its only purpose at all was to scratch my own itch. Then, after the first issue took off and I realized how much time I needed to spend in order to make the next one decent, it became clear that I would have to cover more than just the production costs: I\u2019d have to take time out from client work as well. Doing this meant I\u2019d have to earn some money. Probably not enough to equate to the exact amount of time lost when I could be doing client work (not that you could ever describe time as being lost when you work on something you love), but enough to survive; for me to feel that I was getting paid while doing all of the work that 8 Faces entailed. The answer was to raise money through partnerships with some cool companies who were happy to be associated with my little project.\n\nA sustainable business model\n\nBusiness model! I can\u2019t believe I just wrote those words! But a business model is really just a loose plan for how not to screw up. And all that stuff I wrote in the paragraph above about partnering with companies so I could get some money in while I put the magazine together? Well, that\u2019s my business model. \n\nIf you\u2019re making any product that has some sort of production cost, whether that\u2019s physical print run expenses or up-front dev work to get an app built, covering those costs before you even release your product means that you\u2019ll be in profit from the first copy you sell. This is no small point: production expenses are pretty much the only cost you\u2019ll ever need to recoup, so having them covered before you launch anything is pretty much the best possible position in which you could place yourself. Happy days, as Jamie Oliver would say.\n\nObtaining these initial funds through partnerships has another benefit. Sure, it\u2019s a form of advertising but, done right, your partners can potentially provide you with great content, too. In the case of 8 Faces, the ads look as nice as the rest of the magazine, and a couple of our partners also provide proper articles: genuinely meaningful, relevant, reader-pleasing articles at that. You\u2019d be amazed at how many companies are willing to become partners and, as the old adage goes, if you don\u2019t ask, you don\u2019t get.\n\nWith profit comes responsibility\n\nDon\u2019t forget about the responsibility you have to your audience if you engage in a relationship with a partner or any type of advertiser: although I may have freely admitted my capitalist leanings, I\u2019m still essentially a hairy hippy, and I feel that any partnership should be good for me as a publisher, good for the partner and \u2014 most importantly \u2014 good for the reader. Really, the key word here is relevance, and that\u2019s where 99.9% of advertising fails abysmally. \n\n(99.9% is not a scientific figure, but you know what I\u2019m on about.)\n\nThe main grey area when a side project becomes profitable is how you share that profit, partly because \u2014 in my opinion, at least \u2014 the transition from non-profitable side project to relatively successful source of income can be a little blurred. Asking for help for nothing when there\u2019s no money to be had is pretty normal, but sometimes it\u2019s easy to get used to that free help even once you start making money. I believe the best approach is to ask for help with the promise that it will always be rewarded as soon as there\u2019s money available. (Oh, god: this sounds like one of those nightmarish client proposals. It\u2019s not, honest.) If you\u2019re making something cool, people won\u2019t mind helping out while you find your feet.\n\nEvents often think that they\u2019re exempt from sharing profit. Perhaps that\u2019s because many event organizers think they\u2019re doing the speakers a favour rather than the other way around (that\u2019s a whole separate article), but it\u2019s shocking to see how many people seem to think they can profit from content-makers \u2014 speakers, for example \u2014 and yet not pay for that content. It was for this reason that Keir and I paid all of our speakers for our Insites: The Tour side project, which we ran back in July. We probably could\u2019ve got away without paying them, especially as the gig was so informal, but it was the right thing to do.\n\nIn conclusion: money as a by-product\n\nLet\u2019s conclude by returning to the slightly problematic nature of money, because it\u2019s the pivot on which your side project\u2019s success can swing, regardless of whether you measure success by monetary gain. I would argue that success has nothing to do with profit \u2014 it\u2019s about you being able to spend the time you want on the project. Unfortunately, that is almost always linked to money: money to pay yourself while you work on your dream idea; money to pay for more servers when your web app hits the big time; money to pay for efforts to get the word out there. The key, then, is to judge success on your own terms, and seek to generate as much money as you see fit, whether it\u2019s purely to cover your running costs, or enough to buy a small country. There\u2019s nothing wrong with profit, as long as you\u2019re ethical about it. (Pro tip: if you\u2019ve earned enough to buy a small country, you\u2019ve probably been unethical along the way.)\n\nThe point at which individuals and companies fail \u2014 in the moral sense, for sure, but often in the competitive sense, too \u2014 is when money is the primary motivation. It should never be the primary motivation. If you\u2019re not passionate enough about something to do it as an unprofitable side project, you shouldn\u2019t be doing it all. \n\nEarning money should be a by-product of doing what you love. And who doesn\u2019t want to spend their life doing what they love?", "year": "2011", "author": "Elliot Jay Stocks", "author_slug": "elliotjaystocks", "published": "2011-12-22T00:00:00+00:00", "url": "https://24ways.org/2011/from-side-project-to-not-so-side-project/", "topic": "business"} {"rowid": 281, "title": "Nine Things I've Learned", "contents": "I\u2019ve been a professional graphic designer for fourteen years and for just under four of those a professional web designer. Like most designers I\u2019ve learned a lot in my time, both from a design point of view and in business as freelance designer. A few of the things I\u2019ve learned stick out in my mind, so I thought I\u2019d share them with you. They\u2019re pretty random and in no particular order.\n\n1. Becoming the designer you want to be\n\nWhen I started out as a young graphic designer, I wanted to design posters and record sleeves, pretty much like every other young graphic designer. The problem is that the reality of the world means that when you get your first job you\u2019re designing the back of a paracetamol packet or something equally weird. I recently saw a tweet that went something like this: \u201cYou\u2019ll never become the designer you always dreamt of being by doing the work you never wanted to do\u201d. This is so true; to become the designer you want to be, you need to be designing the things you\u2019re passionate about designing. This probably this means working in the evenings and weekends for little or no money, but it\u2019s time well spent. Doing this will build up your portfolio with the work that really shows what you can do! Soon, someone will ask you to design something based on having seen this work. From this point, you\u2019re carving your own path in the direction of becoming the designer you always wanted to be.\n\n2. Compete on your own terms\n\nAs well as all being friends, we are also competitors. In order to win new work we need a selling point, preferably a unique selling point. Web design is a combination of design disciplines \u2013 user experience design, user interface Design, visual design, development, and so on. Some companies will sell themselves as UX specialists, which is fine, but everyone who designs a website from scratch does some sort of UX, so it\u2019s not really a unique selling point. Of course, some people do it better than others.\n\nOne area of web design that clients have a strong opinion on, and will judge you by, is visual design. It\u2019s an area in which it\u2019s definitely possible to have a unique selling point. Designing the visual aesthetic for a website is a combination of logical decision making and a certain amount of personal style. If you can create a unique visual style to your work, it can become a selling point that\u2019s unique to you.\n\n3. How much to charge and staying motivated\n\nWhen you\u2019re a freelance designer one of the hardest things to do is put a price on your work and skills. Finding the right amount to charge is a fine balance between supplying value to your customer and also charging enough to stay motivated to do a great job. It\u2019s always tempting to offer a low price to win work, but it\u2019s often not the best approach: not just for yourself but for the client as well.\n\nA client once asked me if I could reduce my fee by \u00a31,000 and still be motivated enough to do a good job. In this case the answer was yes, but it was the question that resonated with me. I realized I could use this as a gauge to help me price projects. Before I send out a quote I now always ask myself the question \u201cIs the amount I\u2019ve quoted enough to make me feel motivated to do my best on this project?\u201d I never send out a quote unless the answer is yes. In my mind there\u2019s no point in doing any project half-heartedly, as every project is an opportunity to build your reputation and expand your portfolio to show potential clients what you can do. Offering a client a good price but not being prepared to put everything you have into it, isn\u2019t value for money. \n\n4. Supplying the right design\n\nWhen I started out as a graphic designer it seemed to be the done thing to supply clients with a ton of options for their logo or brochure designs. In a talk given by Dan Rubin, he mentioned that this was a legacy of agencies competing with each other in a bid to create the illusion of offering more value for money. Over the years, I\u2019ve realized that offering more than one solution makes no sense. The reason a client comes to you as a designer is because you\u2019re the person than can get it right. If I were to supply three options, I\u2019d be knowingly offering my client at least two options that I didn\u2019t think worked.\n\nTo this day I still get asked how many homepage design options I\u2019ll supply for the quoted amount. The answer is one. Of course, I\u2019m more than happy to iterate upon the design to fine-tune it and, on the odd occasion, I do revisit a design concept if I just didn\u2019t nail the design first time around. Your time is much better spent refining the right design option than rushing out three substandard designs in the same amount of time.\n\n5. Colour is key\n\nThere are many contributing factors that go into making a good visual design, but one of the simplest ways to do this is through the use of colour. The colour palette used in a design can have such a profound effect on a visual design that it almost feels like you\u2019re cheating. It\u2019s easy to add more and more subtle shades of colour to add a sense of sophistication and complexity to a design, but it dilutes the overall visual impact. When I design, I almost have a rule that only allows me to use a very limited colour palette. I don\u2019t always stick to it, but it\u2019s always in mind and something I\u2019m constantly reviewing through my design process.\n\n6. Creative thinking is central to good or boundary-pushing web design\n\nWhen we think of creativity in web design we often link this to the visual design, as there is an obvious opportunity to be creative in this area if the brief allows it. Something that I\u2019ve learnt in my time as a web designer is that there\u2019s a massive need for creative thinking in the more technical aspects of web design. The tools we use for building websites are there to be manipulated and used in creative ways to design exciting and engaging user experiences. Great developers are constantly using their creativity to push the boundaries of what can be done with CSS, jQuery and JavaScript. \n\nBeing creative and creative thinking are things we should embrace as an industry and they are qualities that can be found in anyone, whether they be a visual designer or Rails developer.\n\n7. Creative block: don\u2019t be afraid to get things wrong\n\nCreative block can be a killer when designing. It\u2019s often applied to visual design, which is more subjective. I suffer from creative block on a regular basis. It\u2019s hugely frustrating and can screw up your schedule. Having thought about what creative block actually is, I\u2019ve come to the conclusion that it\u2019s actually more of a lack of direction than a lack of ideas. You have ideas and solutions in mind but don\u2019t feel committed to any of them. You\u2019re scared that whatever direction you take, it\u2019ll turn out to be wrong. I\u2019ve found that the best remedy for this is to work through this barrier. It\u2019s a bit like designing with a blindfold on \u2013 you don\u2019t really know where you\u2019re going. If you stick to your guns and keep pressing forward I find that, nine times out of ten, this process leads to a solution. As the page begins to fill, the direction you\u2019re looking for slowly begins to take shape.\n\n8. You get better at designing by designing\n\nI often get emails asking me what books someone can read to help them become a better designer. There are a lot of good books on subjects like HTML5, CSS, responsive web design and the like, that will really help improve anyone\u2019s web design skills. But, when it comes to visual design, the best way to get better is to design as much as possible. You can\u2019t follow instructions for these things because design isn\u2019t following instructions. A large part of web design is definitely applying a set of widely held conventions, but there\u2019s another part to it that is invention and the only way to get better at this is to do it as much as possible.\n\n9. Self-belief is overrated\n\nThroughout our lives we\u2019re told to have self-belief. Self-belief and confidence in what we do, whatever that may be. The problem is that some people find it easier than others to believe in themselves. I\u2019ve spent years trying to convince myself to believe in what I do but have always found it difficult to have complete confidence in my design skills. Self-doubt always creeps in.\n\nI\u2019ve realized that it\u2019s ok to doubt myself and I think it might even be a good thing! I\u2019ve realized that it\u2019s my self-doubt that propels me forward and makes me work harder to achieve the best results. The reason I\u2019m sharing this is because I know I\u2019m not the only designer that feels this way. You can spend a lot of time fighting self-doubt only to discover that it\u2019s your body\u2019s natural mechanism to help you do the best job possible.", "year": "2011", "author": "Mike Kus", "author_slug": "mikekus", "published": "2011-12-11T00:00:00+00:00", "url": "https://24ways.org/2011/nine-things-ive-learned/", "topic": "business"} {"rowid": 312, "title": "Preparing to Be Badass Next Year", "contents": "Once we\u2019ve eaten our way through the holiday season, people will start to think about new year\u2019s resolutions. We tend to focus on things that we want to change\u2026 and often things that we don\u2019t like about ourselves to \u201cfix\u201d. We set rules for ourselves, or try to start new habits or stop bad ones. We focus in on things we will or won\u2019t do. \nFor many of us the list of things we \u201cought\u201d to be spending time on is just plain overwhelming \u2013 family, charity/community, career, money, health, relationships, personal development. \nIt\u2019s kinda scary even just listing it out, isn\u2019t it? I want to encourage you to think differently about next year.\nThe ever-brilliant Kathy Sierra articulates a better approach really well when talking about the attitude we should have to building great products. She tells us to think not about what the user will do with our product, but about what they are trying to achieve in the real world and how our product helps them to be badass1.\nWhen we help the user be badass, then we are really making a difference. \nI suppose this is one way of saying: focus not on what you will do, focus on what it will help you achieve. How will it help you be awesome?\nIn what ways do you want to be more badass next year?\nA professional lens\nThough of course you might want to focus in on health or family or charity or community or another area next year, many people will want to become more badass in their chosen career. \nSo let\u2019s talk about a scaffold to help you figure out your professional / career development next year. \nFirst up, an assumption: everyone wants to be awesome. Nobody gets up in the morning aiming to be crap at their job. Nobody thinks to themselves \u201cToday I am aiming for just south of mediocre, and if I can mess up everybody else\u2019s ability to do good work then that will be just perfect2\u201d. \nErgo, you want to be awesome. So what does awesome look like? \nDanger!\nThe big trap that people fall into when think about their professional development is to immediately focus on the things that they aren\u2019t good at. When you ask people \u201cwhat do you want to work on getting better at next year?\u201d they frequently gravitate to the things that they believe they are bad at. \nWhy is this a trap? Because if you focus all your time and energy on improving the areas that you suck at, you are going to end up middling at everything. Going from bad \u2192 mediocre at a given skill / behaviour takes a bunch of time and energy. So if you spend all your time going from bad \u2192 mediocre at things, what do you think you end up? That\u2019s right, mediocre. \nMediocrity is not a great career goal, kids. \nWhat do you already rock at?\nThe much better investment of time and energy is to go from good \u2192 awesome. It often takes the same amount of relative time and energy, but wow the end result is better! So first, ask yourself and those who know you well what you are already pretty damn good at. Combat imposter syndrome by asking others. \nThen figure out how to double down on those things. What does brilliant look like for a given skill? What\u2019s the knowledge or practice that you need to level yourself up even further in that thing?\nBut what if I really really suck?\nAdmittedly, sometimes something you suck at really is holding you back. But it\u2019s important to separate out weaknesses (just something you suck at) from controlling weaknesses (something you suck at that actually matters for your chosen career). \nIf skill x is just not an important thing for you to be good at, you may never need to care that you aren\u2019t good at it. If your current role or the one you aspire to next really really requires you to be great at x, then it\u2019s worth investing your time and energy (and possibly money too) getting better at it.\nSo when you look at the things that you aren\u2019t good at, which of those are actually essential for success?\nThe right ratio\nA good rule of thumb is to pick three things you are already good at to work on becoming awesome at and limit yourself to one weakness that you are trying to improve on. That way you are making sure that you get to awesome in areas where you already have an advantage, and limit the amount of time you are spending on going from bad \u2192 mediocre. \nLevelling up learning\nSo once you\u2019ve figured out your areas you want to focus on next year, what do you actually decide to do? \nMost of all, you should try to design your day-to-day work in a way that it is also an effective learning experience. This means making sure you have a good feedback loop \u2013 you get to try something, see if it works, learn from it, rinse and repeat. \nIt\u2019s also about balance: you want to be challenged enough for work to be interesting, without it being so hard it\u2019s frustrating. You want to do similar / the same things often enough that you get to learn and improve, without it being so repetitive that it\u2019s boring. \nContinuously getting better at things you are already good at is actually both easier and harder than it sounds. The advantage is that it\u2019s pretty easy to add the feedback loop to make sure that you are improving; the disadvantage is that you\u2019re already good at these skills so you could easily just \u201cdo\u201d without ever stopping to reflect and improve. Build in time for personal retrospectives (\u201cWhat went well? What didn\u2019t? What one thing will I choose to change next time?\u201d) and find a way of getting feedback from outside sources as well. \nAs for the new skills, it\u2019s worth knowing that skill development follows a particular pattern:\n\nWe all start out unconsciously incompetent (we don\u2019t know what to do and if we tried we\u2019d unwittingly get it wrong), progress on to conscious incompetence (we now know we\u2019re doing it wrong) then conscious competence (we\u2019re doing it right but wow it takes effort and attention) and eventually get to unconscious competence (automatically getting it right). \nYour past experiences and knowledge might let you move faster through these stages, but no one gets to skip them. Invest the time and remember you need the feedback loop to really improve. \nWhat about keeping up?\nEverything changes very fast in our industry. We need to invest in not falling behind, in keeping on top of what great looks like. There are a bunch of ways to do this, from reading blog posts, following links on Twitter, reading books to attending conferences or workshops, or just finding time to build things in new ways or with new technologies. \nWhich will work best for you depends on how you best learn. Do you prefer to swallow a book? Do you learn most by building or experimenting? \nWhatever your learning style though, remember that there are three real needs:\n\nScan the landscape (what\u2019s changing, does it matter)\nGain the knowledge or skills (get the detail)\nApply the knowledge or skills (use it in reality)\n\nWhen you remember that you need all three of these things it can help you get more of what you do. \nFor me personally, I use a combination of conferences and blogs / Twitter to scan the landscape. Half of what I want out of a conference is just a list of things to have on my radar that might become important. I then pick a couple of things to go read up on more (I personally learn most effectively by swallowing a book or spec or similar). And then I pick one thing at a time to actually apply in real life, to embed the skill / knowledge. \nIn summary\n\nAim to be awesome (mediocrity is not a career goal).\nFigure out what you already rock at.\nOnly care about stuff you suck at that matters for your career.\nPick three things to go from good \u2192 awesome and one thing to go from bad \u2192 mediocre (or mediocre \u2192 good) this year.\nDesign learning into your daily work.\nScan the landscape, learn new stuff, apply it for real. \nBe badass!\n\n\n\n\n\nShe wrote a whole book about it. You should read it: Badass: Making Users Awesome\u00a0\u21a9\n\n\nBefore you argue too vehemently: I suppose some antisocial sociopathic bastards do exist. Identify them, and then RUN AWAY FAST AS YOU CAN #realtalk\u00a0\u21a9", "year": "2016", "author": "Meri Williams", "author_slug": "meriwilliams", "published": "2016-12-22T00:00:00+00:00", "url": "https://24ways.org/2016/preparing-to-be-badass-next-year/", "topic": "business"} {"rowid": 328, "title": "Swooshy Curly Quotes Without Images", "contents": "The problem\n\nTake a quote and render it within blockquote tags, applying big, funky and stylish curly quotes both at the beginning and the end without using any images \u2013 at all.\n\nThe traditional way\n\nFeint background images under the text, or an image in the markup housed in a little float. Often designers only use the opening curly quote as it\u2019s just too difficult to float a closing one.\n\nWhy is the traditional way bad?\n\nWell, for a start there are no actual curly quotes in the text (unless you\u2019re doing some nifty image replacement). Thus with CSS disabled you\u2019ll only have default blockquote styling to fall back on. Secondly, images don\u2019t resize, so scaling text will have no affect on your graphic curlies.\n\nThe solution\n\nUse really big text. Then it can be resized by the browser, resized using CSS, and even be restyled with a new font style if you fancy it. It\u2019ll also make sense when CSS is unavailable.\n\nThe problem\n\nCreating \u201cDrop Caps\u201d with CSS has been around for a while (Big Dan Cederholm discusses a neat solution in that first book of his), but drop caps are normal characters \u2013 the A to Z or 1 to 10 \u2013 and these can all be pulled into a set space and do not serve up a ton of whitespace, unlike punctuation characters.\n\nCurly quotes aren\u2019t like traditional characters. Like full stops, commas and hashes they float within the character space and leave lots of dead white space, making it bloody difficult to manipulate them with CSS. Styles generally fit around text, so cutting into that character is tricky indeed. Also, all that extra white space is going to push into the quote text and make it look pretty uneven. This grab highlights the actual character space:\n\n\n\nSee how this is emphasized when we add a normal alphabetical character within the span. This is what we\u2019re dealing with here:\n\n\n\nThen, there\u2019s size. Call in a curly quote at less than 300% font-size and it ain\u2019t gonna look very big. The white space it creates will be big enough, but the curlies will be way too small. We need more like 700% (as in this example) to make an impression, but that sure makes for a big character space.\n\nPrepare the curlies\n\nFirstly, remove the opening \u201c from the quote. Replace it with the opening curly quote character entity \u201c. Then replace the closing \u201c with the entity reference for that, which is \u201d. Now at least the curlies will look nice and swooshy.\n\nAdd the hooks\n\nTwo reasons why we aren\u2019t using :first-letter pseudo class to manipulate the curlies. Firstly, only CSS2-friendly browsers would get what we\u2019re doing, and secondly we need to affect the last \u201cletter\u201d of our text also \u2013 the closing curly quote.\n\nSo, add a span around the opening curly, and a second span around the closing curly, giving complete control of the characters:\n\n
\u201cSpeech marks. Curly quotes. That annoying thing cool people do with their fingers to emphasize a buzzword, shortly before you hit them.\u201d
\n\nSo far nothing will look any different, aside form the curlies looking a bit nicer. I know we\u2019ve just added extra markup, but the benefits as far as accessibility are concerned are good enough for me, and of course there are no images to download.\n\nThe CSS\n\nOK, easy stuff first. Our first rule .bqstart floats the span left, changes the color, and whacks the font-size up to an exuberant 700%. Our second rule .bqend does the same tricks aside from floating the curly to the right.\n\n.bqstart {\n float: left;\n font-size: 700%;\n color: #FF0000;\n }\n\n .bqend {\n float: right;\n font-size: 700%;\n color: #FF0000;\n }\n\nThat gives us this, which is rubbish. I\u2019ve highlighted the actual span area with outlines:\n\n\n\nNote that the curlies don\u2019t even fit inside the span! At this stage on IE 6 PC you won\u2019t even see the quotes, as it only places focus on what it thinks is in the div. Also, the quote text is getting all spangled.\n\nFiddle with margin and padding\n\nThink of that span outline box as a window, and that you need to position the curlies within that window in order to see them. By adding some small adjustments to the margin and padding it\u2019s possible to position the curlies exactly where you want them, and remove the excess white space by defining a height:\n\n.bqstart {\n float: left;\n height: 45px;\n margin-top: -20px;\n padding-top: 45px;\n margin-bottom: -50px;\n font-size: 700%;\n color: #FF0000;\n }\n\n .bqend {\n float: right;\n height: 25px;\n margin-top: 0px;\n padding-top: 45px;\n font-size: 700%;\n color: #FF0000;\n }\n\nI wanted the blocks of my curlies to align with the quote text, whereas you may want them to dig in or stick out more. Be aware however that my positioning works for IE PC and Mac, Firefox and Safari. Too much tweaking seems to break the magic in various browsers at various times. Now things are fitting beautifully:\n\nI must admit that the heights, margins and spacing don\u2019t make a lot of sense if you analyze them. This was a real trial and error job. Get it working on Safari, and IE would fail. Sort IE, and Firefox would go weird.\n\nFinished\n\nThe final thing looks ace, can be resized, looks cool without styles, and can be edited with CSS at any time. Here\u2019s a real example (note that I\u2019m specifying Lucida Grande and then Verdana for my curlies):\n\n \u201cSpeech marks. Curly quotes. That annoying thing cool people do with their fingers to emphasize a buzzword, shortly before you hit them.\u201d\n\nBrowsers happy\n\nAs I said, too much tweaking of margins and padding can break the effect in some browsers. Even now, Firefox insists on dropping the closing curly by approximately 6 or 7 pixels, and if I adjust the padding for that, it\u2019ll crush it into the text on Safari or IE. Weird. Still, as I close now it seems solid through resizing tests on Safari, Firefox, Camino, Opera and IE PC and Mac. Lovely.\n\nIt\u2019s probably not perfect, but together we can beat the evil typographic limitations of the web and walk together towards a brighter, more aligned world. Merry Christmas.", "year": "2005", "author": "Simon Collison", "author_slug": "simoncollison", "published": "2005-12-21T00:00:00+00:00", "url": "https://24ways.org/2005/swooshy-curly-quotes-without-images/", "topic": "business"} {"rowid": 8, "title": "Coding Towards Accessibility", "contents": "\u201cCan we make it AAA-compliant?\u201d \u2013 does this question strike fear into your heart? Maybe for no other reason than because you will soon have to wade through the impenetrable WCAG documentation once again, to find out exactly what AAA-compliant means?\n\nI\u2019m not here to talk about that.\n\nThe Web Content Accessibility Guidelines are a comprehensive and peer-reviewed resource which we\u2019re lucky to have at our fingertips. But they are also a pig to read, and they may have contributed to the sense of mystery and dread with which some developers associate the word accessibility.\n\nThis Christmas, I want to share with you some thoughts and some practical tips for building accessible interfaces which you can start using today, without having to do a ton of reading or changing your tools and workflow.\n\nBut first, let\u2019s clear up a couple of misconceptions.\n\nDreary, flat experiences\n\nI recently built a front-end framework for the Post Office. This was a great gig for a developer, but when I found out about my client\u2019s stringent accessibility requirements I was concerned that I\u2019d have to scale back what was quite a complex set of visual designs.\n\nSites like Jakob Neilsen\u2019s old workhorse useit.com and even the pioneering GOV.UK may have to shoulder some of the blame for this. They put a premium on usability and accessibility over visual flourish. (Although, in fairness to Mr Neilsen, his new site nngroup.com is really quite a snazzy affair, comparatively.)\n\nOf course, there are other reasons for these sites\u2019 aesthetics \u2014 and it\u2019s not because of the limitations of the form. You can make an accessible site look as glossy or as plain as you want it to look. It\u2019s always our own ingenuity and attention to detail that are going to be the limiting factors.\n\nSynecdoche\n\nWe must always guard against the tendency to assume that catering to screen readers means we have the whole accessibility ballgame covered. \n\nThere\u2019s so much more to accessibility than assistive technology, as you know. And within the field of assistive technology there are plenty of other devices for us to consider.\n\nPlanning to accommodate all these users and devices can be daunting. When I first started working in this field I thought that the breadth of technology was prohibitive. I didn\u2019t even know what a screen reader looked like. (I assumed they were big and heavy, perhaps like an old typewriter, and certainly they would be expensive and difficult to fathom.) This is nonsense, of course. Screen reader emulators are readily available as browser extensions and can be activated in seconds. Chromevox and Fangs are both excellent and you should download one or the other right now.\n\nBut the really good news is that you can emulate many other types of assistive technology without downloading a byte. And this is where we move from misconceptions into some (hopefully) useful advice.\n\nThe mouse trap\n\nThe simplest and most effective way to improve your abilities as a developer of accessible interfaces is to unplug your mouse.\n\nKeyboard operation has its own WCAG chapter, because most users of assistive technology are navigating the web using only their keyboards. You can go some way towards putting yourself into their shoes so easily \u2014 just by ditching a peripheral.\n\nLearning this was a lightbulb moment for me. When I build interfaces I am constantly flicking between code and the browser, testing or viewing the changes I have made. Now, instead of checking a new element once, I check it twice: once with my mouse and then again without.\n\nDon\u2019t just :hover\n\nThe reality is that when you first start doing this you can find your site becomes unusable straightaway. It\u2019s easy to lose track of which element is in focus as you hit the tab key repeatedly.\n\nOne of the easiest changes you can make to your coding practice is to add :focus and :active pseudo-classes to every hover state that you write. I\u2019m still amazed at how many sites fail to provide a decent focus state for links (and despite previous 24 ways authors in 2007 and 2009 writing on this same issue!).\n\nYou may find that in some cases it makes sense to have something other than, or in addition to, the hover state on focus, but start with the hover state that your designer has taken the time to provide you with. It\u2019s a tiny change and there is no downside. So instead of this:\n\n.my-cool-link:hover {\n\tbackground-color: MistyRose ;\t\n}\n\n\u2026try writing this:\n\n.my-cool-link:hover,\n.my-cool-link:focus,\n.my-cool-link:active {\n\tbackground-color: MistyRose ;\t\n}\n\nI\u2019ve toyed with the idea of making a Sass mixin to take care of this for me, but I haven\u2019t yet. I worry that people reading my code won\u2019t see that I\u2019m explicitly defining my focus and active states so I take the hit and write my hover rules out longhand.\n\nJavaScript can play, too\n\nThis was another revelation for me. Keyboard-only navigation doesn\u2019t necessitate a JavaScript-free experience, and up-to-date screen readers can execute JavaScript. So we\u2019re able to create complex JavaScript-driven interfaces which all users can interact with.\n\nSome of the hard work has already been done for us. First, there are already conventions around keyboard-driven interfaces. Think about the last time you viewed a photo album on Facebook. You can use the arrow keys to switch between photos, and the escape key closes whichever lightbox-y UI thing Facebook is showing its photos in this week. Arrow keys (up/down as well as left/right) for progression through content; Escape to back out of something; Enter or space bar to indicate a positive intention \u2014 these are established keyboard conventions which we can apply to our interfaces to improve their accessiblity. \n\nOf course, by doing so we are improving our interfaces in general, giving all users the option to switch between keyboard and mouse actions as and when it suits them.\n\nSecond, this guy wants to help you out. Hans Hillen is a developer who has done a great deal of work around accessibility and JavaScript-powered interfaces. Along with The Paciello Group he has created a version of the jQuery UI library which has been fully optimised for keyboard navigation and screen reader use. It\u2019s a fantastic reference which I revisit all the time \n\nI\u2019m not a huge fan of the jQuery UI library. It\u2019s a pain to style and the code is a bit bloated. So I\u2019ve not used this demo as a code resource to copy wholesale. I use it by playing with the various components and seeing how they react to keyboard controls. Each component is also fully marked up with the relevant ARIA roles to improve screen reader announcement where possible (more on this below).\n\nCoding for accessibility promotes good habits\n\nThis is a another observation around accessibility and JavaScript. I noticed an improvement in the structure and abstraction of my code when I started adding keyboard controls to my interface elements. \n\nYour code has to become more modular and event-driven, because any number of events could trigger the same interaction. A mouse-click, the Enter key and the space bar could all conceivably trigger the same open function on a collapsed accordion element. (And you want to keep things DRY, don\u2019t you?) \n\nIf you aren\u2019t already in the habit of separating out your interface functionality into discrete functions, you will be soon.\n\nvar doSomethingCool = function(){\n\t// Do something cool here.\n}\n\n// Bind function to a button click - pretty vanilla\n$('.myCoolButton').on('click', function(){\n\tdoSomethingCool();\n\treturn false;\n});\n\n// Bind the same function to a range of keypresses\n$(document).keyup(function(e){\n\tswitch(e.keyCode) {\n\t\tcase 13: // enter\n\t\tcase 32: // spacebar\n\t\t\tdoSomethingCool();\n\t\t\tbreak;\n\t\tcase 27: // escape\n\t\t\tdoSomethingElse();\n\t\t\tbreak;\n\t}\n});\n\nTo be honest, if you\u2019re doing complex UI stuff with JavaScript these days, or if you\u2019ve been building any responsive interfaces which rely on JavaScript, then you are most likely working with an application framework such as Backbone, Angular or Ember, so an abstraced and event-driven application structure will be familar to you. It should be super easy for you to start helping out your keyboard-only users if you aren\u2019t already \u2014 just add a few more event bindings into your UI layer!\n\nManipulating the tab order\n\nSo, you\u2019ve adjusted your mindset and now you test every change to your codebase using a keyboard as well as a mouse. You\u2019ve applied all your hover states to :focus and :active so you can see where you\u2019re tabbing on the page, and your interactive components react seamlessly to a mixture of mouse and keyboard commands. Feels good, right?\n\nThere\u2019s another level of optimisation to consider: manipulating the tab order. Certain DOM elements are naturally part of the tab order, and others are excluded. Links and input elements are the main elements included in the tab order, and static elements like paragraphs and headings are excluded. What if you want to make a static element \u2018tabbable\u2019? \n\nA good example would be in an expandable accordion component. Each section of the accordion should be separated by a heading, and there\u2019s no reason to make that heading into a link simply because it\u2019s interactive.\n\n
\n\t

Tyrannosaurus

\n\t

Tyrannosaurus; meaning \"tyrant lizard\"...

\n\n\t

Utahraptor

\n\t

Utahraptor is a genus of theropod dinosaurs...

\n\n\t

Dromiceiomimus

\n\t

Ornithomimus is a genus of ornithomimid dinosaurs...

\n

\n\nAdding the heading elements to the tab order is trivial. We just set their tabindex attribute to zero. You could do this on the server or the client. I prefer to do it with JavaScript as part of the accordion setup and initialisation process.\n\n$('.accordion-widget h3').attr('tabindex', '0');\n\nYou can apply this trick in reverse and take elements out of the tab order by setting their tabindex attribute to \u22121, or change the tab order completely by using other integers. This should be done with great care, if at all. You have to be sure that the markup you remove from the tab order comes out because it genuinely improves the keyboard interaction experience. This is hard to validate without user testing. The danger is that developers will try to sweep complicated parts of the UI under the carpet by taking them out of the tab order. This would be considered a dark pattern \u2014 at least on my team!\n\nA farewell ARIA\n\nThis is where things can get complex, and I\u2019m no expert on the ARIA specification: I feel like I\u2019ve only dipped my toe into this aspect of coding for accessibility. But, as with WCAG, I\u2019d like to demystify things a little bit to encourage you to look into this area further yourself.\n\nARIA roles are of most benefit to screen reader users, because they modify and augment screen reader announcements. \n\nLet\u2019s take our dinosaur accordion from the previous section. The markup is semantic, so a screen reader that can\u2019t handle JavaScript will announce all the content within the accordion, no problem.\n\nBut modern screen readers can deal with JavaScript, and this means that all the lovely dino information beneath each heading has probably been hidden on document.ready, when the accordion initialised. It might have been hidden using display:none, which prevents a screen reader from announcing content. If that\u2019s as far as you have gone, then you\u2019ve committed an accessibility sin by hiding content from screen readers. Your user will hear a set of headings being announced, with no content in between. It would sound something like this if you were using Chromevox:\n\n> Tyrannosaurus. Heading Three.\n> Utahraptor. Heading Three.\n> Dromiceiomimus. Heading Three.\n\nWe can add some ARIA magic to the markup to improve this, using the tablist role. Start by adding a role of tablist to the widget, and roles of tab and tabpanel to the headings and paragraphs respectively. Set boolean values for aria-selected, aria-hidden and aria-expanded. The markup could end up looking something like this.\n\n
\n\t\t\n\t

Utahraptor

\n\tUtahraptor is a genus of theropod dinosaurs...

\n\t\t\n
\n\nNow, if a screen reader user encounters this markup they will hear the following:\n\n> Tyrannosaurus. Tab not selected; one of three.\n> Utahraptor. Tab not selected; two of three.\n> Dromiceiomimus. Tab not selected; three of three.\n\nYou could add arrow key events to help the user browse up and down the tab list items until they find one they like. \n\nYour accordion open() function should update the ARIA boolean values as well as adding whatever classes and animations you have built in as standard. Your users know that unselected tabs are meant to be interacted with, so if a user triggers the open function (say, by hitting Enter or the space bar on the second item) they will hear this:\n\n> Utahraptor. Selected; two of three.\n\nThe paragraph element for the expanded item will not be hidden by your CSS, which means it will be announced as normal by the screen reader.\n\nThis kind of thing makes so much more sense when you have a working example to play with. Again, I refer you to the fantastic resource that Hans Hillen has put together: this is his take on an accessible accordion, on which much of my example is based.\n\nConclusion\n\nGetting complex interfaces right for all of your users can be difficult \u2014 there\u2019s no point pretending otherwise. And there\u2019s no substitute for user testing with real users who navigate the web using assistive technology every day. This kind of testing can be time-consuming to recruit for and to conduct. On top of this, we now have accessibility on mobile devices to contend with. That\u2019s a huge area in itself, and it\u2019s one which I have not yet had a chance to research properly.\n\nSo, there\u2019s lots to learn, and there\u2019s lots to do to get it right. But don\u2019t be disheartened. If you have read this far then I\u2019ll leave you with one final piece of advice: don\u2019t wait.\n\nDon\u2019t wait until you\u2019re building a site which mandates AAA-compliance to try this stuff out. Don\u2019t wait for a client with the will or the budget to conduct the full spectrum of user testing to come along. Unplug your mouse, and start playing with your interfaces in a new way. You\u2019ll be surprised at the things that you learn and the issues you uncover. \n\nAnd the next time an true accessibility project comes along, you will be way ahead of the game.", "year": "2013", "author": "Charlie Perrins", "author_slug": "charlieperrins", "published": "2013-12-03T00:00:00+00:00", "url": "https://24ways.org/2013/coding-towards-accessibility/", "topic": "code"} {"rowid": 11, "title": "JavaScript: Taking Off the Training Wheels", "contents": "JavaScript is the third pillar of front-end web development. Of those pillars, it is both the most powerful and the most complex, so it\u2019s understandable that when 24 ways asked, \u201cWhat one thing do you wish you had more time to learn about?\u201d, a number of you answered \u201cJavaScript!\u201d\n\nThis article aims to help you feel happy writing JavaScript, and maybe even without libraries like jQuery. I can\u2019t comprehensively explain JavaScript itself without writing a book, but I hope this serves as a springboard from which you can jump to other great resources.\n\nWhy learn JavaScript?\n\nSo what\u2019s in it for you? Why take the next step and learn the fundamentals?\n\nConfidence with jQuery\n\nIf nothing else, learning JavaScript will improve your jQuery code; you\u2019ll be comfortable writing jQuery from scratch and feel happy bending others\u2019 code to your own purposes. Writing efficient, fast and bug-free jQuery is also made much easier when you have a good appreciation of JavaScript, because you can look at what jQuery is really doing. Understanding how JavaScript works lets you write better jQuery because you know what it\u2019s doing behind the scenes. When you need to leave the beaten track, you can do so with confidence.\n\nIn fact, you could say that jQuery\u2019s ultimate goal is not to exist: it was invented at a time when web APIs were very inconsistent and hard to work with. That\u2019s slowly changing as new APIs are introduced, and hopefully there will come a time when jQuery isn\u2019t needed.\n\nAn example of one such change is the introduction of the very useful document.querySelectorAll. Like jQuery, it converts a CSS selector into a list of matching elements. Here\u2019s a comparison of some jQuery code and the equivalent without.\n\n$('.counter').each(function (index) {\n $(this).text(index + 1);\n});\n\nvar counters = document.querySelectorAll('.counter');\n[].slice.call(counters).forEach(function (elem, index) {\n elem.textContent = index + 1;\n});\n\nSolving problems no one else has!\n\nWhen you have to go to the internet to solve a problem, you\u2019re forever stuck reusing code other people wrote to solve a slightly different problem to your own. Learning JavaScript will allow you to solve problems in your own way, and begin to do things nobody else ever has.\n\nNode.js\n\nNode.js is a non-browser environment for running JavaScript, and it can do just about anything! But if that sounds daunting, don\u2019t worry: the Node community is thriving, very friendly and willing to help.\n\nI think Node is incredibly exciting. It enables you, with one language, to build complete websites with complex and feature-filled front- and back-ends. Projects that let users log in or need a database are within your grasp, and Node has a great ecosystem of library authors to help you build incredible things. Exciting!\n\nHere\u2019s an example web server written with Node. http is a module that allows you to create servers and, like jQuery\u2019s $.ajax, make requests. It\u2019s a small amount of code to do something complex and, while working with Node is different from writing front-end code, it\u2019s certainly not out of your reach.\n\nvar http = require('http');\nhttp.createServer(function (req, res) {\n res.writeHead(200, {'Content-Type': 'text/plain'});\n res.end('Hello World');\n}).listen(1337);\nconsole.log('Server running at http://localhost:1337/');\n\nGrunt and other website tools\n\nNode has brought in something of a renaissance in tools that run in the command line, like Yeoman and Grunt. Both of these rely heavily on Node, and I\u2019ll talk a little bit about Grunt here.\n\nGrunt is a task runner, and many people use it for compiling Sass or compressing their site\u2019s JavaScript and images. It\u2019s pretty cool. You configure Grunt via the gruntfile.js, so JavaScript skills will come in handy, and since Grunt supports plug-ins built with JavaScript, knowing it unlocks the bucketloads of power Grunt has to offer.\n\nWays to improve your skills\n\nSo you know you want to learn JavaScript, but what are some good ways to learn and improve? I think the answer to that is different for different people, but here are some ideas.\n\nRebuild a jQuery app\n\nConverting a jQuery project to non-jQuery code is a great way to explore how you modify elements on the page and make requests to the server for data. My advice is to focus on making it work in one modern browser initially, and then go cross-browser if you\u2019re feeling adventurous. There are many resources for directly comparing jQuery and non-jQuery code, like Jeffrey Way\u2019s jQuery to JavaScript article.\n\nFind a mentor\n\nIf you think you\u2019d work better on a one-to-one basis then finding yourself a mentor could be a brilliant way to learn. The JavaScript community is very friendly and many people will be more than happy to give you their time. I\u2019d look out for someone who\u2019s active and friendly on Twitter, and does the kind of work you\u2019d like to do. Introduce yourself over Twitter or send them an email. I wouldn\u2019t expect a full tutoring course (although that is another option!) but they\u2019ll be very glad to answer a question and any follow-ups every now and then.\n\nGo to a workshop\n\nMany conferences and local meet-ups run workshops, hosted by experts in a particular field. See if there\u2019s one in your area. Workshops are great because you can ask direct questions, and you\u2019re in an environment where others are learning just like you are \u2014 no need to learn alone!\n\nSet yourself challenges\n\nThis is one way I like to learn new things. I have a new thing that I\u2019m not very good at, so I pick something that I think is just out of my reach and I try to build it. It\u2019s learning by doing and, even if you fail, it can be enormously valuable.\n\nWhere to start?\n\nIf you\u2019ve decided learning JavaScript is an important step for you, your next question may well be where to go from here.\n\nI\u2019ve collected some links to resources I know of or use, with some discussion about why you might want to check a particular site out. I hope this serves as a springboard for you to go out and learn as much as you want.\n\nBeginner\n\nIf you\u2019re just getting started with JavaScript, I\u2019d recommend heading to one of these places. They cover the basics and, in some cases, a little more advanced stuff. They\u2019re all reputable sources (although, I\u2019ve included something I wrote \u2014 you can decide about that one!) and will not lead you astray.\n\n\n\tjQuery\u2019s JavaScript 101 is a great first resource for JavaScript that will give you everything you need to work with jQuery like a pro.\n\tCodecademy\u2019s JavaScript Track is a small but useful JavaScript course. If you like learning interactively, this could be one for you.\n\tHTMLDog\u2019s JavaScript Tutorials take you right through from the basics of code to a brief introduction to newer technology like Node and Angular. [Disclaimer: I wrote this stuff, so it comes with a hazard warning!]\n\tThe tuts+ jQuery to JavaScript mentioned earlier is great for seeing how jQuery code looks when converted to pure JavaScript.\n\n\nGetting in-depth\n\nFor more comprehensive documentation and help I\u2019d recommend adding these places to your list of go-tos.\n\n\n\tMDN: the Mozilla Developer Network is the first place I go for many JavaScript questions. I mostly find myself there via a search, but it\u2019s a great place to just go and browse.\n\tAxel Rauschmayer\u2019s 2ality is a stunning collection of articles that will take you deep into JavaScript. It\u2019s certainly worth looking at.\n\tAddy Osmani\u2019s JavaScript Design Patterns is a comprehensive collection of patterns for writing high quality JavaScript, particularly as you (I hope) start to write bigger and more complex applications.\n\n\nAnd finally\u2026\n\nI think the key to learning anything is curiosity and perseverance. If you have a question, go out and search for the answer, even if you have no idea where to start. Keep going and going and eventually you\u2019ll get there. I bet you\u2019ll learn a whole lot along the way. Good luck!\n\nMany thanks to the people who gave me their time when I was working on this article: Tom Oakley, Jack Franklin, Ben Howdle and Laura Kalbag.", "year": "2013", "author": "Tom Ashworth", "author_slug": "tomashworth", "published": "2013-12-05T00:00:00+00:00", "url": "https://24ways.org/2013/javascript-taking-off-the-training-wheels/", "topic": "code"} {"rowid": 15, "title": "Git for Grown-ups", "contents": "You are a clever and talented person. You create beautiful designs, or perhaps you have architected a system that even my cat could use. Your peers adore you. Your clients love you. But, until now, you haven\u2019t *&^#^! been able to make Git work. It makes you angry inside that you have to ask your co-worker, again, for that *&^#^! command to upload your work.\n\nIt\u2019s not you. It\u2019s Git. Promise.\n\nYes, this is an article about the popular version control system, Git. But unlike just about every other article written about Git, I\u2019m not going to give you the top five commands that you need to memorize; and I\u2019m not going to tell you all your problems would be solved if only you were using this GUI wrapper or that particular workflow. You see, I\u2019ve come to a grand realization: when we teach Git, we\u2019re doing it wrong.\n\nLet me back up for a second and tell you a little bit about the field of adult education. (Bear with me, it gets good and will leave you feeling both empowered and righteous.) Andragogy, unlike pedagogy, is a learner-driven educational experience. There are six main tenets to adult education: \n\n\n\tAdults prefer to know why they are learning something.\n\tThe foundation of the learning activities should include experience.\n\tAdults prefer to be able to plan and evaluate their own instruction.\n\tAdults are more interested in learning things which directly impact their daily activities.\n\tAdults prefer learning to be oriented not towards content, but towards problems.\n\tAdults relate more to their own motivators than to external ones.\n\n\nNowhere in this list does it include \u201cmemorize the five most popular Git commands\u201d. And yet this is how we teach version control: init, add, commit, branch, push. You\u2019re an expert! Sound familiar? In the hierarchy of learning, memorizing commands is the lowest, or most basic, form of learning. At the peak of learning you are able to not just analyze and evaluate a problem space, but create your own understanding in relation to your existing body of knowledge.\n\n\u201cFine,\u201d I can hear you saying to yourself. \u201cBut I\u2019m here to learn about version control.\u201d Right you are! So how can we use this knowledge to master Git? First of all: I give you permission to use Git as a tool. A tool which you control and which you assign tasks to. A tool like a hammer, or a saw. Yes, your mastery of your tools will shape the kinds of interactions you have with your work, and your peers. But it\u2019s yours to control. Git was written by kernel developers for kernel development. The web world has adopted Git, but it is not a tool designed for us and by us. It\u2019s no Sass, y\u2019know? Git wasn\u2019t developed out of our frustration with managing CSS files in an increasingly complex ecosystem of components and atomic design. So, as you work through the next part of this article, give yourself a bit of a break. We\u2019re in this together, and it\u2019s going to be OK.\n\nWe\u2019re going to do a little activity. We\u2019re going to create your perfect Git cheatsheet.\n\nI want you to start by writing down a list of all the people on your code team. This list may include:\n\n\n\tdevelopers\n\tdesigners\n\tproject managers\n\tclients\n\n\nNext, I want you to write down a list of all the ways you interact with your team. Maybe you\u2019re a solo developer and you do all the tasks. Maybe you only do a few things. But I want you to write down a list of all the tasks you\u2019re actually responsible for. For example, my list looks like this:\n\n\n\twriting code\n\treviewing code\n\tpublishing tested code to your server(s)\n\ttroubleshooting broken code\n\n\nThe next list will end up being a series of boxes in a diagram. But to start, I want you to write down a list of your tools and constraints. This list potentially has a lot of noun-like items and verb-like items:\n\n\n\tcode hosting system (Bitbucket? GitHub? Unfuddle? self-hosted?)\n\tserver ecosystem (dev/staging/live)\n\tautomated testing systems or review gates\n\tautomated build systems (that Jenkins dude people keep referring to)\n\n\nBrilliant! Now you\u2019ve got your actors and your actions, it\u2019s time to shuffle them into a diagram. There are many popular workflow patterns. None are inherently right or wrong; rather, some are more or less appropriate for what you are trying to accomplish.\n\nCentralized workflow\n\nEveryone saves to a single place. This workflow may mean no version control, or a very rudimentary version control system which only ever has a single copy of the work available to the team at any point in time.\n\n \n\nBranching workflow\n\nEveryone works from a copy of the same place, merging their changes into the main copy as their work is completed. Think of the branches as a motorcycle sidecar: they\u2019re along for the ride and probably cannot exist in isolation of the main project for long without serious danger coming to the either the driver or sidecar passenger. Branches are a fundamental concept in version control \u2014 they allow you to work on new features, bug fixes, and experimental changes within a single repository, but without forcing the changes onto others working from the same branch.\n\n \n\nForking workflow\n\nEveryone works from their own, independent repository. A fork is an exact duplicate of a repository that a developer can make their own changes to. It can be kept up to date with additional changes made in other repositories, but it cannot force its changes onto another\u2019s repository. A fork is a complete repository which can use its own workflow strategies. If developers wish to merge their work with the main project, they must make a request of some kind (submit a patch, or a pull request) which the project collaborators may choose to adopt or reject. This workflow is popular for open source projects as it enforces a review process.\n\n \n\nGitflow workflow\n\nA specific workflow convention which includes five streams of parallel coding efforts: master, development, feature branches, release branches, and hot fixes. This workflow is often simplified down to a few elements by web teams, but may be used wholesale by software product teams. The original article describing this workflow was written by Vincent Driessen back in January 2010.\n\n \n\nBut these workflows aren\u2019t about you yet, are they? So let\u2019s make the connections.\n\nFrom the list of people on your team you identified earlier, draw a little circle. Give each of these circles some eyes and a smile. Now I want you to draw arrows between each of these people in the direction that code (ideally) flows. Does your designer create responsive prototypes which are pushed to the developer? Draw an arrow to represent this.\n\nChances are high that you don\u2019t just have people on your team, but you also have some kind of infrastructure. Hopefully you wrote about it earlier. For each of the servers and code repositories in your infrastructure, draw a square. Now, add to your diagram the relationships between the people and each of the machines in the infrastructure. Who can deploy code to the live server? How does it really get there? I bet it goes through some kind of code hosting system, such as GitHub. Draw in those arrows.\n\nBut wait!\n\nThe code that\u2019s on your development machine isn\u2019t the same as the live code. This is where we introduce the concept of a branch in version control. In Git, a repository contains all of the code (sort of). A branch is a fragment of the code that has been worked on in isolation to the other branches within a repository. Often branches will have elements in common. When we compare two (or more) branches, we are asking about the difference (or diff) between these two slivers. Often the master branch is used on production, and the development branch is used on our dev server. The difference between these two branches is the untested code that is not yet deployed.\n\nOn your diagram, see if you can colour-code according to the branch names at each of the locations within your infrastructure. You might find it useful to make a few different copies of the diagram to isolate each of the tasks you need to perform. For example: our team has a peer review process that each branch must go through before it is merged into the shared development branch.\n\nFinally, we are ready to add the Git commands necessary to make sense of the arrows in our diagram. If we are bringing code to our own workstation we will issue one of the following commands: clone (the first time we bring code to our workstation) or pull. Remembering that a repository contains all branches, we will issue the command checkout to switch from one branch to another within our own workstation. If we want to share a particular branch with one of our team mates, we will push this branch back to the place we retrieved it from (the origin). Along each of the arrows in your diagram, write the name of the command you are are going to use when you perform that particular task.\n\n \n\nFrom here, it\u2019s up to you to be selfish. Before asking Git what command it would like you to use, sketch the diagram of what you want. Git is your tool, you are not Git\u2019s tool. Draw the diagram. Communicate your tasks with your team as explicitly as you can. Insist on being a selfish adult learner \u2014 demand that others explain to you, in ways that are relevant to you, how to do the things you need to do today.", "year": "2013", "author": "Emma Jane Westby", "author_slug": "emmajanewestby", "published": "2013-12-04T00:00:00+00:00", "url": "https://24ways.org/2013/git-for-grownups/", "topic": "code"} {"rowid": 16, "title": "URL Rewriting for the Fearful", "contents": "I think it was Marilyn Monroe who said, \u201cIf you can\u2019t handle me at my worst, please just fix these rewrite rules, I\u2019m getting an internal server error.\u201d Even the blonde bombshell hated configuring URL rewrites on her website, and I think most of us know where she was coming from.\n\nThe majority of website projects I work on require some amount of URL rewriting, and I find it mildly enjoyable \u2014 I quite like a good rewrite rule. I suspect you may not share my glee, so in this article we\u2019re going to go back to basics to try to make the whole rigmarole more understandable.\n\nWhen we think about URL rewriting, usually that means adding some rules to an .htaccess file for an Apache web server. As that\u2019s the most common case, that\u2019s what I\u2019ll be sticking to here. If you work with a different server, there\u2019s often documentation specifically for translating from Apache\u2019s mod_rewrite rules. I even found an automatic converter for nginx.\n\nThis isn\u2019t going to be a comprehensive guide to every URL rewriting problem you might ever have. That would take us until Christmas. If you consider yourself a trial-and-error dabbler in the HTTP 500-infested waters of URL rewriting, then hopefully this will provide a little bit more of a basis to help you figure out what you\u2019re doing. If you\u2019ve ever found yourself staring at the white screen of death after screwing up your .htaccess file, don\u2019t worry. As Michael Jackson once insipidly whined, you are not alone.\n\nThe basics\n\nRewrite rules form part of the Apache web server\u2019s configuration for a website, and can be placed in a number of different locations as part of your virtual host configuration. By far the simplest and most portable option is to use an .htaccess file in your website root. Provided your server has mod_rewrite available, all you need to do to kick things off in your .htaccess file is:\n\nRewriteEngine on\n\nThe general formula for a rewrite rule is:\n\nRewriteRule URL/to/match URL/to/use/if/it/matches [options]\n\nWhen we talk about URL rewriting, we\u2019re normally talking about one of two things: redirecting the browser to a different URL; or rewriting the URL internally to use a particular file. We\u2019ll look at those in turn.\n\nRedirects\n\nRedirects match an incoming URL, and then redirect the user\u2019s browser to a different address. These can be useful for maintaining legacy URLs if content changes location as part of a site redesign. Redirecting the old URL to the new location makes sure that any incoming links, such as those from search engines, continue to work. \n\nIn 1998, Sir Tim Berners-Lee wrote that Cool URIs don\u2019t change, encouraging us all to go the extra mile to make sure links keep working forever. I think that sometimes it\u2019s fine to move things around \u2014 especially to correct bad URL design choices of the past \u2014 provided that you can do so while keeping those old URLs working. That\u2019s where redirects can help.\n\nA redirect might look like this\n\nRewriteRule ^article/used/to/be/here.php$ /article/now/lives/here/ [R=301,L]\n\nRewriting\n\nBy default, web servers closely map page URLs to the files in your site. On receiving a request for http://example.com/about/history.html the server goes to the configured folder for the example.com website, and then goes into the about folder and returns the history.html file.\n\nA rewrite rule changes that process by breaking the direct relationship between the URL and the file system. \u201cWhen there\u2019s a request for /about/history.html\u201d a rewrite rule might say, \u201cuse the file /about_section.php instead.\u201d\n\nThis opens up lots of possibilities for creative ways to map URLs to the files that know how to serve up the page. Most MVC frameworks will have a single rule to rewrite all page URLs to one single file. That file will be a script which kicks off the framework to figure out what to do to serve the page.\n\nRewriteRule ^for/this/url/$ /use/this/file.php [L] \n\nMatching patterns\n\nBy now you\u2019ll have noted the weird ^ and $ characters wrapped around the URL we\u2019re trying to match. That\u2019s because what we\u2019re actually using here is a pattern. Technically, it is what\u2019s called a Perl Compatible Regular Expression (PCRE) or simply a regex or regexp. We\u2019ll call it a pattern because we\u2019re not animals.\n\nWhat are these patterns? If I asked you to enter your credit card expiry date as MM/YY then chances are you\u2019d wonder what I wanted your credit card details for, but you\u2019d know that I wanted a two-digit month, a slash, and a two-digit year. That\u2019s not a regular expression, but it\u2019s the same idea: using some placeholder characters to define the pattern of the input you\u2019re trying to match.\n\nWe\u2019ve already met two regexp characters.\n\n\n\t^\n\tMatches the beginning of a string\n\t$\n\tMatches the end of a string\n\n\nWhen a pattern starts with ^ and ends with $ it\u2019s to make sure we match the complete URL start to finish, not just part of it. There are lots of other ways to match, too:\n\n\n\t[0-9]\n\tMatches a number, 0\u20139. [2-4] would match numbers 2 to 4 inclusive.\n\t[a-z]\n\tMatches lowercase letters a\u2013z\n\t[A-Z]\n\tMatches uppercase letters A\u2013Z\n\t[a-z0-9]\n\tCombining some of these, this matches letters a\u2013z and numbers 0\u20139\n\n\nThese are what we call character groups. The square brackets basically tell the server to match from the selection of characters within them. You can put any specific characters you\u2019re looking for within the brackets, as well as the ranges shown above. \n\nHowever, all these just match one single character. [0-9] would match 8 but not 84 \u2014 to match 84 we\u2019d need to use [0-9] twice.\n\n[0-9][0-9]\n\nSo, if we wanted to match 1984 we could to do this:\n\n[0-9][0-9][0-9][0-9] \n\n\u2026but that\u2019s getting silly. Instead, we can do this:\n\n[0-9]{4}\n\nThat means any character between 0 and 9, four times. If we wanted to match a number, but didn\u2019t know how long it might be (for example, a database ID in the URL) we could use the + symbol, which means one or more.\n\n[0-9]+\n\nThis now matches 1, 123 and 1234567.\n\nPutting it into practice\n\nLet\u2019s say we need to write a rule to match article URLs for this website, and to rewrite them to use /article.php under the hood. The articles all have URLs like this:\n\n2013/article-title/\n\nThey start with a year (from 2005 up to 2013, currently), a slash, and then have a URL-safe version of the article title (a slug), ending in a slash. We\u2019d match it like this:\n\n^[0-9]{4}/[a-z0-9-]+/$\n\nIf that looks frightening, don\u2019t worry. Breaking it down, from the start of the URL (^) we\u2019re looking for four numbers ([0-9]{4}). Then a slash \u2014 that\u2019s just literal \u2014 and then anything lowercase a\u2013z or 0\u20139 or a dash ([a-z0-9-]) one or more times (+), ending in a slash (/$).\n\nPutting that into a rewrite rule, we end up with this:\n\nRewriteRule ^[0-9]{4}/[a-z0-9-]+/$ /article.php\n\nWe\u2019re getting close now. We can match the article URLs and rewrite them to use article.php. Now we just need to make sure that article.php knows which article it\u2019s supposed to display.\n\nCapturing groups, and replacements\n\nWhen rewriting URLs you\u2019ll often want to take important parts of the URL you\u2019re matching and pass them along to the script that handles the request. That\u2019s usually done by adding those parts of the URL on as query string arguments. For our example, we want to make sure that article.php knows the year and the article title we\u2019re looking for. That means we need to call it like this:\n\n/article.php?year=2013&slug=article-title\n\nTo do this, we need to mark which parts of the pattern we want to reuse in the destination. We do this with round brackets or parentheses. By placing parentheses around parts of the pattern we want to reuse, we create what\u2019s called a capturing group. To capture an important part of the source URL to use in the destination, surround it in parentheses.\n\nOur pattern now looks like this, with parentheses around the parts that match the year and slug, but ignoring the slashes:\n\n^([0-9]{4})/([a-z0-9-]+)/$ \n\nTo use the capturing groups in the destination URL, we use the dollar sign and the number of the group we want to use. So, the first capturing group is $1, the second is $2 and so on. (The $ is unrelated to the end-of-pattern $ we used before.)\n\nRewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 \n\nThe value of the year capturing group gets used as $1 and the article title slug is $2. Had there been a third group, that would be $3 and so on. In regexp parlance, these are called back-references as they refer back to the pattern.\n\nOptions\n\nSeveral brain-taxing minutes ago, I mentioned some options as the final part of a rewrite rule. There are lots of options (or flags) you can set to change how the rule is processed. The most useful (to my mind) are:\n\n\n\tR=301\n\tPerform an HTTP 301 redirect to send the user\u2019s browser to the new URL. A status of 301 means a resource has moved permanently and so it\u2019s a good way of both redirecting the user to the new URL, and letting search engines know to update their indexes.\n\tL\n\tLast. If this rule matches, don\u2019t bother processing the following rules.\n\n\nOptions are set in square brackets at the end of the rule. You can set multiple options by separating them with commas:\n\nRewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 [L]\n\nor\n\nRewriteRule ^about/([a-z0-9-]+).jsp/$ /about/$1/ [R=301,L] \n\nCommon pitfalls\n\nOnce you\u2019ve built up a few rewrite rules, things can start to go wrong. You may have been there: a rule which looks perfectly good is somehow not matching. One common reason for this is hidden behind that [L] flag. \n\nL for Last is a useful option to tell the rewrite engine to stop once the rule has been matched. This is what it does \u2014 the remaining rules in the .htaccess file are then ignored. However, once a URL has been rewritten, the entire set of rules are then run again on the new URL. If the new URL matches any of the rules, that too will be rewritten and on it goes. \n\nOne way to avoid this problem is to keep your \u2018real\u2019 pages under a folder path that will never match one of your rules, or that you can exclude from the rewrite rules.\n\nUseful snippets\n\nI find myself reusing the same few rules over and over again, just with minor changes. Here are some useful examples to refer back to.\n\nExcluding a directory\n\nAs mentioned above, if you\u2019re rewriting lots of fancy URLs to a collection of real files it can be helpful to put those files in a folder and exclude it from rewrite rules. This helps solve the issue of rewrite rules reapplying to your newly rewritten URL. To exclude a directory, put a rule like this at the top of your file, before your other rules. Our files are in a folder called _source, the dash in the rule means do nothing, and the L flag means the following rules won\u2019t be applied.\n\nRewriteRule ^_source - [L]\n\nThis is also useful for excluding things like CMS folders from your website\u2019s rewrite rules\n\nRewriteRule ^perch - [L] \n\nAdding or removing www from the domain\n\nSome folk like to use a www and others don\u2019t. Usually, it\u2019s best to pick one and go with it, and redirect the one you don\u2019t want. On this site, we don\u2019t use www.24ways.org so we redirect those requests to 24ways.org.\n\nThis uses a RewriteCond which is like an if for a rewrite rule: \u201cIf this condition matches, then apply the following rule.\u201d In this case, it\u2019s if the HTTP HOST (or domain name, basically) matches this pattern, then redirect everything:\n\nRewriteCond %{HTTP_HOST} ^www.24ways.org$ [NC]\nRewriteRule ^(.*)$ http://24ways.org/$1 [R=301,L]\n\nThe [NC] flag means \u2018no case\u2019 \u2014 the match is case-insensitive. The dots in the domain are escaped with a backslash, as a dot is a regular expression character which means match anything, so we escape it because we literally mean a dot in this instance.\n\nRemoving file extensions\n\nSometimes all you need to do to tidy up a URL is strip off the technology-specific file extension, so that /about/history.php becomes /about/history. This is easily achieved with the help of some more rewrite conditions.\n\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_FILENAME}.php -f\nRewriteRule ^(.+)$ $1.php [L,QSA]\n\nThis says if the file being asked for isn\u2019t a file (!-f) and if it isn\u2019t a directory (!-d) and if the file name plus .php is an actual file (-f) then rewrite by adding .php on the end. The QSA flag means \u2018query string append\u2019: append the existing query string onto the rewritten URL.\n\nIt\u2019s these sorts of more generic catch-all rules that you need to watch out for when your .htaccess gets rerun after a successful match. Without care they can easily rematch the newly rewritten URL.\n\nLogging for when it all goes wrong\n\nAlthough not possible within your .htaccess file, if you have access to your Apache configuration files you can enable rewrite logging. This can be useful to track down where a rule is going wrong, if it\u2019s matching incorrectly or failing to match. It also gives you an overview of the amount of work being done by the rewrite engine, enabling you to rearrange your rules and maximise performance.\n\nRewriteEngine On\nRewriteLog \"/full/system/path/to/rewrite.log\"\nRewriteLogLevel 5\n\nTo be doubly clear: this will not work from an .htaccess file \u2014 it needs to be added to the main Apache configuration files. (I sometimes work using MAMP PRO locally on my Mac, and this can be pasted into the snappily named Customized virtual host general settings box in the Advanced tab for your site.)\n\nThe white screen of death\n\nOne of the most frustrating things when working with rewrite rules is that when you make a mistake it can result in the server returning an HTTP 500 Internal Server Error. This in itself isn\u2019t an error message, of course. It\u2019s more of a notification that an error has occurred. The real error message can usually be found in your Apache error log.\n\nIf you have access to your server logs, check the Apache error log and you\u2019ll usually find a much more descriptive error message, pointing you towards your mistake. (Again, if using MAMP PRO, go to Server, Apache and the View Log button.)\n\nIn conclusion\n\nRewriting URLs can be a bear, but the advantages are clear. Keeping a tidy URL structure, disconnected from the technology or file structure of your site can result in URLs that are easier to use and easier to maintain into the future.\n\nIf you\u2019re redesigning a site, remember that cool URIs don\u2019t change, so budget some time to make sure that any content you move has a rewrite rule associated with it to keep any links working.\n\nFurther reading\n\nTo find out more about URL rewriting and perhaps even learn more about regular expressions, I can recommend the following resources.\n\n\n\tFrom the horse\u2019s mouth, the Apache mod_rewrite documentation\n\tParticularly useful with that documentation is the RewriteRule Flags listing\n\tYou may wish to don sunglasses to follow the otherwise comprehensive Regular-Expressions.info tutorial\n\tFriend of 24 ways, Neil Crosby has a mod_rewrite Beginner\u2019s Guide which I\u2019ve found handy over the years.\n\n\nAs noted at the start, this isn\u2019t a fully comprehensive guide, but I hope it\u2019s useful in finding your feet with a powerful but sometimes annoying technology. Do you have useful snippets you often use on projects? Feel free to share them in the comments.", "year": "2013", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2013-12-01T00:00:00+00:00", "url": "https://24ways.org/2013/url-rewriting-for-the-fearful/", "topic": "code"} {"rowid": 18, "title": "Grunt for People Who Think Things Like Grunt are Weird and Hard", "contents": "Front-end developers are often told to do certain things:\n\n\n\tWork in as small chunks of CSS and JavaScript as makes sense to you, then concatenate them together for the production website.\n\tCompress your CSS and minify your JavaScript to make their file sizes as small as possible for your production website.\n\tOptimize your images to reduce their file size without affecting quality.\n\tUse Sass for CSS authoring because of all the useful abstraction it allows.\n\n\nThat\u2019s not a comprehensive list of course, but those are the kind of things we need to do. You might call them tasks.\n\nI bet you\u2019ve heard of Grunt. Well, Grunt is a task runner. Grunt can do all of those things for you. Once you\u2019ve got it set up, which isn\u2019t particularly difficult, those things can happen automatically without you having to think about them again.\n\nBut let\u2019s face it: Grunt is one of those fancy newfangled things that all the cool kids seem to be using but at first glance feels strange and intimidating. I hear you. This article is for you.\n\nLet\u2019s nip some misconceptions in the bud right away\n\nPerhaps you\u2019ve heard of Grunt, but haven\u2019t done anything with it. I\u2019m sure that applies to many of you. Maybe one of the following hang-ups applies to you.\n\nI don\u2019t need the things Grunt does\n\nYou probably do, actually. Check out that list up top. Those things aren\u2019t nice-to-haves. They are pretty vital parts of website development these days. If you already do all of them, that\u2019s awesome. Perhaps you use a variety of different tools to accomplish them. Grunt can help bring them under one roof, so to speak. If you don\u2019t already do all of them, you probably should and Grunt can help. Then, once you are doing those, you can keep using Grunt to do more for you, which will basically make you better at doing your job.\n\nGrunt runs on Node.js \u2014 I don\u2019t know Node\n\nYou don\u2019t have to know Node. Just like you don\u2019t have to know Ruby to use Sass. Or PHP to use WordPress. Or C++ to use Microsoft Word.\n\nI have other ways to do the things Grunt could do for me\n\nAre they all organized in one place, configured to run automatically when needed, and shared among every single person working on that project? Unlikely, I\u2019d venture.\n\nGrunt is a command line tool \u2014 I\u2019m just a designer\n\nI\u2019m a designer too. I prefer native apps with graphical interfaces when I can get them. But I don\u2019t think that\u2019s going to happen with Grunt1.\n\nThe extent to which you need to use the command line is:\n\n\n\tNavigate to your project\u2019s directory.\n\tType grunt and press Return.\n\n\nAfter set-up, that is, which again isn\u2019t particularly difficult.\n\nOK. Let\u2019s get Grunt installed\n\nNode is indeed a prerequisite for Grunt. If you don\u2019t have Node installed, don\u2019t worry, it\u2019s very easy. You literally download an installer and run it. Click the big Install button on the Node website.\n\nYou install Grunt on a per-project basis. Go to your project\u2019s folder. It needs a file there named package.json at the root level. You can just create one and put it there.\n\n package.json at root\n\nThe contents of that file should be this:\n\n{\n \"name\": \"example-project\",\n \"version\": \"0.1.0\",\n \"devDependencies\": {\n \"grunt\": \"~0.4.1\"\n }\n}\n\nFeel free to change the name of the project and the version, but the devDependencies thing needs to be in there just like that.\n\nThis is how Node does dependencies. Node has a package manager called NPM (Node packaged modules) for managing Node dependencies (like a gem for Ruby if you\u2019re familiar with that). You could even think of it a bit like a plug-in for WordPress.\n\nOnce that package.json file is in place, go to the terminal and navigate to your folder. Terminal rubes like me do it like this:\n\n Terminal rube changing directories\n\nThen run the command:\n\nnpm install\n\nAfter you\u2019ve run that command, a new folder called node_modules will show up in your project.\n\n Example of node_modules folder\n\nThe other files you see there, README.md and LICENSE are there because I\u2019m going to put this project on GitHub and that\u2019s just standard fare there.\n\nThe last installation step is to install the Grunt CLI (command line interface). That\u2019s what makes the grunt command in the terminal work. Without it, typing grunt will net you a \u201cCommand Not Found\u201d-style error. It is a separate installation for efficiency reasons. Otherwise, if you had ten projects you\u2019d have ten copies of Grunt CLI.\n\nThis is a one-liner again. Just run this command in the terminal:\n\nnpm install -g grunt-cli\n\nYou should close and reopen the terminal as well. That\u2019s a generic good practice to make sure things are working right. Kinda like restarting your computer after you install a new application was in the olden days.\n\nLet\u2019s make Grunt concatenate some files\n\nPerhaps in our project there are three separate JavaScript files:\n\n\n\tjquery.js \u2013 The library we are using.\n\tcarousel.js \u2013 A jQuery plug-in we are using.\n\tglobal.js \u2013 Our authored JavaScript file where we configure and call the plug-in.\n\n\nIn production, we would concatenate all those files together for performance reasons (one request is better than three). We need to tell Grunt to do this for us.\n\nBut wait. Grunt actually doesn\u2019t do anything all by itself. Remember Grunt is a task runner. The tasks themselves we will need to add. We actually haven\u2019t set up Grunt to do anything yet, so let\u2019s do that.\n\nThe official Grunt plug-in for concatenating files is grunt-contrib-concat. You can read about it on GitHub if you want, but all you have to do to use it on your project is to run this command from the terminal (it will henceforth go without saying that you need to run the given commands from your project\u2019s root folder):\n\nnpm install grunt-contrib-concat --save-dev\n\nA neat thing about doing it this way: your package.json file will automatically be updated to include this new dependency. Open it up and check it out. You\u2019ll see a new line:\n\n\"grunt-contrib-concat\": \"~0.3.0\"\n\nNow we\u2019re ready to use it. To use it we need to start configuring Grunt and telling it what to do.\n\nYou tell Grunt what to do via a configuration file named Gruntfile.js2\n\nJust like our package.json file, our Gruntfile.js has a very special format that must be just right. I wouldn\u2019t worry about what every word of this means. Just check out the format:\n\nmodule.exports = function(grunt) {\n\n // 1. All configuration goes here \n grunt.initConfig({\n pkg: grunt.file.readJSON('package.json'),\n\n concat: {\n // 2. Configuration for concatinating files goes here.\n }\n\n });\n\n // 3. Where we tell Grunt we plan to use this plug-in.\n grunt.loadNpmTasks('grunt-contrib-concat');\n\n // 4. Where we tell Grunt what to do when we type \"grunt\" into the terminal.\n grunt.registerTask('default', ['concat']);\n\n};\n\nNow we need to create that configuration. The documentation can be overwhelming. Let\u2019s focus just on the very simple usage example.\n\nRemember, we have three JavaScript files we\u2019re trying to concatenate. We\u2019ll list file paths to them under src in an array of file paths (as quoted strings) and then we\u2019ll list a destination file as dest. The destination file doesn\u2019t have to exist yet. It will be created when this task runs and squishes all the files together.\n\nBoth our jquery.js and carousel.js files are libraries. We most likely won\u2019t be touching them. So, for organization, we\u2019ll keep them in a /js/libs/ folder. Our global.js file is where we write our own code, so that will be right in the /js/ folder. Now let\u2019s tell Grunt to find all those files and squish them together into a single file named production.js, named that way to indicate it is for use on our real live website.\n\nconcat: { \n dist: {\n src: [\n 'js/libs/*.js', // All JS in the libs folder\n 'js/global.js' // This specific file\n ],\n dest: 'js/build/production.js',\n }\n}\n\nNote: throughout this article there will be little chunks of configuration code like above. The intention is to focus in on the important bits, but it can be confusing at first to see how a particular chunk fits into the larger file. If you ever get confused and need more context, refer to the complete file.\n\nWith that concat configuration in place, head over to the terminal, run the command:\n\ngrunt\n\nand watch it happen! production.js will be created and will be a perfect concatenation of our three files. This was a big aha! moment for me. Feel the power course through your veins. Let\u2019s do more things!\n\nLet\u2019s make Grunt minify that JavaScript\n\nWe have so much prep work done now, adding new tasks for Grunt to run is relatively easy. We just need to:\n\n\n\tFind a Grunt plug-in to do what we want\n\tLearn the configuration style of that plug-in\n\tWrite that configuration to work with our project\n\n\nThe official plug-in for minifying code is grunt-contrib-uglify. Just like we did last time, we just run an NPM command to install it:\n\nnpm install grunt-contrib-uglify --save-dev\n\nThen we alter our Gruntfile.js to load the plug-in:\n\ngrunt.loadNpmTasks('grunt-contrib-uglify');\n\nThen we configure it:\n\nuglify: {\n build: {\n src: 'js/build/production.js',\n dest: 'js/build/production.min.js'\n }\n}\n\nLet\u2019s update that default task to also run minification:\n\ngrunt.registerTask('default', ['concat', 'uglify']);\n\nSuper-similar to the concatenation set-up, right?\n\nRun grunt at the terminal and you\u2019ll get some deliciously minified JavaScript:\n\n Minified JavaScript\n\nThat production.min.js file is what we would load up for use in our index.html file.\n\nLet\u2019s make Grunt optimize our images\n\nWe\u2019ve got this down pat now. Let\u2019s just go through the motions. The official image minification plug-in for Grunt is grunt-contrib-imagemin. Install it:\n\nnpm install grunt-contrib-imagemin --save-dev\n\nRegister it in the Gruntfile.js:\n\ngrunt.loadNpmTasks('grunt-contrib-imagemin');\n\nConfigure it:\n\nimagemin: {\n dynamic: {\n files: [{\n expand: true,\n cwd: 'images/',\n src: ['**/*.{png,jpg,gif}'],\n dest: 'images/build/'\n }]\n }\n}\n\nMake sure it runs:\n\ngrunt.registerTask('default', ['concat', 'uglify', 'imagemin']);\n\nRun grunt and watch that gorgeous squishification happen:\n\n Squished images\n\nGotta love performance increases for nearly zero effort.\n\nLet\u2019s get a little bit smarter and automate\n\nWhat we\u2019ve done so far is awesome and incredibly useful. But there are a couple of things we can get smarter on and make things easier on ourselves, as well as Grunt:\n\n\n\tRun these tasks automatically when they should\n\tRun only the tasks needed at the time\n\n\nFor instance:\n\n\n\tConcatenate and minify JavaScript when JavaScript changes\n\tOptimize images when a new image is added or an existing one changes\n\n\nWe can do this by watching files. We can tell Grunt to keep an eye out for changes to specific places and, when changes happen in those places, run specific tasks. Watching happens through the official grunt-contrib-watch plugin.\n\nI\u2019ll let you install it. It is exactly the same process as the last few plug-ins we installed. We configure it by giving watch specific files (or folders, or both) to watch. By watch, I mean monitor for file changes, file deletions or file additions. Then we tell it what tasks we want to run when it detects a change.\n\nWe want to run our concatenation and minification when anything in the /js/ folder changes. When it does, we should run the JavaScript-related tasks. And when things happen elsewhere, we should not run the JavaScript-related tasks, because that would be irrelevant. So:\n\nwatch: {\n scripts: {\n files: ['js/*.js'],\n tasks: ['concat', 'uglify'],\n options: {\n spawn: false,\n },\n } \n}\n\nFeels pretty comfortable at this point, hey? The only weird bit there is the spawn thing. And you know what? I don\u2019t even really know what that does. From what I understand from the documentation it is the smart default. That\u2019s real-world development. Just leave it alone if it\u2019s working and if it\u2019s not, learn more.\n\nNote: Isn\u2019t it frustrating when something that looks so easy in a tutorial doesn\u2019t seem to work for you? If you can\u2019t get Grunt to run after making a change, it\u2019s very likely to be a syntax error in your Gruntfile.js. That might look like this in the terminal:\n\n Errors running Grunt\n\nUsually Grunt is pretty good about letting you know what happened, so be sure to read the error message. In this case, a syntax error in the form of a missing comma foiled me. Adding the comma allowed it to run.\n\nLet\u2019s make Grunt do our preprocessing\n\nThe last thing on our list from the top of the article is using Sass \u2014 yet another task Grunt is well-suited to run for us. But wait? Isn\u2019t Sass technically in Ruby? Indeed it is. There is a version of Sass that will run in Node and thus not add an additional dependency to our project, but it\u2019s not quite up-to-snuff with the main Ruby project. So, we\u2019ll use the official grunt-contrib-sass plug-in which just assumes you have Sass installed on your machine. If you don\u2019t, follow the command line instructions.\n\nWhat\u2019s neat about Sass is that it can do concatenation and minification all by itself. So for our little project we can just have it compile our main global.scss file:\n\nsass: {\n dist: {\n options: {\n style: 'compressed'\n },\n files: {\n 'css/build/global.css': 'css/global.scss'\n }\n } \n}\n\nWe wouldn\u2019t want to manually run this task. We already have the watch plug-in installed, so let\u2019s use it! Within the watch configuration, we\u2019ll add another subtask:\n\ncss: {\n files: ['css/*.scss'],\n tasks: ['sass'],\n options: {\n spawn: false,\n }\n}\n\nThat\u2019ll do it. Now, every time we change any of our Sass files, the CSS will automaticaly be updated.\n\nLet\u2019s take this one step further (it\u2019s absolutely worth it) and add LiveReload. With LiveReload, you won\u2019t have to go back to your browser and refresh the page. Page refreshes happen automatically and in the case of CSS, new styles are injected without a page refresh (handy for heavily state-based websites).\n\nIt\u2019s very easy to set up, since the LiveReload ability is built into the watch plug-in. We just need to:\n\n\nInstall the browser plug-in\nAdd to the top of the watch configuration:\n. watch: {\n options: {\n livereload: true,\n },\n scripts: { \n /* etc */\n\nRestart the browser and click the LiveReload icon to activate it.\nUpdate some Sass and watch it change the page automatically.\n\n\n Live reloading browser\n\nYum.\n\nPrefer a video?\n\nIf you\u2019re the type that likes to learn by watching, I\u2019ve made a screencast to accompany this article that I\u2019ve published over on CSS-Tricks: First Moments with Grunt\n\nLeveling up\n\nAs you might imagine, there is a lot of leveling up you can do with your build process. It surely could be a full time job in some organizations.\n\nSome hardcore devops nerds might scoff at the simplistic setup we have going here. But I\u2019d advise them to slow their roll. Even what we have done so far is tremendously valuable. And don\u2019t forget this is all free and open source, which is amazing.\n\nYou might level up by adding more useful tasks:\n\n\n\tRunning your CSS through Autoprefixer (A+ Would recommend) instead of a preprocessor add-ons.\n\tWriting and running JavaScript unit tests (example: Jasmine).\n\tBuild your image sprites and SVG icons automatically (example: Grunticon).\n\tStart a server, so you can link to assets with proper file paths and use services that require a real URL like TypeKit and such, as well as remove the need for other tools that do this, like MAMP.\n\tCheck for code problems with HTML-Inspector, CSS Lint, or JS Hint.\n\tHave new CSS be automatically injected into the browser when it ever changes.\n\tHelp you commit or push to a version control repository like GitHub.\n\tAdd version numbers to your assets (cache busting).\n\tHelp you deploy to a staging or production environment (example: DPLOY).\n\n\nYou might level up by simply understanding more about Grunt itself:\n\n\n\tRead Grunt Boilerplate by Mark McDonnell.\n\tRead Grunt Tips and Tricks by Nicolas Bevacqua.\n\tOrganize your Gruntfile.js by splitting it up into smaller files.\n\tCheck out other people\u2019s and projects\u2019 Gruntfile.js.\n\tLearn more about Grunt by digging into its source and learning about its API.\n\n\nLet\u2019s share\n\nI think some group sharing would be a nice way to wrap this up. If you are installing Grunt for the first time (or remember doing that), be especially mindful of little frustrating things you experience(d) but work(ed) through. Those are the things we should share in the comments here. That way we have this safe place and useful resource for working through those confusing moments without the embarrassment. We\u2019re all in this thing together!\n\n \n\n1 Maybe someday someone will make a beautiful Grunt app for your operating system of choice. But I\u2019m not sure that day will come. The configuration of the plug-ins is the important part of using Grunt. Each plug-in is a bit different, depending on what it does. That means a uniquely considered UI for every single plug-in, which is a long shot.\n\nPerhaps a decent middleground is this Grunt DevTools Chrome add-on.\n\n2 Gruntfile.js is often referred to as Gruntfile in documentation and examples. Don\u2019t literally name it Gruntfile \u2014 it won\u2019t work.", "year": "2013", "author": "Chris Coyier", "author_slug": "chriscoyier", "published": "2013-12-11T00:00:00+00:00", "url": "https://24ways.org/2013/grunt-is-not-weird-and-hard/", "topic": "code"} {"rowid": 20, "title": "Make Your Browser Dance", "contents": "It was a crisp winter\u2019s evening when I pulled up alongside the pier. I stepped out of my car and the bitterly cold sea air hit my face. I walked around to the boot, opened it and heaved out a heavy flight case. I slammed the boot shut, locked the car and started walking towards the venue.\n\nThis was it. My first gig. I thought about all those weeks of preparation: editing video clips, creating 3-D objects, making coloured patterns, then importing them all into software and configuring effects to change as the music did; targeting frequency, beat, velocity, modifying size, colour, starting point; creating playlists of these\u2026 and working out ways to mix them as the music played.\n\nThis was it. This was me VJing.\n\nThis was all a lifetime (well a decade!) ago.\n\nWhen I started web designing, VJing took a back seat. I was more interested in interactive layouts, semantic accessible HTML, learning all the IE bugs and mastering the quirks that CSS has to offer. More recently, I have been excited by background gradients, 3-D transforms, the @keyframe directive, as well as new APIs such as getUserMedia, indexedDB, the Web Audio API\n\nBut wait, have I just come full circle? Could it be possible, with these wonderful new things in technologies I am already familiar with, that I could VJ again, right here, in a browser?\n\nWell, there\u2019s only one thing to do: let\u2019s try it!\n\nLet\u2019s take to the dance floor \n\nOver the past couple of years working in The Lab I have learned to take a much more iterative approach to projects than before. One of my new favourite methods of working is to create a proof of concept to make sure my theory is feasible, before going on to create a full-blown product. So let\u2019s take the same approach here.\n\nThe main VJing functionality I want to recreate is manipulating visuals in relation to sound. So for my POC I need to create a visual, with parameters that can be changed, then get some sound and see if I can analyse that sound to detect some data, which I can then use to manipulate the visual parameters. Easy, right?\n\nSo, let\u2019s start at the beginning: creating a simple visual. For this I\u2019m going to create a CSS animation. It\u2019s just a funky i element with the opacity being changed to make it flash.\n\n See the Pen Creating a light by Rumyra (@Rumyra) on CodePen\n\nA note about prefixes: I\u2019ve left them out of the code examples in this post to make them easier to read. Please be aware that you may need them. I find a great resource to find out if you do is caniuse.com. You can also check out all the code for the examples in this article\n\nStart the music\n\nWell, that\u2019s pretty easy so far. Next up: loading in some sound. For this we\u2019ll use the Web Audio API. The Web Audio API is based around the concept of nodes. You have a source node: the sound you are loading in; a destination node: usually the device\u2019s speakers; and any number of processing nodes in between. All this processing that goes on with the audio is sandboxed within the AudioContext.\n\nSo, let\u2019s start by initialising our audio context.\n\nvar contextClass = window.AudioContext;\nif (contextClass) {\n //web audio api available.\n var audioContext = new contextClass();\n} else {\n //web audio api unavailable\n //warn user to upgrade/change browser\n}\n\nNow let\u2019s load our sound file into the new context we created with an XMLHttpRequest.\n\nfunction loadSound() {\n\t//set audio file url\n\tvar audioFileUrl = '/octave.ogg';\n\t//create new request\n\tvar request = new XMLHttpRequest();\n\trequest.open(\"GET\", audioFileUrl, true);\n\trequest.responseType = \"arraybuffer\";\n\n\trequest.onload = function() {\n\t\t//take from http request and decode into buffer\n\t\tcontext.decodeAudioData(request.response, function(buffer) {\n\t \taudioBuffer = buffer;\n\t });\n\t\t}\n\trequest.send();\n}\n\nPhew! Now we\u2019ve loaded in some sound! There are plenty of things we can do with the Web Audio API: increase volume; add filters; spatialisation. If you want to dig deeper, the O\u2019Reilly Web Audio API book by Boris Smus is available to read online free.\n\nAll we really want to do for this proof of concept, however, is analyse the sound data. To do this we really need to know what data we have.\n\n Learning the steps\n\nLet\u2019s take a minute to step back and remember our school days and science class. I\u2019m sure if I drew a picture of a sound wave, we would all start nodding our heads.\n\n \n\nThe sound you hear is caused by pressure differences in the particles in the air. Sound pushes these particles together, causing vibrations. Amplitude is basically strength of pressure. A simple example of change of amplitude is when you increase the volume on your stereo and the output wave increases in size.\n\nThis is great when everything is analogue, but the waveform varies continuously and it\u2019s not suitable for digital processing: there\u2019s an infinite set of values. For digital processing, we need discrete numbers.\n\nWe have to sample the waveform at set time intervals, and record data such as amplitude and frequency. Luckily for us, just the fact we have a digital sound file means all this hard work is done for us. What we\u2019re doing in the code above is piping that data in the audio context. All we need to do now is access it.\n\nWe can do this with the Web Audio API\u2019s analysing functionality. Just pop in an analysing node before we connect the source to its destination node.\n\nfunction createAnalyser(source) {\n\t//create analyser node\n\tanalyser = audioContext.createAnalyser();\n\t//connect to source\n\tsource.connect(analyzer);\n\t//pipe to speakers\n\tanalyser.connect(audioContext.destination);\n}\n\nThe data I\u2019m really interested in here is frequency. Later we could look into amplitude or time, but for now I\u2019m going to stick with frequency.\n\nThe analyser node gives us frequency data via the getFrequencyByteData method.\n\n Don\u2019t forget to count!\n\nTo collect the data from the getFrequencyByteData method, we need to pass in an empty array (a JavaScript typed array is ideal). But how do we know how many items the array will need when we create it?\n\nThis is really up to us and how high the resolution of frequencies we want to analyse is. Remember we talked about sampling the waveform; this happens at a certain rate (sample rate) which you can find out via the audio context\u2019s sampleRate attribute. This is good to bear in mind when you\u2019re thinking about your resolution of frequencies.\n\nvar sampleRate = audioContext.sampleRate;\n\nLet\u2019s say your file sample rate is 48,000, making the maximum frequency in the file 24,000Hz (thanks to a wonderful theorem from Dr Harry Nyquist, the maximum frequency in the file is always half the sample rate). The analyser array we\u2019re creating will contain frequencies up to this point. This is ideal as the human ear hears the range 0\u201320,000hz.\n\nSo, if we create an array which has 2,400 items, each frequency recorded will be 10Hz apart. However, we are going to create an array which is half the size of the FFT (fast Fourier transform), which in this case is 2,048 which is the default. You can set it via the fftSize property.\n\n//set our FFT size\nanalyzer.fftSize = 2048;\n//create an empty array with 1024 items\nvar frequencyData = new Uint8Array(1024);\n\nSo, with an array of 1,024 items, and a frequency range of 24,000Hz, we know each item is 24,000 \u00f7 1,024 = 23.44Hz apart.\n\nThe thing is, we also want that array to be updated constantly. We could use the setInterval or setTimeout methods for this; however, I prefer the new and shiny requestAnimationFrame.\n\nfunction update() {\n \t//constantly getting feedback from data\n \trequestAnimationFrame(update);\n \tanalyzer.getByteFrequencyData(frequencyData);\n}\n\n Putting it all together\n\nSweet sticks! Now we have an array of frequencies from the sound we loaded, updating as the sound plays. Now we want that data to trigger our animation from earlier.\n\nWe can easily pause and run our CSS animation from JavaScript:\n\nelement.style.webkitAnimationPlayState = \"paused\";\nelement.style.webkitAnimationPlayState = \"running\";\n\nUnfortunately, this may not be ideal as our animation might be a whole heap longer than just a flashing light. We may want to target specific points within that animation to have it stop and start in a visually pleasing way and perhaps not smack bang in the middle.\n\nThere is no really easy way to do this at the moment as Zach Saucier explains in this wonderful article. It takes some jiggery pokery with setInterval to try to ascertain how far through the CSS animation you are in percentage terms.\n\nThis seems a bit much for our proof of concept, so let\u2019s backtrack a little. We know by the animation we\u2019ve created which CSS properties we want to change. This is pretty easy to do directly with JavaScript.\n\nelement.style.opacity = \"1\";\nelement.style.opacity = \"0.2\";\n\nSo let\u2019s start putting it all together. For this example I want to trigger each light as a different frequency plays. For this, I\u2019ll loop through the HTML elements and change the opacity style if the frequency gain goes over a certain threshold.\n\n//get light elements\nvar lights = document.getElementsByTagName('i');\nvar totalLights = lights.length;\n\nfor (var i=0; i 160){\n //start animation on element\n lights[i].style.opacity = \"1\";\n } else {\n lights[i].style.opacity = \"0.2\";\n }\n}\n\nSee all the code in action here. I suggest viewing in a modern browser :)\n\nAwesome! It is true \u2014 we can VJ in our browser!\n\nLet\u2019s dance!\n\nSo, let\u2019s start to expand this simple example. First, I feel the need to make lots of lights, rather than just a few. Also, maybe we should try a sound file more suited to gigs or clubs.\n\nCheck it out!\n\nI don\u2019t know about you, but I\u2019m pretty excited \u2014 that\u2019s just a bit of HTML, CSS and JavaScript!\n\nThe other thing to think about, of course, is the sound that you would get at a venue. We don\u2019t want to load sound from a file, but rather pick up on what is playing in real time. The easiest way to do this, I\u2019ve found, is to capture what my laptop\u2019s mic is picking up and piping that back into the audio context. We can do this by using getUserMedia.\n\nLet\u2019s include this in this demo. If you make some noise while viewing the demo, the lights will start to flash.\n\n And relax :)\n\nThere you have it. Sit back, play some music and enjoy the Winamp like experience in front of you.\n\nSo, where do we go from here? I already have a wealth of ideas. We haven\u2019t started with canvas, SVG or the 3-D features of CSS. There are other things we can detect from the audio as well. And yes, OK, it\u2019s questionable whether the browser is the best environment for this. For one, I\u2019m using a whole bunch of nonsensical HTML elements (maybe each animation could be held within a web component in the future). But hey, it\u2019s fun, and it looks cool and sometimes I think it\u2019s OK to just dance.", "year": "2013", "author": "Ruth John", "author_slug": "ruthjohn", "published": "2013-12-02T00:00:00+00:00", "url": "https://24ways.org/2013/make-your-browser-dance/", "topic": "code"} {"rowid": 21, "title": "Keeping Parts of Your Codebase Private on GitHub", "contents": "Open source is brilliant, there\u2019s no denying that, and GitHub has been instrumental in open source\u2019s recent success. I\u2019m a keen open-sourcerer myself, and I have a number of projects on GitHub. However, as great as sharing code is, we often want to keep some projects to ourselves. To this end, GitHub created private repositories which act like any other Git repository, only, well, private!\n\nA slightly less common issue, and one I\u2019ve come up against myself, is the desire to only keep certain parts of a codebase private. A great example would be my site, CSS Wizardry; I want the code to be open source so that people can poke through and learn from it, but I want to keep any draft blog posts private until they are ready to go live. Thankfully, there is a very simple solution to this particular problem: using multiple remotes.\n\nBefore we begin, it\u2019s worth noting that you can actually build a GitHub Pages site from a private repo. You can keep the entire source private, but still have GitHub build and display a full Pages/Jekyll site. I do this with csswizardry.net. This post will deal with the more specific problem of keeping only certain parts of the codebase (branches) private, and expose parts of it as either an open source project, or a built GitHub Pages site.\n\nN.B. This post requires some basic Git knowledge.\n\nAdding your public remote\n\nLet\u2019s assume you\u2019re starting from scratch and you currently have no repos set up for your project. (If you do already have your public repo set up, skip to the \u201cAdding your private remote\u201d section.)\n\nSo, we have a clean slate: nothing has been set up yet, we\u2019re doing all of that now. On GitHub, create two repositories. For the sake of this article we shall call them site.com and private.site.com. Make the site.com repo public, and the private.site.com repo private (you will need a paid GitHub account).\n\nOn your machine, create the site.com directory, in which your project will live. Do your initial work in there, commit some stuff \u2014 whatever you need to do. Now we need to link this local Git repo on your machine with the public repo (remote) on GitHub. We should all be used to this:\n\n$ git remote add origin git@github.com:[user]/site.com.git\n\nHere we are simply telling Git to add a remote called origin which lives at git@github.com:[user]/site.com.git. Simple stuff. Now we need to push our current branch (which will be master, unless you\u2019ve explicitly changed it) to that remote:\n\n$ git push -u origin master\n\nHere we are telling Git to push our master branch to a corresponding master branch on the remote called origin, which we just added. The -u sets upstream tracking, which basically tells Git to always shuttle code on this branch between the local master branch and the master branch on the origin remote. Without upstream tracking, you would have to tell Git where to push code to (and pull it from) every time you ran the push or pull commands. This sets up a permanent bond, if you like.\n\nThis is really simple stuff, stuff that you will probably have done a hundred times before as a Git user. Now to set up our private remote.\n\nAdding your private remote\n\nWe\u2019ve set up our public, open source repository on GitHub, and linked that to the repository on our machine. All of this code will be publicly viewable on GitHub.com. (Remember, GitHub is just a host of regular Git repositories, which also puts a nice GUI around it all.) We want to add the ability to keep certain parts of the codebase private. What we do now is add another remote repository to the same local repository. We have two repos on GitHub (site.com and private.site.com), but only one repository (and, therefore, one directory) on our machine. Two GitHub repos, and one local one.\n\nIn your local repo, check out a new branch. For the sake of this article we shall call the branch dev. This branch might contain work in progress, or draft blog posts, or anything you don\u2019t want to be made publicly viewable on GitHub.com. The contents of this branch will, in a moment, live in our private repository.\n\n$ git checkout -b dev\n\nWe have now made a new branch called dev off the branch we were on last (master, unless you renamed it).\n\nNow we need to add our private remote (private.site.com) so that, in a second, we can send this branch to that remote:\n\n$ git remote add private git@github.com:[user]/private.site.com.git\n\nLike before, we are just telling Git to add a new remote to this repo, only this time we\u2019ve called it private and it lives at git@github.com:[user]/private.site.com.git. We now have one local repo on our machine which has two remote repositories associated with it.\n\nNow we need to tell our dev branch to push to our private remote:\n\n$ git push -u private dev\n\nHere, as before, we are pushing some code to a repo. We are saying that we want to push the dev branch to the private remote, and, once again, we\u2019ve set up upstream tracking. This means that, by default, the dev branch will only push and pull to and from the private remote (unless you ever explicitly state otherwise).\n\nNow you have two branches (master and dev respectively) that push to two remotes (origin and private respectively) which are public and private respectively.\n\nAny work we do on the master branch will push and pull to and from our publicly viewable remote, and any code on the dev branch will push and pull from our private, hidden remote.\n\nAdding more branches\n\nSo far we\u2019ve only looked at two branches pushing to two remotes, but this workflow can grow as much or as little as you\u2019d like. Of course, you\u2019d never do all your work in only two branches, so you might want to push any number of them to either your public or private remotes. Let\u2019s imagine we want to create a branch to try something out real quickly:\n\n$ git checkout -b test\n\nNow, when we come to push this branch, we can choose which remote we send it to:\n\n$ git push -u private test\n\nThis pushes the new test branch to our private remote (again, setting the persistent tracking with -u).\n\nYou can have as many or as few remotes or branches as you like.\n\nCombining the two\n\nLet\u2019s say you\u2019ve been working on a new feature in private for a few days, and you\u2019ve kept that on the private remote. You\u2019ve now finalised the addition and want to move it into your public repo. This is just a simple merge. Check out your master branch:\n\n$ git checkout master\n\nThen merge in the branch that contained the feature:\n\n$ git merge dev\n\nNow master contains the commits that were made on dev and, once you\u2019ve pushed master to its remote, those commits will be viewable publicly on GitHub:\n\n$ git push\n\nNote that we can just run $ git push on the master branch as we\u2019d previously set up our upstream tracking (-u).\n\nMultiple machines\n\nSo far this has covered working on just one machine; we had two GitHub remotes and one local repository. Let\u2019s say you\u2019ve got yourself a new Mac (yay!) and you want to clone an existing project:\n\n$ git clone git@github.com:[user]/site.com.git\n\nThis will not clone any information about the remotes you had set up on the previous machine. Here you have a fresh clone of the public project and you will need to add the private remote to it again, as above.\n\nDone!\n\nIf you\u2019d like to see me blitz through all that in one go, check the showterm recording.\n\nThe beauty of this is that we can still share our code, but we don\u2019t have to develop quite so openly all of the time. Building a framework with a killer new feature? Keep it in a private branch until it\u2019s ready for merge. Have a blog post in a Jekyll site that you\u2019re not ready to make live? Keep it in a private drafts branch. Working on a new feature for your personal site? Tuck it away until it\u2019s finished. Need a staging area for a Pages-powered site? Make a staging remote with its own custom domain.\n\nAll this boils down to, really, is the fact that you can bring multiple remotes together into one local codebase on your machine. What you do with them is entirely up to you!", "year": "2013", "author": "Harry Roberts", "author_slug": "harryroberts", "published": "2013-12-09T00:00:00+00:00", "url": "https://24ways.org/2013/keeping-parts-of-your-codebase-private-on-github/", "topic": "code"} {"rowid": 30, "title": "Making Sites More Responsive, Responsibly", "contents": "With digital projects we\u2019re used to shifting our thinking to align with our target audience. We may undertake research, create personas, identify key tasks, or observe usage patterns, with our findings helping to refine our ongoing creations.\u00a0A product\u2019s overall experience can make or break its success, and when it comes to defining these experiences our development choices play a huge role alongside more traditional user-focused activities.\n\nThe popularisation of responsive web design is a great example of how we are able to shape the web\u2019s direction through using technology to provide better experiences. If we think back to the move from table-based layouts to CSS, initially our clients often didn\u2019t know or care about the difference in these approaches, but\u00a0we\u00a0did. Responsive design was similar in this respect \u2013 momentum grew through the web industry choosing to use an approach that we felt would give a better experience, and which was more future-friendly.\u00a0\n\nWe tend to think of responsive design as a means of displaying content appropriately across a range of devices, but the technology and our implementation of it can facilitate much more. A responsive layout not only helps your content work when the newest smartphone comes out, but it also ensures your layout suitably adapts if a visually impaired user drastically changes the size of the text.\n\n The 24 ways site at 400% on a Retina MacBook Pro displays a layout more typically used for small screens.\n\nWhen we think more broadly, we realise that our technical choices and approaches to implementation can have knock-on effects for the greater good, and beyond our initial target audiences. We can make our experiences more\u00a0responsive to people\u2019s needs, enhancing their usability and accessibility along the way.\n\nBeing responsibly responsive\n\nOf course, when we think about being more responsive, there\u2019s a fine line between creating useful functionality and becoming intrusive and overly complex. In the excellent Responsible Responsive Design, Scott Jehl states that:\n\n\nA responsible responsive design equally considers the following throughout a project:\n\nUsability: The way a website\u2019s user interface is presented to the user, and how that UI responds to browsing conditions and user interactions.\nAccess: The ability for users of all devices, browsers, and assistive technologies to access and understand a site\u2019s features and content.\nSustainability: The ability for the technology driving a site or application to work for devices that exist today and to continue to be usable and accessible to users, devices, and browsers in the future.\nPerformance: The speed at which a site\u2019s features and content are perceived to be delivered to the user and the efficiency with which they operate within the user interface.\n\n\n\nScott\u2019s book covers these ideas in a lot more detail than I\u2019ll be able to here (put it on your Christmas list if it\u2019s not there already), but for now let\u2019s think a bit more about our roles as digital creators\u00a0and the power this gives us.\n\nOur choices around technology and the decisions we have to make can be extremely wide-ranging. Solutions will vary hugely depending on the needs of each project, though we can further explore the concept of making our creations more responsive through the use of humble web technologies.\n\nThe power of the web\n\nWe all know that under the HTML5 umbrella are some great new capabilities, including a number of JavaScript APIs such as geolocation, web audio, the file API and many more. We often use these to enhance the functionality of our sites and apps, to add in new features, or to facilitate device-specific interactions.\n\nYou\u2019ll have seen articles with flashy titles such as \u201cTop 5 JavaScript APIs You\u2019ve Never Heard Of!\u201d, which you\u2019ll probably read, think \u201cThat\u2019s quite cool\u201d, yet never use in any real work.\n\nThere is great potential for technologies like these\u00a0to be misused, but there are also great prospects for them to be used well to enhance experiences. Let\u2019s have a look at a few\u00a0examples you may not have considered.\n\nOffline first\n\nWhen we make websites, many of us follow a process which involves user stories \u2013 standardised snippets of context explaining who needs what, and why.\n\n\u201cAs a student I want to pay online for my course so I don\u2019t have to visit the college in person.\u201d\n\n\u201cAs a retailer I want to generate unique product codes so I can manage my stock.\u201d\n\nWe very often focus heavily on what\u00a0needs doing, but may not consider carefully how it will be done. As in Scott\u2019s list, accessibility is extremely important, not only in terms of providing a great experience to users of assistive technologies, but also to make your creation more accessible in the general sense \u2013 including under different conditions.\n\nOffline first is yet another \u2018first\u2019 methodology (my personal favourite being \u2018tea first\u2019), which encourages us to develop so that connectivity\u00a0itself is an enhancement \u2013 letting\u00a0users continue with tasks even when they\u2019re offline. Despite the rapid growth in public Wi-Fi, if we consider data costs and connectivity in developing countries, our travel habits with planes, underground trains and roaming (or simply if you live in the UK\u2019s signal-barren East Anglian wilderness as I do), then you\u2019ll realise that connectivity isn\u2019t as ubiquitous as our internet-addled brains would make us believe. Take a scenario that I\u2019m sure we\u2019re all familiar with \u2013 the digital conference. Your venue may be in a city served by high-speed networks, but after overloading capacity with a full house of hashtag-hungry attendees, each carrying several devices, then everyone\u2019s likely to be offline after all. Wouldn\u2019t it be better if we could do something like this instead?\n\n\n\tSomeone visits our conference website.\n\tOn this initial run, some assets may be cached for future use: the conference schedule, the site\u2019s CSS, photos of the speakers.\n\tWhen the attendee revisits the site on the day, the page shell loads up from the cache.\n\tIf we have cached content (our session timetable, speaker photos or anything else), we can load it directly from the cache. We might then try to update this, or get some new content from the internet, but the conference attendee already has a base experience to use.\n\tIf we don\u2019t have something cached already, then we can try\u00a0grabbing it online.\n\tIf for any reason our requests for new content fail (we\u2019re offline), then we can display a pre-cached error message from the initial load, perhaps providing our users with alternative suggestions from what is\u00a0cached.\n\n\nThere are a number of ways we can make something like this, including using the application cache (AppCache) if you\u2019re that way inclined. However, you may want to look into service workers\u00a0instead. There are also some great resources on Offline First!\u00a0if you\u2019d like to find out more about this.\n\nBuilding in offline functionality isn\u2019t necessarily about starting offline first, and it\u2019s also perfectly possible to retrofit sites and apps to catch offline scenarios, but this kind of graceful degradation can end up being more complex than if we\u2019d considered it from the start. By treating connectivity as an enhancement, we can improve the experience and provide better performance than we can when waiting to counter failures. Our websites can respond to connectivity and usage scenarios, on top of adapting how we present our content. Thinking in this way can enhance each point in Scott\u2019s criteria.\n\nAs I mentioned, this isn\u2019t necessarily the kind of development choice that our clients will ask us for, but it\u2019s one we may decide is simply the right way to build based on our project, enhancing the experience we provide to people, and making it more responsive to their situation.\n\nEven more accessible\n\nWe\u2019ve looked at accessibility in terms of broadening when we can interact with a website, but what about how? Our user stories and personas are often of limited use. We refer in very general terms to students, retailers, and sometimes just users. What if we have a student whose needs are very different from another student? Can we make our sites even more usable and accessible through our development choices?\n\nAgain using JavaScript to illustrate this concept, we can do a lot more with the ways people interact with our websites, and with the feedback we provide, than simply accepting keyboard, mouse and touch inputs and displaying output on a screen.\n\nInput\n\nAmbient light detection is one of those features that looks great in simple demos, but which we struggle to put to practical use. It\u2019s not new \u2013 many satnav systems automatically change the contrast for driving at night or in tunnels, and our laptops may alter the screen brightness or keyboard backlighting to better adapt to our surroundings. Using web technologies we can adapt our presentation to be better suited to ambient light levels.\n\nIf our device has an appropriate light sensor and runs a browser that supports the API, we can grab the ambient light in units using ambient light events, in JavaScript. We may then change our presentation based on different bandings, perhaps like this:\n\nwindow.addEventListener('devicelight', function(e) {\n var lux = e.value;\n\n if (lux < 50) {\n //Change things for dim light\n }\n if (lux >= 50 && lux <= 10000) {\n //Change things for normal light\n }\n if (lux > 10000) {\n //Change things for bright light\n }\n});\n\nLive demo\u00a0(requires light sensor and supported browser).\n\nSoon we may also be able to do such detection through CSS, with light-level being cited in the Media Queries Level 4 specification. If that becomes the case, it\u2019ll probably look something like this:\n\n@media (light-level: dim) {\n /*Change things for dim light*/\n}\n\n@media (light-level: normal) {\n /*Change things for normal light*/\n}\n\n@media (light-level: washed) {\n /*Change things for bright light*/\n}\n\nWhile we may be quick to dismiss this kind of detection as being a gimmick, it\u2019s important to consider that apps such as Light Detector, listed on Apple\u2019s accessibility page, provide important context around exactly this functionality.\n\n\n\t\u201cIf you are blind, Light Detector helps you to be more independent in many daily activities. At home, point your iPhone towards the ceiling to understand where the light fixtures are and whether they are switched on. In a room, move the device along the wall to check if there is a window and where it is. You can find out whether the shades are drawn by moving the device up and down.\u201d\n\n\teverywaretechnologies.com/apps/lightdetector\n\n\nInput can be about so much more than what we enter through keyboards. Both an ever increasing amount of available sensors and more APIs being supported by the major browsers will allow us to cater for more scenarios and respond to them accordingly. This can be as complex or simple as you need; for instance, while x-webkit-speech has been deprecated, the web speech API is available for a number of browsers, and research into sign language detection is also being performed by organisations such as Microsoft.\n\nOutput\n\nWeb technologies give us some great enhancements around input, allowing us to adapt our experiences accordingly. They also provide us with some nice ways to provide feedback to users.\n\nWhen we play video games, many of our modern consoles come with the ability to have rumble effects on our controller pads. These are a great example of an enhancement, as they provide a level of feedback that is entirely optional, but which can give a great deal of extra information to the player in the right circumstances, and broaden the scope of our comprehension beyond what we\u2019re seeing and hearing.\n\nHaptic feedback is possible on the web as well. We could use this in any number of responsible applications, such as alerting a user to changes or using different patterns as a communication mechanism. If you find yourself in a pickle, here\u2019s how to print out SOS in Morse code through the vibration API. The following code indicates the length of vibration in milliseconds, interspersed by pauses in milliseconds.\n\nnavigator.vibrate([100, 300, 100, 300, 100, 300, 600, 300, 600, 300, 600, 300, 100, 300, 100, 300, 100]);\n\nLive demo\u00a0(requires supported browser)\n\nWith great power\u2026\n\nWhat you\u2019ve no doubt come to realise by now is that these are just more examples of progressive enhancement, whose inclusion will provide a better experience if the capabilities are available, but which we should not rely on. This idea isn\u2019t new, but the most important thing to remember, and what I would like you to take away from this article, is that it is up to us to decide to include these kind of approaches within our projects \u2013 if we don\u2019t root for them, they probably won\u2019t happen. This is where our professional responsibility comes in.\n\nWe won\u2019t necessarily be asked to implement solutions for the scenarios above, but they illustrate how we can help to push the boundaries of experiences. Maybe we\u2019ll have to switch our thinking about how we build, but we can create more usable products for a diverse range of people and usage scenarios through the choices we make around technology. Let\u2019s stop thinking simply in terms of features inside a narrow view of our target users, and work out how we can extend these to cater for a wider set of situations.\n\nWhen you plan your next digital project, consider the power of the web and the enhancements we can use, and try to make your projects even more responsive and responsible.", "year": "2014", "author": "Sally Jenkinson", "author_slug": "sallyjenkinson", "published": "2014-12-10T00:00:00+00:00", "url": "https://24ways.org/2014/making-sites-more-responsive-responsibly/", "topic": "code"} {"rowid": 31, "title": "Dealing with Emergencies in Git", "contents": "The stockings were hung by the chimney with care,\nIn hopes that version control soon would be there.\n\nThis summer I moved to the UK with my partner, and the onslaught of the Christmas holiday season began around the end of October (October!). It does mean that I\u2019ve had more than a fair amount of time to come up with horrible Git analogies for this article. Analogies, metaphors, and comparisons help the learner hook into existing mental models about how a system works. They only help, however, if the learner has enough familiarity with the topic at hand to make the connection between the old and new information.\n\nLet\u2019s start by painting an updated version of Clement Clarke Moore\u2019s Christmas living room. Empty stockings are hung up next to the fireplace, waiting for Saint Nicholas to come down the chimney and fill them with small treats. Holiday treats are scattered about. A bowl of mixed nuts, the holiday nutcracker, and a few clementines. A string of coloured lights winds its way up an evergreen.\n\nPerhaps a few of these images are familiar, or maybe they\u2019re just settings you\u2019ve seen in a movie. It doesn\u2019t really matter what the living room looks like though. The important thing is to ground yourself in your own experiences before tackling a new subject. Instead of trying to brute-force your way into new information, as an adult learner constantly ask yourself: \u2018What is this like? What does this remind me of? What do I already know that I can use to map out this new territory?\u2019 It\u2019s okay if the map isn\u2019t perfect. As you refine your understanding of a new topic, you\u2019ll outgrow the initial metaphors, analogies, and comparisons.\n\nWith apologies to Mr. Moore, let\u2019s give it a try.\n\nGetting Interrupted in Git\n\nWhen on the roof there arose such a clatter!\n\nYou\u2019re happily working on your software project when all of a sudden there are freaking reindeer on the roof! Whatever you\u2019ve been working on is going to need to wait while you investigate the commotion.\n\nIf you\u2019ve got even a little bit of experience working with Git, you know that you cannot simply change what you\u2019re working on in times of emergency. If you\u2019ve been doing work, you have a dirty working directory and you cannot change branches, or push your work to a remote repository while in this state.\n\nUp to this point, you\u2019ve probably dealt with emergencies by making a somewhat useless commit with a message something to the effect of \u2018switching branches for a sec\u2019. This isn\u2019t exactly helpful to future you, as commits should really contain whole ideas of completed work. If you get interrupted, especially if there are reindeer on the roof, the chances are very high that you weren\u2019t finished with what you were working on.\n\nYou don\u2019t need to make useless commits though. Instead, you can use the stash command. This command allows you to temporarily set aside all of your changes so that you can come back to them later. In this sense, stash is like setting your book down on the side table (or pushing the cat off your lap) so you can go investigate the noise on the roof. You aren\u2019t putting your book away though, you\u2019re just putting it down for a moment so you can come back and find it exactly the way it was when you put it down.\n\nLet\u2019s say you\u2019ve been working in the branch waiting-for-st-nicholas, and now you need to temporarily set aside your changes to see what the noise was on the roof:\n\n$ git stash\n\nAfter running this command, all uncommitted work will be temporarily removed from your working directory, and you will be returned to whatever state you were in the last time you committed your work.\n\nWith the book safely on the side table, and the cat safely off your lap, you are now free to investigate the noise on the roof. It turns out it\u2019s not reindeer after all, but just your boss who thought they\u2019d help out by writing some code on the project you\u2019ve been working on. Bless. Rolling your eyes, you agree to take a look and see what kind of mischief your boss has gotten themselves into this time.\n\nYou fetch an updated list of branches from the remote repository, locate the branch your boss had been working on, and checkout a local copy:\n\n$ git fetch\n$ git branch -r\n$ git checkout -b helpful-boss-branch origin/helpful-boss-branch\n\nYou are now in a local copy of the branch where you are free to look around, and figure out exactly what\u2019s going on.\n\nYou sigh audibly and say, \u2018Okay. Tell me what was happening when you first realised you\u2019d gotten into a mess\u2019 as you look through the log messages for the branch.\n\n$ git log --oneline\n$ git log\n\nBy using the log command you will be able to review the history of the branch and find out the moment right before your boss ended up stuck on your roof.\n\nYou may also want to compare the work your boss has done to the main branch for your project. For this article, we\u2019ll assume the main branch is named master.\n\n$ git diff master\n\nLooking through the commits, you may be able to see that things started out okay but then took a turn for the worse.\n\nChecking out a single commit\n\nUsing commands you\u2019re already familiar with, you can rewind through history and take a look at the state of the code at any moment in time by checking out a single commit, just like you would a branch.\n\nUsing the log command, locate the unique identifier (commit hash) of the commit you want to investigate. For example, let\u2019s say the unique identifier you want to checkout is 25f6d7f.\n\n$ git checkout 25f6d7f\n\nNote: checking out '25f6d7f'.\n\nYou are in 'detached HEAD' state. You can look around,\nmake experimental changes and commit them, and you can\ndiscard any commits you make in this state without\nimpacting any branches by performing another checkout.\n\nIf you want to create a new branch to retain commits you create, you may do so (now or later) by using @-b@ with the checkout command again. Example:\n\n$ git checkout -b new_branch_name\n\nHEAD is now at 25f6d7f... Removed first paragraph.\n\nThis is usually where people start to panic. Your boss screwed something up, and now your HEAD is detached. Under normal circumstances, these words would be a very good reason to panic.\n\nTake a deep breath. Nothing bad is going to happen. Being in a detached HEAD state just means you\u2019ve temporarily disconnected from a known chain of events. In other words, you\u2019re currently looking at the middle of a story (or branch) about what happened \u2013 and you\u2019re not at the endpoint for this particular story.\n\nGit allows you to view the history of your repository as a timeline (technically it\u2019s a directed acyclic graph). When you make commits which are not associated with a branch, they are essentially inaccessible once you return to a known branch. If you make commits while you\u2019re in a detached HEAD state, and then try to return to a known branch, Git will give you a warning and tell you how to save your work.\n\n$ git checkout master\n\nWarning: you are leaving 1 commit behind, not connected to\nany of your branches:\n\n 7a85788 Your witty holiday commit message.\n\nIf you want to keep them by creating a new branch, this may be a good time to do so with:\n\n$ git branch new_branch_name 7a85788\n\nSwitched to branch 'master'\nYour branch is up-to-date with 'origin/master'.\n\nSo, if you want to save the commits you\u2019ve made while in a detached HEAD state, you simply need to put them on a new branch.\n\n$ git branch saved-headless-commits 7a85788\n\nWith this trick under your belt, you can jingle around in history as much as you\u2019d like. It\u2019s not like sliding around on a timeline though. When you checkout a specific commit, you will only have access to the history from that point backwards in time. If you want to move forward in history, you\u2019ll need to move back to the branch tip by checking out the branch again.\n\n$ git checkout helpful-boss-branch\n\nYou\u2019re now back to the present. Your HEAD is now pointing to the endpoint of a known branch, and so it is no longer detached. Any changes you made while on your adventure are safely stored in a new branch, assuming you\u2019ve followed the instructions Git gave you. That wasn\u2019t so scary after all, now, was it?\n\nBack to our reindeer problem.\n\nIf your boss is anything like the bosses I\u2019ve worked with, chances are very good that at least some of their work is worth salvaging. Depending on how your repository is structured, you\u2019ll want to capture the good work using one of several different methods.\n\nBack in the living room, we\u2019ll use our bowl of nuts to illustrate how you can rescue a tiny bit of work.\n\nSaving just one commit\n\nAbout that bowl of nuts. If you\u2019re like me, you probably had some favourite kinds of nuts from an assorted collection. Walnuts were generally the most satisfying to crack open. So, instead of taking the entire bowl of nuts and dumping it into a stocking (merging the stocking and the bowl of nuts), we\u2019re just going to pick out one nut from the bowl. In Git terms, we\u2019re going to cherry-pick a commit and save it to another branch.\n\nFirst, checkout the main branch for your development work. From this branch, create a new branch where you can copy the changes into.\n\n$ git checkout master\n$ git checkout -b rescue-the-boss\n\nFrom your boss\u2019s branch, helpful-boss-branch locate the commit you want to keep.\n\n$ git log --oneline helpful-boss-branch\n\nLet\u2019s say the commit ID you want to keep is e08740b. From your rescue branch, use the command cherry-pick to copy the changes into your current branch.\n\n$ git cherry-pick e08740b\n\nIf you review the history of your current branch again, you will see you now also have the changes made in the commit in your boss\u2019s branch.\n\nAt this point you might need to make a few additional fixes to help your boss out. (You\u2019re angling for a bonus out of all this. Go the extra mile.) Once you\u2019ve made your additional changes, you\u2019ll need to add that work to the branch as well.\n\n$ git add [filename(s)]\n$ git commit -m \"Building on boss's work to improve feature X.\"\n\nGo ahead and test everything, and make sure it\u2019s perfect. You don\u2019t want to introduce your own mistakes during the rescue mission!\n\nUploading the fixed branch\n\nThe next step is to upload the new branch to the remote repository so that your boss can download it and give you a huge bonus for helping you fix their branch.\n\n$ git push -u origin rescue-the-boss\n\nCleaning up and getting back to work\n\nWith your boss rescued, and your bonus secured, you can now delete the local temporary branches.\n\n$ git branch --delete rescue-the-boss\n$ git branch --delete helpful-boss-branch\n\nAnd settle back into your chair to wait for Saint Nicholas with your book, your branch, and possibly your cat.\n\n$ git checkout waiting-for-st-nicholas\n$ git stash pop\n\nYour working directory has been returned to exactly the same state you were in at the beginning of the article.\n\nHaving fun with analogies\n\nI\u2019ve had a bit of fun with analogies in this article. But sometimes those little twists on ideas can really help someone pick up a new idea (git stash: it\u2019s like when Christmas comes around and everyone throws their fashion sense out the window and puts on a reindeer sweater for the holiday party; or git bisect: it\u2019s like trying to find that one broken light on the string of Christmas lights). It doesn\u2019t matter if the analogy isn\u2019t perfect. It\u2019s just a way to give someone a temporary hook into a concept in a way that makes the concept accessible while the learner becomes comfortable with it. As the learner\u2019s comfort increases, the analogies can drop away, making room for the technically correct definition of how something works.\n\nOr, if you\u2019re like me, you can choose to never grow old and just keep mucking about in the analogies. I\u2019d argue it\u2019s a lot more fun to play with a string of Christmas lights and some holiday cheer than a directed acyclic graph anyway.", "year": "2014", "author": "Emma Jane Westby", "author_slug": "emmajanewestby", "published": "2014-12-02T00:00:00+00:00", "url": "https://24ways.org/2014/dealing-with-emergencies-in-git/", "topic": "code"} {"rowid": 36, "title": "Naming Things", "contents": "There are only two hard things in computer science: cache invalidation and naming things.\nPhil Karlton\n\n\nBeing a professional web developer means taking responsibility for the code you write and ensuring it is comprehensible to others. Having a documented code style is one means of achieving this, although the size and type of project you\u2019re working on will dictate the conventions used and how rigorously they are enforced.\n\nWorking in-house may mean working with multiple developers, perhaps in distributed teams, who are all committing changes \u2013 possibly to a significant codebase \u2013 at the same time. Left unchecked, this codebase can become unwieldy. Coding conventions ensure everyone can contribute, and help build a product that works as a coherent whole.\n\nEven on smaller projects, perhaps working within an agency or by yourself, at some point the resulting product will need to be handed over to a third party. It\u2019s sensible, therefore, to ensure that your code can be understood by those who\u2019ll eventually take ownership of it.\n\nPut simply, code is read more often than it is written or changed. A consistent and predictable naming scheme can make code easier for other developers to understand, improve and maintain, presumably leaving them free to worry about cache invalidation.\n\nLet\u2019s talk about semantics\n\nNames not only allow us to identify objects, but they can also help us describe the objects being identified.\n\nSemantics (the meaning or interpretation of words) is the cornerstone of standards-based web development. Using appropriate HTML elements allows us to create documents and applications that have implicit structural meaning. Thanks to HTML5, the vocabulary we can choose from has grown even larger.\n\nHTML elements provide one level of meaning: a widely accepted description of a document\u2019s underlying structure. It\u2019s only with the mutual agreement of browser vendors and developers that

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

    \n
  • Rudolph
  • \n
  • Dasher
  • \n
  • Dancer
  • \n
  • Prancer
  • \n
  • Vixen
  • \n
  • Comet
  • \n
  • Cupid
  • \n
  • Dunder
  • \n
  • Blixem
  • \n
\n\nI know that:\n\n\n\t.sleigh is a containing block or component.\n\t.sleigh__reindeer is used only as a descendent element of .sleigh.\n\t.sleigh__reindeer\u2013\u2013famous is used only as a modifier of .sleigh__reindeer.\n\n\nWith this naming scheme in place, I know which styles relate to a particular component, and which are shared. Beyond reducing specificity-related head-scratching, this approach has given me a framework within which I can consistently label items, and has sped up my workflow considerably.\n\nEach of these methodologies shows that any robust CSS naming convention will have clear rules around case (lowercase, camelCase, PascalCase) and the use of special (allowed) characters like hyphens and underscores.\n\nWhat makes for a good name?\n\nRegardless of higher-level conventions, there\u2019s no getting away from the fact that, at some point, we\u2019re still going to have to name things. Recognising that classes should be named with other developers in mind, what makes for a good name?\n\nUnderstandable\n\nThe most important aspect is for a name to be understandable. Words used in your project may come from a variety of sources: some may be widely understood, and others only be recognised by people working within a particular environment.\n\n\n\tCulture\nMost words you\u2019ll choose will have common currency outside the world of web development, although they may have a particular interpretation among developers (think menu, list, input). However, words may have a narrower cultural significance; for example, in Germany and other German-speaking countries, impressum is the term used for legally mandated statements of ownership.\n\tIndustry\nIndustries often use specific terms to describe common business practices and concepts. Publishing has a number of these (headline, standfirst, masthead, colophon\u2026) all have well understood meanings \u2013 and not all of them are relevant to online usage.\n\tOrganisation\nCompanies may have internal names (or nicknames) for their products and services. The Guardian is rife with such names: bisons (and buffalos), pixies (and super-pixies), bentos (and mini-bentos)\u2026 all of which mean something very different outside the organisation. Although such names can be useful inside smaller teams, in larger organisations they can become a barrier to entry, a sort of secret code used among employees who have been around long enough to know what they mean.\n\tProduct\nYour team will undoubtedly have created names for specific features or interface components used in your product. For example, at Clearleft we coined the term gravigation for a navigation bar that was pinned to the bottom of the viewport. Elements of a visual design language may have names, too. Transport for London\u2019s bar and circle logo is known internally as the roundel, while Nike\u2019s logo is called the swoosh. Branding agencies often christen colours within a brand palette, too, either to evoke aspects of the identity or to indicate intended usage.\n\n\nOnce you recognise the origin of the words you use, you\u2019ll be better able to judge their appropriateness. Using Latin words for class names may satisfy a need to use semantic-sounding terms but, unless you work in a company whose employees have a basic grasp of Latin, a degree of translation will be required. Military ranks might be a clever way of declaring sizes without implying actual values, but I\u2019d venture most people outside the armed forces don\u2019t know how they\u2019re ordered.\n\nObvious\n\nQuite often, the first name that comes into your head will be the best option. Names that obliquely reference the function of a class (e.g. receptacle instead of container, kevlar instead of no-bullets) only serve to add an additional layer of abstraction. Don\u2019t overthink it!\n\nOne way of knowing if the names you use are well understood is to look at what similar concepts are called in existing vocabularies. schema.org, Dublin Core and the BBC\u2019s ontologies are all useful sources for object names.\n\nFunctional\n\nWhile we\u2019ve learned to avoid using presentational classes, there remains a tension between naming things based on their content, and naming them for their intended presentation or behaviour (which may change at different breakpoints). Rather than think about a component\u2019s appearance or behaviour, instead look to its function, its purpose. To clarify, ask what a component\u2019s function is, and not how the component functions.\n\nFor example, the Guardian\u2019s internal content system uses the following names for different types of image placement: supporting, showcase and thumbnail, with inline being the default. These options make no promise of the resulting position on a webpage (or smartphone app, or television screen\u2026), but do suggest intended use, and therefore imply the likely presentation.\n\nConsistent\n\nBeing consistent in your approach to names will allow for easier naming of successive components, and extending the vocabulary when necessary. For example, a predictably named hierarchy might use names like primary and secondary. Should another level need to be added, tertiary is clearly be preferred over third.\n\nAppropriate\n\nYour project will feature a mix of style rules. Some will perform utility functions (clearing floats, removing bullets from a list, reseting margins), while others will perform specific functions used only once or twice in a project. Names should reflect this. For commonly used classes, be generic; for unique components be more specific.\n\nIt\u2019s also worth remembering that you can use multiple classes on an element, so combining both generic and specific can give you a powerful modular design system:\n\n\n\tGeneric: list\n\tSpecific: naughty-children\n\tCombined: naughty-children list\n\n\nIf following the BEM methodology, you might use the following classes:\n\n\n\tGeneric: list\n\tSpecific: list\u2013\u2013nice-children\n\tCombined: list list\u2013\u2013nice-children\n\n\nExtensible\n\nGood naming schemes can be extended. One way of achieving this is to use namespaces, which are basically a way of grouping related names under a higher-level term.\n\nMicroformats are a good example of a well-designed naming scheme, with many of its vocabularies taking property names from existing and related specifications (e.g. hCard is a 1:1 representation of vCard). Microformats 2 goes one step further by grouping properties under several namespaces:\n\n\n\th-* for root class names (e.g. h-card)\n\tp-* for simple (text) properties (e.g. p-name)\n\tu-* for URL properties (e.g. u-photo)\n\tdt-* for date/time properties (e.g. dt-bday)\n\te-* for embedded markup properties (e.g. e-note)\n\n\nThe inclusion of namespaces is a massive improvement over the earlier specification, but the downside is that microformats now occupy five separate namespaces. This might be problematic if you are using u-* for your utility classes. While nothing will break, your naming system won\u2019t be as robust, so plan accordingly.\n\n(Note: Microformats perform a very specific function, separate from any presentational concerns. It\u2019s therefore considered best practice to not use microformat classes as styling hooks, but instead use additional classes that relate to the function of the component and adhere to your own naming conventions.)\n\nShort\n\nNames should be as long as required, but no longer. When looking for words to describe a particular function, I try to look for single words where possible. Avoid abbreviations unless they are understood within the contexts described above. rrp is fine if labelling a recommended retail price in an online shop, but not very helpful if used to mean ragged-right paragraph, for example.\n\nFun!\n\nFinally, names can be an opportunity to have some fun! Names can give character to a project, be it by providing an outlet for in-jokes or adding little easter eggs for those inclined to look.\n\nThe copyright statement on Apple\u2019s website has long been named sosumi, a word that has a nice little history inside Apple. Until recently, the hamburger menu icon on the Guardian website was labelled honest-burger, after the developer\u2019s favourite burger restaurant.\n\nA few thoughts on preprocessors\n\nCSS preprocessors have solved a lot of problems, but they have an unfortunate downside: they require you to name yet more things! Whereas we needed to worry only about style rules, now we need names for variables, mixins, functions\u2026 oh my!\n\nA second article could be written about naming these, so for now I\u2019ll offer just a few thoughts. The first is to note that preprocessors make it easier to change things, as they allow for DRYer code. So while the names of variables are important (and the advice in this article still very much applies), you can afford to relax a little.\n\nLooking to name colour variables? If possible, find out if colours have been assigned names in a brand palette. If not, use obvious names (based on appearance or function, depending on your preference) and adapt as the palette grows. If it becomes difficult to name colours that are too similar, I\u2019d venture that the problem lies with the design rather than the naming scheme.\n\nThe same is true for responsive breakpoints. Preprocessors allow you to move awkward naming conventions out of the markup and into the CSS. Although terms like mobile, tablet and desktop are not desirable given the need to think about device-agnostic design, if these terms are widely understood within a product team and among stakeholders, using them will ensure everyone is using the same language (they can always be changed later).\n\nIt still feels like we\u2019re at the very beginning of understanding how preprocessors fit into a development workflow, if at all! I suspect over the next few years, best practices will emerge for all of these considerations. In the meantime, use your brain!\n\n\n\nEven with sensible rules and conventions in place, naming things can remain difficult, but hopefully I\u2019ve made this exercise a little less painful. Christmas is a time of giving, so to the developer reading your code in a year\u2019s time, why not make your gift one of clearer class names.", "year": "2014", "author": "Paul Lloyd", "author_slug": "paulrobertlloyd", "published": "2014-12-21T00:00:00+00:00", "url": "https://24ways.org/2014/naming-things/", "topic": "code"} {"rowid": 37, "title": "JavaScript Modules the ES6 Way", "contents": "JavaScript admittedly has plenty of flaws, but one of the largest and most prominent is the lack of a module system: a way to split up your application into a series of smaller files that can depend on each other to function correctly. \n\nThis is something nearly all other languages come with out of the box, whether it be Ruby\u2019s require, Python\u2019s import, or any other language you\u2019re familiar with. Even CSS has @import! JavaScript has nothing of that sort, and this has caused problems for application developers as they go from working with small websites to full client-side applications. Let\u2019s be clear: it doesn\u2019t mean the new module system in the upcoming version of JavaScript won\u2019t be useful to you if you\u2019re building smaller websites rather than the next Instagram.\n\nThankfully, the lack of a module system will soon be a problem of the past. The next version of JavaScript, ECMAScript 6, will bring with it a full-featured module and dependency management solution for JavaScript. The bad news is that it won\u2019t be landing in browsers for a while yet \u2013 but the good news is that the specification for the module system and how it will look has been finalised. The even better news is that there are tools available to get it all working in browsers today without too much hassle. In this post I\u2019d like to give you the gift of JS modules and show you the syntax, and how to use them in browsers today. It\u2019s much simpler than you might think.\n\nWhat is ES6?\n\nECMAScript is a scripting language that is standardised by a company called Ecma International. JavaScript is an implementation of ECMAScript. ECMAScript 6 is simply the next version of the ECMAScript standard and, hence, the next version of JavaScript. The spec aims to be fully comfirmed and complete by the end of 2014, with a target initial release date of June 2015. It\u2019s impossible to know when we will have full feature support across the most popular browsers, but already some ES6 features are landing in the latest builds of Chrome and Firefox. You shouldn\u2019t expect to be able to use the new features across browsers without some form of additional tooling or library for a while yet.\n\nThe ES6 module spec\n\nThe ES6 module spec was fully confirmed in July 2014, so all the syntax I will show you in this article is not expected to change. I\u2019ll first show you the syntax and the new APIs being added to the language, and then look at how to use them today. There are two parts to the new module system. The first is the syntax for declaring modules and dependencies in your JS files, and the second is a programmatic API for loading in modules manually. The first is what most people are expected to use most of the time, so it\u2019s what I\u2019ll focus on more.\n\nModule syntax\n\nThe key thing to understand here is that modules have two key components. First, they have dependencies. These are things that the module you are writing depends on to function correctly. For example, if you were building a carousel module that used jQuery, you would say that jQuery is a dependency of your carousel. You import these dependencies into your module, and we\u2019ll see how to do that in a minute. Second, modules have exports. These are the functions or variables that your module exposes publicly to anything that imports it. Using jQuery as the example again, you could say that jQuery exports the $ function. Modules that depend on and hence import jQuery get access to the $ function, because jQuery exports it.\n\nAnother important thing to note is that when I discuss a module, all I really mean is a JavaScript file. There\u2019s no extra syntax to use other than the new ES6 syntax. Once ES6 lands, modules and files will be analogous.\n\nNamed exports\n\nModules can export multiple objects, which can be either plain old variables or JavaScript functions. You denote something to be exported with the export keyword:\n\nexport function double(x) {\n return x + x;\n};\n\n\nYou can also store something in a variable then export it. If you do that, you have to wrap the variable in a set of curly braces.\n\nvar double = function(x) {\n return x + x;\n}\n\nexport { double };\n\nA module can then import the double function like so:\n\nimport { double } from 'mymodule';\ndouble(2); // 4\n\nAgain, curly braces are required around the variable you would like to import. It\u2019s also important to note that from 'mymodule' will look for a file called mymodule.js in the same directory as the file you are requesting the import from. There is no need to add the .js extension.\n\nThe reason for those extra braces is that this syntax lets you export multiple variables:\n\nvar double = function(x) {\n return x + x;\n}\n\nvar square = function(x) {\n return x * x;\n}\n\nexport { double, square }\n\nI personally prefer this syntax over the export function \u2026, but only because it makes it much clearer to me what the module exports. Typically I will have my export {\u2026} line at the bottom of the file, which means I can quickly look in one place to determine what the module is exporting.\n\nA file importing both double and square can do so in just the way you\u2019d expect:\n\nimport { double, square } from 'mymodule';\ndouble(2); // 4\nsquare(3); // 9\n\nWith this approach you can\u2019t easily import an entire module and all its methods. This is by design \u2013 it\u2019s much better and you\u2019re encouraged to import just the functions you need to use.\n\nDefault exports\n\nAlong with named exports, the system also lets a module have a default export. This is useful when you are working with a large library such as jQuery, Underscore, Backbone and others, and just want to import the entire library. A module can define its default export (it can only ever have one default export) like so:\n\nexport default function(x) {\n return x + x;\n}\n\nAnd that can be imported:\n\nimport double from 'mymodule';\ndouble(2); // 4\n\n\nThis time you do not use the curly braces around the name of the object you are importing. Also notice how you can name the import whatever you\u2019d like. Default exports are not named, so you can import them as anything you like:\n\nimport christmas from 'mymodule';\nchristmas(2); // 4\n\nThe above is entirely valid.\n\nAlthough it\u2019s not something that is used too often, a module can have both named exports and a default export, if you wish.\n\nOne of the design goals of the ES6 modules spec was to favour default exports. There are many reasons behind this, and there is a very detailed discussion on the ES Discuss site about it. That said, if you find yourself preferring named exports, that\u2019s fine, and you shouldn\u2019t change that to meet the preferences of those designing the spec.\n\nProgrammatic API\n\nAlong with the syntax above, there is also a new API being added to the language so you can programmatically import modules. It\u2019s pretty rare you would use this, but one obvious example is loading a module conditionally based on some variable or property. You could easily import a polyfill, for example, if the user\u2019s browser didn\u2019t support a feature your app relied on. An example of doing this is:\n\nif(someFeatureNotSupported) {\n System.import('my-polyfill').then(function(myPolyFill) {\n // use the module from here\n });\n}\n\nSystem.import will return a promise, which, if you\u2019re not familiar, you can read about in this excellent article on HTMl5 Rocks by Jake Archibald. A promise basically lets you attach callback functions that are run when the asynchronous operation (in this case, System.import), is complete.\n\nThis programmatic API opens up a lot of possibilities and will also provide hooks to allow you to register callbacks that will run at certain points in the lifetime of a module. Those hooks and that syntax are slightly less set in stone, but when they are confirmed they will provide really useful functionality. For example, you could write code that would run every module that you import through something like JSHint before importing it. In development that would provide you with an easy way to keep your code quality high without having to run a command line watch task.\n\nHow to use it today\n\nIt\u2019s all well and good having this new syntax, but right now it won\u2019t work in any browser \u2013 and it\u2019s not likely to for a long time. Maybe in next year\u2019s 24 ways there will be an article on how you can use ES6 modules with no extra work in the browser, but for now we\u2019re stuck with a bit of extra work.\n\nES6 module transpiler\n\nOne solution is to use the ES6 module transpiler, a compiler that lets you write your JavaScript using the ES6 module syntax (actually a subset of it \u2013 not quite everything is supported, but the main features are) and have it compiled into either CommonJS-style code (CommonJS is the module specification that NodeJS and Browserify use), or into AMD-style code (the spec RequireJS uses). There are also plugins for all the popular build tools, including Grunt and Gulp.\n\nThe advantage of using this transpiler is that if you are already using a tool like RequireJS or Browserify, you can drop the transpiler in, start writing in ES6 and not worry about any additional work to make the code work in the browser, because you should already have that set up already. If you don\u2019t have any system in place for handling modules in the browser, using the transpiler doesn\u2019t really make sense. Remember, all this does is convert ES6 module code into CommonJS- or AMD-compliant JavaScript. It doesn\u2019t do anything to help you get that code running in the browser, but if you have that part sorted it\u2019s a really nice addition to your workflow. If you would like a tutorial on how to do this, I wrote a post back in June 2014 on using ES6 with the ES6 module transpiler.\n\nSystemJS\n\nAnother solution is SystemJS. It\u2019s the best solution in my opinion, particularly if you are starting a new project from scratch, or want to use ES6 modules on a project where you have no current module system in place. SystemJS is a spec-compliant universal module loader: it loads ES6 modules, AMD modules, CommonJS modules, as well as modules that just add a variable to the global scope (window, in the browser).\n\nTo load in ES6 files, SystemJS also depends on two other libraries: the ES6 module loader polyfill; and Traceur. Traceur is best accessed through the bower-traceur package, as the main repository doesn\u2019t have an easy to find downloadable version. The ES6 module load polyfill implements System.import, and lets you load in files using it. Traceur is an ES6-to-ES5 module loader. It takes code written in ES6, the newest version of JavaScript, and transpiles it into ES5, the version of JavaScript widely implemented in browsers. The advantage of this is that you can play with the new features of the language today, even though they are not supported in browsers. The drawback is that you have to run all your files through Traceur every time you save them, but this is easily automated. Additionally, if you use SystemJS, the Traceur compilation is done automatically for you.\n\nAll you need to do to get SystemJS running is to add a \n\nWhen you load the page, app.js will be asynchronously loaded. Within app.js, you can now use ES6 modules. SystemJS will detect that the file is an ES6 file, automatically load Traceur, and compile the file into ES5 so that it works in the browser. It does all this dynamically in the browser, but there are tools to bundle your application in production, so it doesn\u2019t make a lot of requests on the live site. In development though, it makes for a really nice workflow.\n\nWhen working with SystemJS and modules in general, the best approach is to have a main module (in our case app.js) that is the main entry point for your application. app.js should then be responsible for loading all your application\u2019s modules. This forces you to keep your application organised by only loading one file initially, and having the rest dealt with by that file.\n\nSystemJS also provides a workflow for bundling your application together into one file.\n\nConclusion\n\nES6 modules may be at least six months to a year away (if not more) but that doesn\u2019t mean they can\u2019t be used today. Although there is an overhead to using them now \u2013 with the work required to set up SystemJS, the module transpiler, or another solution \u2013 that doesn\u2019t mean it\u2019s not worthwhile. Using any module system in the browser, whether that be RequireJS, Browserify or another alternative, requires extra tooling and libraries to support it, and I would argue that the effort to set up SystemJS is no greater than that required to configure any other tool. It also comes with the extra benefit that when the syntax is supported in browsers, you get a free upgrade. You\u2019ll be able to remove SystemJS and have everything continue to work, backed by the native browser solution.\n\nIf you are starting a new project, I would strongly advocate using ES6 modules. It is a syntax and specification that is not going away at all, and will soon be supported in browsers. Investing time in learning it now will pay off hugely further down the road.\n\nFurther reading\n\nIf you\u2019d like to delve further into ES6 modules (or ES6 generally) and using them today, I recommend the following resources:\n\n\n\tECMAScript 6 modules: the final syntax by Axel Rauschmayer\n\tPractical Workflows for ES6 Modules by Guy Bedford\n\tECMAScript 6 resources for the curious JavaScripter by Addy Osmani\n\tTracking ES6 support by Addy Osmani\n\tES6 Tools List by Addy Osmani\n\tUsing Grunt and the ES6 Module Transpiler by Thomas Boyt\n\tJavaScript Modules and Dependencies with jspm by myself\n\tUsing ES6 Modules Today by Guy Bedford", "year": "2014", "author": "Jack Franklin", "author_slug": "jackfranklin", "published": "2014-12-03T00:00:00+00:00", "url": "https://24ways.org/2014/javascript-modules-the-es6-way/", "topic": "code"} {"rowid": 38, "title": "Websites of Christmas Past, Present and Future", "contents": "The websites of Christmas past\n\nThe first website was created at CERN. It was launched on 20 December 1990 (just in time for Christmas!), and it still works today, after twenty-four years. Isn\u2019t that incredible?!\n\nWhy does this website still work after all this time? I can think of a few reasons.\n\nFirst, the authors of this document chose HTML. Of course they couldn\u2019t have known back then the extent to which we would be creating documents in HTML, but HTML always had a lot going for it. It\u2019s built on top of plain text, which means it can be opened in any text editor, and it\u2019s pretty readable, even without any parsing.\n\nDespite the fact that HTML has changed quite a lot over the past twenty-four years, extensions to the specification have always been implemented in a backwards-compatible manner. Reading through the 1992 W3C document HTML Tags, you\u2019ll see just how it has evolved. We still have h1 \u2013 h6 elements, but I\u2019d not heard of the element before. Despite being deprecated since HTML2, it still works in several browsers. You can see it in action on my website.\n\nAs well as being written in HTML, there is no run-time compilation of code; the first website simply consists of HTML files transmitted over the web. Due to its lack of complexity, it stood a good chance of surviving in the turbulent World Wide Web.\n\nThat\u2019s all well and good for a simple, static website. But websites created today are increasingly interactive. Many require a login and provide experiences that are tailored to the individual user. This type of dynamic website requires code to be executed somewhere.\n\nTraditionally, dynamic websites would execute such code on the server, and transmit a simple HTML file to the user. As far as the browser was concerned, this wasn\u2019t much different from the first website, as the additional complexity all happened before the document was sent to the browser.\n\nDoing it all in the browser\n\nIn 2003, the first single page interface was created at slashdotslash.com. A single page interface or single page app is a website where the page is created in the browser via JavaScript. The benefit of this technique is that, after the initial page load, subsequent interactions can happen instantly, or very quickly, as they all happen in the browser.\n\nWhen software runs on the client rather than the server, it is often referred to as a fat client. This means that the bulk of the processing happens on the client rather than the server (which can now be thin).\n\nA fat client is preferred over a thin client because:\n\n\n\tIt takes some processing requirements away from the server, thereby reducing the cost of servers (a thin server requires cheaper, or fewer servers).\n\tThey can often continue working offline, provided no server communication is required to complete tasks after initial load.\n\tThe latency of internet communications is bypassed after initial load, as interactions can appear near instantaneous when compared to waiting for a response from the server.\n\n\nBut there are also some big downsides, and these are often overlooked:\n\n\n\tThey can\u2019t work without JavaScript. Obviously JavaScript is a requirement for any client-side code execution. And as the UK Government Digital Service discovered, 1.1% of their visitors did not receive JavaScript enhancements. Of that 1.1%, 81% had JavaScript enabled, but their browsers failed to execute it (possibly due to dropping the internet connection). If you care about 1.1% of your visitors, you should care about the non-JavaScript experience for your website.\n\tThe browser needs to do all the processing. This means that the hardware it runs on needs to be fast. It also means that we require all clients to have largely the same capabilities and browser APIs.\n\tThe initial payload is often much larger, and nothing will be rendered for the user until this payload has been fully downloaded and executed. If the connection drops at any point, or the code fails to execute owing to a bug, we\u2019re left with the non-JavaScript experience.\n\tThey are not easily indexed as every crawler now needs to run JavaScript just to receive the content of the website.\n\n\nThese are not merely edge case issues to shirk off. The first three issues will affect some of your visitors; the fourth affects everyone, including you.\n\nWhat problem are we trying to solve?\n\nSo what can be done to address these issues? Whereas fat clients solve some inherent issues with the web, they seem to create as many problems. When attempting to resolve any issue, it\u2019s always good to try to uncover the original problem and work forwards from there. One of the best ways to frame a problem is as a user story. A user story considers the who, what and why of a need. Here\u2019s a template:\n\n\n\tAs a {who} I want {what} so that {why}\n\n\nI haven\u2019t got a specific project in mind, so let\u2019s refer to the who as user. Here\u2019s one that could explain the use of thick clients.\n\n\n\tAs a user I want the site to respond to my actions quickly so that I get immediate feedback when I do something.\n\n\nThis user story could probably apply to a great number of websites, but so could this:\n\n\n\tAs a user I want to get to the content quickly, so that I don\u2019t have to wait too long to find out what the site is all about or get the content I need.\n\n\nA better solution\n\nHow can we balance both these user needs? How can we have a website that loads fast, and also reacts fast? The solution is to have a thick server, that serves the complete document, and then a thick client, that manages subsequent actions and replaces parts of the page. What we\u2019re talking about here is simply progressive enhancement, but from the user\u2019s perspective.\n\nThe initial payload contains the entire document. At this point, all interactions would happen in a traditional way using links or form elements. Then, once we\u2019ve downloaded the JavaScript (asynchronously, after load) we can enhance the experience with JavaScript interactions. If for whatever reason our JavaScript fails to download or execute, it\u2019s no biggie \u2013 we\u2019ve already got a fully functioning website. If an API that we need isn\u2019t available in this browser, it\u2019s not a problem. We just fall back to the basic experience.\n\nThis second point, of having some minimum requirement for an enhanced experience, is often referred to as cutting the mustard, first used in this sense by the BBC News team. Essentially it\u2019s an if statement like this:\n\nif('querySelector' in document\n && 'localStorage' in window\n && 'addEventListener' in window) {\n // bootstrap the JavaScript application\n }\n\nThis code states that the browser must support the following methods before downloading and executing the JavaScript:\n\n\n\tdocument.querySelector (can it find elements by CSS selectors)\n\twindow.localStorage (can it store strings)\n\twindow.addEventListener (can it bind to events in a standards-compliant way)\n\n\nThese three properties are what the BBC News team decided to test for, as they are present in their website\u2019s JavaScript. Each website will have its own requirements. The last method, window.addEventListener is in interesting one. Although it\u2019s simple to bind to events on IE8 and earlier, these browsers have very inconsistent support for standards. Making any JavaScript-heavy website work on IE8 and earlier is a painful exercise, and comes at a cost to all users on other browsers, as they\u2019ll download unnecessary code to patch support for IE.\n\n JavaScript API support by browser.\n\nI discovered that IE8 supports 12% of the current JavaScript APIs, while IE9 supports 16%, and IE10 51%. It seems, then, that IE10 could be the earliest version of IE that I\u2019d like to develop JavaScript for. That doesn\u2019t mean that users on browsers earlier than 10 can\u2019t use the website. On the contrary, they get the core experience, and because it\u2019s just HTML and CSS, it\u2019s much more likely to be bug-free, and could even provide a better experience than trying to run JavaScript in their browser. They receive the thin client experience.\n\nBy reducing the number of platforms that our enhanced JavaScript version supports, we can better focus our efforts on those platforms and offer an even greater experience to those users. But we can only do that if we use progressive enhancement. Otherwise our website would be completely broken for all other users.\n\nSo what we have is a thick server, capable of serving the entire website to our users, complete with all core functionality needed for our users to complete their tasks; and we have a thick client on supported browsers, which can bring an even greater experience to those users.\n\nThis is all transparent to users. They may notice that the website seems snappier on the new iPhone they received for Christmas than on the Windows 7 machine they got five years ago, but then they probably expected it to be faster on their iPhone anyway.\n\nIsn\u2019t this just more work?\n\nIt\u2019s true that making a thick server and a thick client is more work than just making one or the other. But there are some big advantages:\n\n\n\tThe website works for everyone.\n\tYou can decide when users get the enhanced experience.\n\tYou can enhance features in an iterative (or agile) manner.\n\tWhen the website breaks, it doesn\u2019t break down.\n\tThe more you practise this approach, the quicker you will become.\n\n\nThe websites of Christmas present\n\nThe best way to discover websites using this technique of progressive enhancement is to disable JavaScript and see if the website breaks. I use the Web Developer extension, which is available for Chrome and Firefox. It lets me quickly disable JavaScript.\n\n Web Developer extension.\n\n24 ways works with and without JavaScript. Try using the menu icon to view the navigation. Without JavaScript, it\u2019s a jump link to the bottom of the page, but with JavaScript, the menu slides in from the right.\n\n 24 ways navigation with JavaScript disabled.\n\n 24 ways navigation with working JavaScript.\n\nGoogle search will also work without JavaScript. You won\u2019t get instant search results or any prerendering, because those are enhancements.\n\nFor a more app-like example, try using Twitter. Without JavaScript, it still works, and looks nearly identical. But when you load JavaScript, links open in modal windows and all pages are navigated much quicker, as only the content that has changed is loaded. You can read about how they achieved this in Twitter\u2019s blog posts Improving performance on twitter.com and Implementing pushState for twitter.com.\n\nUnfortunately Facebook doesn\u2019t use progressive enhancement, which not only means that the website doesn\u2019t work without JavaScript, but it takes longer to load. I tested it on WebPagetest and if you compare the load times of Twitter and Facebook, you\u2019ll notice that, despite putting similar content on the page, Facebook takes two and a half times longer to render the core content on the page.\n\n Facebook takes two and a half times longer to load than Twitter.\n\nWebsites of Christmas yet to come\n\nEvery project is different, and making a website that enjoys a long life, or serves a larger number of users may or may not be a high priority. But I hope I\u2019ve convinced you that it certainly is possible to look to the past and future simultaneously, and that there can be significant advantages to doing so.", "year": "2014", "author": "Josh Emerson", "author_slug": "joshemerson", "published": "2014-12-08T00:00:00+00:00", "url": "https://24ways.org/2014/websites-of-christmas-past-present-and-future/", "topic": "code"} {"rowid": 42, "title": "An Overview of SVG Sprite Creation Techniques", "contents": "SVG can be used as an icon system to replace icon fonts. The reasons why SVG makes for a superior icon system are numerous, but we won\u2019t be going over them in this article. If you don\u2019t use SVG icons and are interested in knowing why you may want to use them, I recommend you check out \u201cInline SVG vs Icon Fonts\u201d by Chris Coyier \u2013 it covers the most important aspects of both systems and compares them with each other to help you make a better decision about which system to choose.\n\nOnce you\u2019ve made the decision to use SVG instead of icon fonts, you\u2019ll need to think of the best way to optimise the delivery of your icons, and ways to make the creation and use of icons faster.\n\nJust like bitmaps, we can create image sprites with SVG \u2013 they don\u2019t look or work exactly alike, but the basic concept is pretty much the same.\n\nThere are several ways to create SVG sprites, and this article will give you an overview of three of them. While we\u2019re at it, we\u2019re going to take a look at some of the available tools used to automate sprite creation and fallback for us.\n\nPrerequisites\n\nThe content of this article assumes you are familiar with SVG. If you\u2019ve never worked with SVG before, you may want to look at some of the introductory tutorials covering SVG syntax, structure and embedding techniques. I recommend the following:\n\n\n\tSVG basics: Using SVG.\n\tStructure: Structuring, Grouping, and Referencing in SVG \u2014 The <g>, <use>, <defs> and <symbol> Elements. We\u2019ll mention <use> and <symbol> quite a bit in this article.\n\tEmbedding techniques: Styling and Animating SVGs with CSS. The article covers several topics, but the section linked focuses on embedding techniques.\n\tA compendium of SVG resources compiled by Chris Coyier \u2014 contains resources to almost every aspect of SVG you might be interested in.\n\n\nAnd if you\u2019re completely new to the concept of spriting, Chris Coyier\u2019s CSS Sprites explains all about them.\n\nAnother important SVG feature is the viewBox attribute. For some of the techniques, knowing your way around this attribute is not required, but it\u2019s definitely more useful if you understand \u2013 even if just vaguely \u2013 how it works. The last technique mentioned in the article requires that you do know the attribute\u2019s syntax and how to use it. To learn all about viewBox, you can refer to my blog post about SVG coordinate systems.\n\nWith the prerequisites in place, let\u2019s move on to spriting SVGs!\n\nBefore you sprite\u2026\n\nIn order to create an SVG sprite with your icons, you\u2019ll of course need to have these icons ready for use.\n\nSome spriting tools require that you place your icons in a folder to which a certain spriting process is to be applied. As such, for all of the upcoming sections we\u2019ll work on the assumption that our SVG icons are placed in a folder named SVG.\n\nEach icon is an individual .svg file.\n\nYou\u2019ll need to make sure each icon is well-prepared and optimised for use \u2013 make sure you\u2019ve cleaned up the code by running it through one of the optimisation tools or processes available (or doing it manually if it\u2019s not tedious).\n\nAfter prepping the icon files and placing them in a folder, we\u2019re ready to create our SVG sprite.\n\nHTML inline SVG sprites\n\nSince SVG is XML code, it can be embedded inline in an HTML document as a code island using the <svg> element. Chris Coyier wrote about this technique first on CSS-Tricks.\n\nThe embedded SVG will serve as a container for our icons and is going to be the actual sprite we\u2019re going to use. So we\u2019ll start by including the SVG in our document.\n\n<!DOCTYPE html>\n<!-- HTML document stuff -->\n\n<svg style=\"display:none;\">\n <!-- icons here -->\n</svg>\n\n<!-- other document stuff -->\n</html>\n\nNext, we\u2019re going to place the icons inside the <svg>. Each icon will be wrapped in a <symbol> element we can then reference and use elsewhere in the page using the SVG <use> element. The <symbol> element has many benefits, and we\u2019re using it because it allows us to define a symbol (which is a convenient markup for an icon) without rendering that symbol on the screen. The elements defined inside <symbol> will only be rendered when they are referenced \u2013 or called \u2013 by the <use> element.\n\nMoreover, <symbol> can have its own viewBox attribute, which makes it possible to control the positioning of its content inside its container at any time.\n\nBefore we move on, I\u2019d like to shed some light on the style=\"display:none;\" part of the snippet above. Without setting the display of the SVG to none, and even though its contents are not rendered on the page, the SVG will still take up space in the page, resulting in a big empty area. In order to avoid that, we\u2019re hiding the SVG entirely with CSS.\n\nNow, suppose we have a Twitter icon in the icons folder. twitter.svg might look something like this:\n\n<!-- twitter.svg -->\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"32\" height=\"32\" viewBox=\"0 0 32 32\">\n<path d=\"M32 6.076c-1.177 0.522-2.443 0.875-3.771 1.034 1.355-0.813 2.396-2.099 2.887-3.632-1.269 0.752-2.674 1.299-4.169 1.593-1.198-1.276-2.904-2.073-4.792-2.073-3.626 0-6.565 2.939-6.565 6.565 0 0.515 0.058 1.016 0.17 1.496-5.456-0.274-10.294-2.888-13.532-6.86-0.565 0.97-0.889 2.097-0.889 3.301 0 2.278 1.159 4.287 2.921 5.465-1.076-0.034-2.088-0.329-2.974-0.821-0.001 0.027-0.001 0.055-0.001 0.083 0 3.181 2.263 5.834 5.266 6.437-0.551 0.15-1.131 0.23-1.73 0.23-0.423 0-0.834-0.041-1.235-0.118 0.835 2.608 3.26 4.506 6.133 4.559-2.247 1.761-5.078 2.81-8.154 2.81-0.53 0-1.052-0.031-1.566-0.092 2.905 1.863 6.356 2.95 10.064 2.95 12.076 0 18.679-10.004 18.679-18.68 0-0.285-0.006-0.568-0.019-0.849 1.283-0.926 2.396-2.082 3.276-3.398z\" fill=\"#000000\"></path>\n</svg>\n\nWe don\u2019t need the root svg element, so we\u2019ll strip the code and only keep the parts that make up the Twitter icon\u2019s shape, which in this example is just the <path> element.Let\u2019s drop that into the sprite container like so:\n\n<svg style=\"display:none;\">\n <symbol id=\"twitter-icon\" viewBox=\"0 0 32 32\">\n <path d=\"M32 6.076c-1.177 \u2026\" fill=\"#000000\"></path>\n </symbol>\n\n <!-- remaining icons here -->\n <symbol id=\"instagram-icon\" viewBox=\"0 0 32 32\">\n <!-- icon contents -->\n </symbol>\n\n <!-- etc. -->\n</svg>\n\nRepeat for the other icons.\n\nThe value of the <symbol> element\u2019s viewBox attribute depends on the size of the SVG. You don\u2019t need to know how the viewBox works to use it in this case. Its value is made up of four parts: the first two will almost always be \u201c0 0\u201d; the second two will be equal to the size of the icon. For example, our Twitter icon is 32px by 32px (see twitter.svg above), so the viewBox value is \u201c0 0 32 32\u201d.\n\nThat said, it is certainly useful to understand how the viewBox works \u2013 it can help you troubleshoot SVG sometimes and gives you better control over it, allowing you to scale, position and even crop SVGs manually without having to resort to an editor. My blog post explains all about the viewBox attribute and its related attributes.\n\nOnce you have your SVG sprite ready, you can display the icons anywhere on the page by referencing them using the SVG <use> element:\n\n<svg class=\"twitter-icon\">\n <use xlink:href=\"#twitter-icon\"></use>\n<svg>\n\nAnd that\u2019s all there is to it!\n\nHTML-inline SVG sprites are simple to create and use, but when you have a lot of icons (and the more icon sets you create) it can easily become daunting if you have to manually transfer the icons into the <svg>. Fortunately, you don\u2019t have to do that. Fabrice Weinberg created a Grunt plugin called grunt-svgstore which takes the icons in your SVG folder and generates the SVG sprites for you; all you have to do is just drop the sprites into your page and use the icons like we did earlier.\n\nThis technique works in all browsers supporting SVG. There seems to be a bug in Safari on iOS which causes the icons not to show up when the SVG sprite is defined at the bottom of the document after the <use> references to the icons, so it\u2019s safest to include the sprite before you use the icons until this bug is fixed.\n\nThis technique has one disadvantage: the SVG sprite cannot be cached. We\u2019re saving an extra HTTP request here but the browser cannot cache the image, so we aren\u2019t speeding up any subsequent page loads by inlining the SVG. There must be a better way \u2013 and there is.\n\nStyling the icons is possible, but getting deep into the styles becomes a bit harder owing to the nature of the contents of the <use> element \u2013 these contents are cloned into a shadow DOM, and hence selecting elements in CSS the traditional way is not possible. However, some techniques to work around that do exist, and give us slightly more styling flexibility. Animations work as expected.\n\nReferencing an external SVG sprite in HTML\n\nInstead of including the SVG inline in the document, you can reference the sprite and the icons inside it externally, taking advantage of fragment identifiers to select individual icons in the sprite.\n\nFor example, the above reference to the Twitter icon would look something like this instead:\n\n<svg class=\"twitter-icon\">\n <use xlink:href=\"path/to/icons.svg#twitter-icon\"></use>\n<svg>\n\n\nicons.svg is the name of the SVG file that contains all of our icons as symbols, and the fragment identifier #twitter-icon is the reference to the <symbol> wrapping the Twitter icon\u2019s contents. Very convenient, isn\u2019t it? The browser will request the sprite and then cache it, speeding up subsequent page loads. Win!\n\nThis technique also works in all browsers supporting SVG except Internet Explorer \u2013 not even IE9+ with SVG support permits this technique. No version of IE supports referencing an external SVG in <use>.\n\nFortunately (again), Jonathan Neil has created a plugin called svg4everybody which fills this gap in IE; you can reference an external sprite in <use> and also provide fallback for browsers that do not support SVG. However, it requires you to have the fallback images (PNG or JPEG, for example) available to do so. For details, refer to the plugin\u2019s Github repository\u2019s readme file.\n\nCSS inline SVG sprites\n\nAnother way to create an SVG sprite is by inlining the SVG icons in a style sheet using data URIs, and providing fallback for non-supporting browsers \u2013 also within the CSS.\n\nUsing this approach, we\u2019re turning the style sheet into the sprite that includes our icons. The style sheet is normally cached by the browser, so we have that concern out of the way.\n\nThis technique is put into practice in Filament Group\u2019s icon system approach, which uses their Grunticon plugin \u2013 or its sister Grumpicon web app \u2013 for generating the necessary CSS for the sprite. As such, we\u2019re going to cover this technique by following a workflow that uses one of these tools.\n\nAgain, we start with our icon SVG files. To focus on the actual spriting method and not on the tooling, I\u2019ll go over the process of sprite creation using the Grumpicon web app, instead of the Grunticon plugin. Both tools generate the same resources that we\u2019re going to use for the icon system. Whether you choose the web app or the Grunt set-up, after processing your SVG folder you\u2019re going to end up with the same set of resources that we\u2019ll be using throughout this section.\n\nThe first step is to drop your icons into the Grumpicon web app.\n\n Grumpicon homepage screenshot.\n\nThe application will then show you a preview of your icons, and a download button will allow you to download the generated files. These files will contain everything you need for your icon system \u2013 all that\u2019s left is for you to drop the generated files and code into your project as recommended and you\u2019ll have your sprite and icons ready to use anywhere you want in your page.\n\nGrumpicon generates five files and one folder in the downloaded package: a png folder containing PNG versions of your icons; three style sheets (that we\u2019ll go over briefly); a loader script file; and preview.html which is a live example showing you the other files in action.\n\nThe script in the loader goes into the <head> of your page. This script handles browser and feature detection, and requests the necessary style sheet depending on browser support for SVG and base64 data URIs. If you view the source code of the preview page, you can see exactly how the script is added.\n\nicons.data.svg.css is the style sheet that contains your icons \u2013 the sprite. The icons are embedded inline inside the style sheet using data URIs, and applied to elements of your choice as background images, using class names. For example:\n\n.twitter-icon{\n background-image: url('data:image/svg+xml;\u2026'); /* the ellipsis is where the icon\u2019s data would go */\n background-repeat: no-repeat;\n background-position: 50% 50%;\n height: 2em;\n width: 2em;\n /* etc. */\n}\n\nThen, you only have to apply the twitter-icon class name to an element in your HTML to apply the icon as a background to it:\n\n<span class=\"twitter-icon\"></span>\n\nAnd that\u2019s all you need to do to get an icon on the page.\n\nicons.data.svg.css, along with the other two style sheets and the png folder should be added to your CSS folder.\n\nicons.data.png.css is the style sheet the script will load in browsers that don\u2019t support SVG, such as IE8. Fallback for the inline SVG is provided as a base64-encoded PNG. For instance, the fallback for the Twitter icon from our example would look like so:\n\n.twitter-icon{\n background-image: url('data:image/png;base64;\u2026\u2019);\n /* etc. */\n}\n\nicons.fallback.css is the style sheet required for browsers that don\u2019t support base64-encoded PNGs \u2013 the PNG images are loaded as usual using the image\u2019s URL. The script will load this style sheet for IE6 and IE7, for example.\n\n.twitter-icon{\n background-image: url(png/twitter-icon.png);\n /* etc. */\n}\n\nThis technique is very different from the previous one. The sprite in this case is literally the style sheet, not an SVG container, and the icon usage is very similar to that of a CSS sprite \u2013 the icons are provided as background images.\n\nThis technique has advantages and disadvantages. For the sake of brevity, I won\u2019t go into further details, but the main limitations worth mentioning are that SVGs embedded as background images cannot be styled with CSS; and animations are restricted to those defined inside the <svg> for each icon. CSS interactions (such as hover effects) don\u2019t work either. Thus, to apply an effect for an icon that changes its color on hover, for example, you\u2019ll need to export a set of SVGs for each colour in order for Grumpicon to create matching fallback PNG images that can then be used for the animation.\n\nFor more details about the Grumpicon workflow, I recommend you check out \u201cA Designer\u2019s Guide to Grumpicon\u201d on Filament Group\u2019s website.\n\nUsing SVG fragment identifiers and views\n\nThis spriting technique is, again, different from the previous ones, and it is my personal favourite.\n\nSVG comes with a standard way of cropping to a specific area in a particular SVG image. If you\u2019ve ever worked with CSS sprites before then this definitely sounds familiar: it\u2019s almost exactly what we do with CSS sprites \u2013 the image containing all of the icons is cropped, so to speak, to show only the one icon that we want in the background positioning area of the element, using background size and positioning properties.\n\nInstead of using background properties, we\u2019ll be using SVG\u2019s viewBox attribute to crop our SVG to the specific icon we want.\n\nWhat I like about this technique is that it is more visual than the previous ones. Using this technique, the SVG sprite is treated like an actual image containing other images (the icons), instead of treating it as a piece of code containing other code.\n\nAgain, our SVG icons are placed inside a main SVG container that is going to be our SVG sprite. If you\u2019re working in a graphics editor, position or arrange your icons inside the canvas any way you want them to be, and then export the graphic as is. Of course, the less empty space there is in your SVG, the better.\n\nIn our example, the sprite contains three icons as shown in the following image. The sprite is open in Sketch. Notice how the SVG is just big enough to fit the icons inside it. It doesn\u2019t have to be like this, but it\u2019s cleaner this way.\n\n Screenshot showing the SVG sprite containing our icons.\n\nNow, suppose you want to display only the Instagram icon. Using the SVG viewBox attribute, we can crop the SVG to the icon. The Instagram icon is positioned at 64px along the positive x-axis, and zero pixels along the y-axis. It is also 32px by 32px in size.\n\n Screenshot showing the position (offset) of the Instagram icon inside the SVG sprite, and its size.\n\nUsing this information, we can specify the value of the viewBox as: 64 0 32 32. This area of the view box contains only the Instagram icon. 64 0 specifies the top-left corner of the view box area, and 32 32 specify its dimensions.\n\nNow, if we were to change the viewBox value on the SVG sprite to this value, only the Instagram icon will be visible inside the SVG viewport. Great. But how do we use this information to display the icon in our page using our sprite?\n\nSVG comes with a native way to link to portions or areas of an image using fragment identifiers. Fragment identifiers are used to link into a particular view area of an SVG document. Thus, using a fragment identifier and the boundaries of the area that we want (from the viewBox), we can link to that area and display it.\n\nFor example, if you want to display the icon from the sprite using an <img> tag, you can reference the icon in the sprite like so:\n\n<img src='uiIcons.svg#svgView(viewBox(64, 0, 32, 32))' alt=\"Settings icon\"/>\n\nThe fragment identifier in the snippet above (#svgView(viewBox(64, 0, 32, 32))) is the important part. This will result in only the Instagram icon\u2019s area of the sprite being displayed.\n\nThere is also another way to do this, using the SVG <view> element. The <view> element can be used to define a view area and then reference that area somewhere else. For example, to define the view box containing the Instagram icon, we can do the following:\n\n<view id='instagram-icon' viewBox='64 0 32 32' />\n\nThen, we can reference this view in our <img> element like this:\n\n<img src='sprite.svg#instagram-icon' alt=\"Instagram icon\" />\n\nThe best part about this technique \u2013 besides the ability to reference an external SVG and hence make use of browser caching \u2013 is that it allows us to use practically any SVG embedding technique and does not restrict us to specific tags.\n\nIt goes without saying that this feature can be used for more than just icon systems, owing to viewBox\u2019s power in controlling an SVG\u2019s viewable area.\n\nSVG fragment identifiers have decent browser support, but the technique is buggy in Safari: there is a bug that causes problems when loading a server SVG file and then using fragment identifiers with it. Bear Travis has documented the issue and a workaround.\n\nWhere to go from here\n\nPick the technique that works best for your project. Each technique has its own pros and cons, relating to convenience and maintainability, performance, and styling and scripting. Each technique also requires its own fallback mechanism.\n\nThe spriting techniques mentioned here are not the only techniques available. Other methods exist, such as SVG stacks, and others may surface in future, but these are the three main ones today.\n\nThe third technique using SVG\u2019s built-in viewBox features is my favourite, and with better browser support and fewer (ideally, no) bugs, I believe it is more likely to become the standard way to create and use SVG sprites. Fallback techniques can be created, of course, in one of many possible ways.\n\nDo you use SVG for your icon system? If so, which is your favourite technique? Do you know or have worked with other ways for creating SVG sprites?", "year": "2014", "author": "Sara Soueidan", "author_slug": "sarasoueidan", "published": "2014-12-16T00:00:00+00:00", "url": "https://24ways.org/2014/an-overview-of-svg-sprite-creation-techniques/", "topic": "code"} {"rowid": 46, "title": "Responsive Enhancement", "contents": "24 ways has been going strong for ten years. That\u2019s an aeon in internet timescales. Just think of all the changes we\u2019ve seen in that time: the rise of Ajax, the explosion of mobile devices, the unrecognisably changed landscape of front-end tooling.\n\nTools and technologies come and go, but one thing has remained constant for me over the past decade: progressive enhancement.\n\nProgressive enhancement isn\u2019t a technology. It\u2019s more like a way of thinking. Instead of thinking about the specifics of how a finished website might look, progressive enhancement encourages you to think about the fundamental meaning of what the website is providing. So instead of thinking of a website in terms of its ideal state in a modern browser on a nice widescreen device, progressive enhancement allows you to think about the core functionality in a more abstract way.\n\nOnce you\u2019ve figured out what the core functionality is \u2013 adding an item to a shopping cart, posting a message, sharing a photo \u2013 then you can enable that functionality in the simplest possible way. That usually means starting with good old-fashioned HTML. Links and forms are often all you need. Then, once you have the core functionality working in a basic way, you can start to enhance to make a progressively better experience for more modern browsers.\n\nThe advantage of working this way isn\u2019t just that your site will work in older browsers (albeit in a rudimentary way). It also ensures that if anything goes wrong in a modern browser, it won\u2019t be catastrophic.\n\nThere\u2019s a common misconception that progressive enhancement means that you\u2019ll spend your time dealing with older browsers, but in fact the opposite is true. Putting the basic functionality into place doesn\u2019t take very long at all. And once you\u2019ve done that, you\u2019re free to spend all your time experimenting with the latest and greatest browser technologies, secure in the knowledge that even if they aren\u2019t universally supported yet, that\u2019s OK: you\u2019ve already got your fallback in place.\n\nThe key to thinking about web development this way is realising that there isn\u2019t one final interface \u2013 there could be many, slightly different interfaces depending on the properties and capabilities of any particular user agent at any particular moment. And that\u2019s OK. Websites do not need to look the same in every browser.\n\nOnce you truly accept that, it\u2019s an immensely liberating idea. Instead of spending your time trying to make websites look the same in wildly varying browsers, you can spend your time making sure that the core functionality of what you build works everywhere, while providing the best possible experience for more capable browsers.\n\nAllow me to demonstrate with a simple example: navigation.\n\nStep one: core functionality\n\nLet\u2019s say we have a straightforward website about the twelve days of Christmas, with a page for each day. The core functionality is pretty clear:\n\n\n\tTo read about any particular day.\n\tTo browse from day to day.\n\n\nThe first is easily satisfied by marking up the text with headings, paragraphs and all the usual structural HTML elements. The second is satisfied by providing a list of good ol\u2019 hyperlinks.\n\nNow where\u2019s the best place to position this navigation list? Personally, I\u2019m a big fan of the jump-to-footer pattern. This puts the content first and the navigation second. At the top of the page there\u2019s a link with an href attribute pointing to the fragment identifier for the navigation.\n\n<body>\n <main role=\"main\" id=\"top\">\n <a href=\"#menu\" class=\"control\">Menu</a>\n ...\n </main>\n <nav role=\"navigation\" id=\"menu\">\n ...\n <a href=\"#top\" class=\"control\">Dismiss</a>\n </nav>\n</body>\n\nSee the footer-anchor pattern in action.\n\nBecause it\u2019s nothing more than a hyperlink, this works in just about every browser since the dawn of the web. Following hyperlinks is what web browsers were made to do (hence the name).\n\nStep two: layout as an enhancement\n\nThe footer-anchor pattern is a particularly neat solution on small-screen devices, like mobile phones. Once more screen real estate is available, I can use the magic of CSS to reposition the navigation above the content. I could use position: absolute, flexbox or, in this case, display: table.\n\n@media all and (min-width: 35em) {\n .control {\n display: none;\n }\n body {\n display: table;\n }\n [role=\"navigation\"] {\n display: table-caption;\n columns: 6 15em;\n }\n}\n\nSee the styles for wider screens in action\n\nStep three: enhance!\n\nRight. At this point I\u2019m providing core functionality to everyone, and I\u2019ve got nice responsive styles for wider screens. I could stop here, but the real advantage of progressive enhancement is that I don\u2019t have to. From here on, I can go crazy adding all sorts of fancy enhancements for modern browsers, without having to worry about providing a fallback for older browsers \u2013 the fallback is already in place.\n\nWhat I\u2019d really like is to provide a swish off-canvas pattern for small-screen devices. Here\u2019s my plan:\n\n\n\tPosition the navigation under the main content.\n\tListen out for the .control links being activated and intercept that action.\n\tWhen those links are activated, toggle a class of .active on the body.\n\tIf the .active class exists, slide the content out to reveal the navigation.\n\n\nHere\u2019s the CSS for positioning the content and navigation:\n\n@media all and (max-width: 35em) {\n [role=\"main\"] {\n transition: all .25s;\n width: 100%;\n position: absolute;\n z-index: 2;\n top: 0;\n right: 0;\n }\n [role=\"navigation\"] {\n width: 75%;\n position: absolute;\n z-index: 1;\n top: 0;\n right: 0;\n }\n .active [role=\"main\"] {\n transform: translateX(-75%);\n }\n}\n\nIn my JavaScript, I\u2019m going to listen out for any clicks on the .control links and toggle the .active class on the body accordingly:\n\n(function (win, doc) {\n 'use strict';\n var linkclass = 'control',\n activeclass = 'active',\n toggleClassName = function (element, toggleClass) {\n var reg = new RegExp('(s|^)' + toggleClass + '(s|$)');\n if (!element.className.match(reg)) {\n element.className += ' ' + toggleClass;\n } else {\n element.className = element.className.replace(reg, '');\n }\n },\n navListener = function (ev) {\n ev = ev || win.event;\n var target = ev.target || ev.srcElement;\n if (target.className.indexOf(linkclass) !== -1) {\n ev.preventDefault();\n toggleClassName(doc.body, activeclass);\n }\n };\n doc.addEventListener('click', navListener, false);\n}(this, this.document));\n\nI\u2019m all set, right? Not so fast!\n\nCutting the mustard\n\nI\u2019ve made the assumption that addEventListener will be available in my JavaScript. That isn\u2019t a safe assumption. That\u2019s because JavaScript \u2013 unlike HTML or CSS \u2013 isn\u2019t fault-tolerant. If you use an HTML element or attribute that a browser doesn\u2019t understand, or if you use a CSS selector, property or value that a browser doesn\u2019t understand, it\u2019s no big deal. The browser will just ignore what it doesn\u2019t understand: it won\u2019t throw an error, and it won\u2019t stop parsing the file.\n\nJavaScript is different. If you make an error in your JavaScript, or use a JavaScript method or property that a browser doesn\u2019t recognise, that browser will throw an error, and it will stop parsing the file. That\u2019s why it\u2019s important to test for features before using them in JavaScript. That\u2019s also why it isn\u2019t safe to rely on JavaScript for core functionality.\n\nIn my case, I need to test for the existence of addEventListener:\n\n(function (win, doc) {\n if (!win.addEventListener) {\n return;\n }\n ...\n}(this, this.document));\n\nThe good folk over at the BBC call this kind of feature test cutting the mustard. If a browser passes the test, it cuts the mustard, and so it gets the enhancements. If a browser doesn\u2019t cut the mustard, it doesn\u2019t get the enhancements. And that\u2019s fine because, remember, websites don\u2019t need to look the same in every browser.\n\nI want to make sure that my off-canvas styles are only going to apply to mustard-cutting browsers. I\u2019m going to use JavaScript to add a class of .cutsthemustard to the document:\n\n(function (win, doc) {\n if (!win.addEventListener) {\n return;\n }\n ...\n var enhanceclass = 'cutsthemustard';\n doc.documentElement.className += ' ' + enhanceclass;\n}(this, this.document));\n\nNow I can use the existence of that class name to adjust my CSS:\n\n@media all and (max-width: 35em) {\n .cutsthemustard [role=\"main\"] {\n transition: all .25s;\n width: 100%;\n position: absolute;\n z-index: 2;\n top: 0;\n right: 0;\n }\n .cutsthemustard [role=\"navigation\"] {\n width: 75%;\n position: absolute;\n z-index: 1;\n top: 0;\n right: 0;\n }\n .cutsthemustard .active [role=\"main\"] {\n transform: translateX(-75%);\n }\n}\n\nSee the enhanced mustard-cutting off-canvas navigation. Remember, this only applies to small screens so you might have to squish your browser window.\n\nEnhance all the things!\n\nThis was a relatively simple example, but it illustrates the thinking behind progressive enhancement: once you\u2019re providing the core functionality to everyone, you\u2019re free to go crazy with all the latest enhancements for modern browsers.\n\nProgressive enhancement doesn\u2019t mean you have to provide all the same functionality to everyone \u2013 quite the opposite. That\u2019s why it\u2019s key to figure out early on what the core functionality is, and make sure that it can be provided with the most basic technology. But from that point on, you\u2019re free to add many more features that aren\u2019t mission-critical. You should reward more capable browsers by giving them more of those features, such as animation in CSS, geolocation in JavaScript, and new input types in HTML.\n\nLike I said, progressive enhancement isn\u2019t a technology. It\u2019s a way of thinking. Once you start thinking this way, you\u2019ll be prepared for whatever the next ten years throws at us.", "year": "2014", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2014-12-09T00:00:00+00:00", "url": "https://24ways.org/2014/responsive-enhancement/", "topic": "code"} {"rowid": 49, "title": "Universal React", "contents": "One of the libraries to receive a huge amount of focus in 2015 has been ReactJS, a library created by Facebook for building user interfaces and web applications.\nMore generally we\u2019ve seen an even greater rise in the number of applications built primarily on the client side with most of the logic implemented in JavaScript. One of the main issues with building an app in this way is that you immediately forgo any customers who might browse with JavaScript turned off, and you can also miss out on any robots that might visit your site to crawl it (such as Google\u2019s search bots). Additionally, we gain a performance improvement by being able to render from the server rather than having to wait for all the JavaScript to be loaded and executed.\nThe good news is that this problem has been recognised and it is possible to build a fully featured client-side application that can be rendered on the server. The way in which these apps work is as follows:\n\nThe user visits www.yoursite.com and the server executes your JavaScript to generate the HTML it needs to render the page.\nIn the background, the client-side JavaScript is executed and takes over the duty of rendering the page.\nThe next time a user clicks, rather than being sent to the server, the client-side app is in control.\nIf the user doesn\u2019t have JavaScript enabled, each click on a link goes to the server and they get the server-rendered content again.\n\nThis means you can still provide a very quick and snappy experience for JavaScript users without having to abandon your non-JS users. We achieve this by writing JavaScript that can be executed on the server or on the client (you might have heard this referred to as isomorphic) and using a JavaScript framework that\u2019s clever enough handle server- or client-side execution. Currently, ReactJS is leading the way here, although Ember and Angular are both working on solutions to this problem.\nIt\u2019s worth noting that this tutorial assumes some familiarity with React in general, its syntax and concepts. If you\u2019d like a refresher, the ReactJS docs are a good place to start.\n\u00a0Getting started\nWe\u2019re going to create a tiny ReactJS application that will work on the server and the client. First we\u2019ll need to create a new project and install some dependencies. In a new, blank directory, run:\nnpm init -y\nnpm install --save ejs express react react-router react-dom\nThat will create a new project and install our dependencies:\n\nejs is a templating engine that we\u2019ll use to render our HTML on the server.\nexpress is a small web framework we\u2019ll run our server on.\nreact-router is a popular routing solution for React so our app can fully support and respect URLs.\nreact-dom is a small React library used for rendering React components.\n\nWe\u2019re also going to write all our code in ECMAScript 6, and therefore need to install BabelJS and configure that too.\nnpm install --save-dev babel-cli babel-preset-es2015 babel-preset-react\nThen, create a .babelrc file that contains the following:\n{\n \"presets\": [\"es2015\", \"react\"]\n}\nWhat we\u2019ve done here is install Babel\u2019s command line interface (CLI) tool and configured it to transform our code from ECMAScript 6 (or ES2015) to ECMAScript 5, which is more widely supported. We\u2019ll need the React transforms when we start writing JSX when working with React.\nCreating a server\nFor now, our ExpressJS server is pretty straightforward. All we\u2019ll do is render a view that says \u2018Hello World\u2019. Here\u2019s our server code:\nimport express from 'express';\nimport http from 'http';\n\nconst app = express();\n\napp.use(express.static('public'));\n\napp.set('view engine', 'ejs');\n\napp.get('*', (req, res) => {\n res.render('index');\n});\n\nconst server = http.createServer(app);\n\nserver.listen(3003);\nserver.on('listening', () => {\n console.log('Listening on 3003');\n});\nHere we\u2019re using ES6 modules, which I wrote about on 24 ways last year, if you\u2019d like a reminder. We tell the app to render the index view on any GET request (that\u2019s what app.get('*') means, the wildcard matches any route).\nWe now need to create the index view file, which Express expects to be defined in views/index.ejs:\n<!DOCTYPE html>\n<html>\n <head>\n <title>My App</title>\n </head>\n\n <body>\n Hello World\n </body>\n</html>\nFinally, we\u2019re ready to run the server. Because we installed babel-cli earlier we have access to the babel-node executable, which will transform all your code before running it through node. Run this command:\n./node_modules/.bin/babel-node server.js\nAnd you should now be able to visit http://localhost:3003 and see \u2018Hello World\u2019 right there:\n\nBuilding the React app\nNow we\u2019ll build the React application entirely on the server, before adding the client-side JavaScript right at the end. Our app will have two routes, / and /about which will both show a small amount of content. This will demonstrate how to use React Router on the server side to make sure our React app plays nicely with URLs.\nFirstly, let\u2019s update views/index.ejs. Our server will figure out what HTML it needs to render, and pass that into the view. We can pass a value into our view when we render it, and then use EJS syntax to tell it to output that data. Update the template file so the body looks like so:\n<body>\n <%- markup %>\n</body>\nNext, we\u2019ll define the routes we want our app to have using React Router. For now we\u2019ll just define the index route, and not worry about the /about route quite yet. We could define our routes in JSX, but I think for server-side rendering it\u2019s clearer to define them as an object. Here\u2019s what we\u2019re starting with:\nconst routes = {\n path: '',\n component: AppComponent,\n childRoutes: [\n {\n path: '/',\n component: IndexComponent\n }\n ]\n}\nThese are just placed at the top of server.js, after the import statements. Later we\u2019ll move these into a separate file, but for now they are fine where they are.\nNotice how I define first that the AppComponent should be used at the '' path, which effectively means it matches every single route and becomes a container for all our other components. Then I give it a child route of /, which will match the IndexComponent. Before we hook these routes up with our server, let\u2019s quickly define components/app.js and components/index.js. app.js looks like so:\nimport React from 'react';\n\nexport default class AppComponent extends React.Component {\n render() {\n return (\n <div>\n <h2>Welcome to my App</h2>\n { this.props.children }\n </div>\n );\n }\n}\nWhen a React Router route has child components, they are given to us in the props under the children key, so we need to include them in the code we want to render for this component. The index.js component is pretty bland:\nimport React from 'react';\n\nexport default class IndexComponent extends React.Component {\n render() {\n return (\n <div>\n <p>This is the index page</p>\n </div>\n );\n }\n}\nServer-side routing with React Router\nHead back into server.js, and firstly we\u2019ll need to add some new imports:\nimport React from 'react';\nimport { renderToString } from 'react-dom/server';\nimport { match, RoutingContext } from 'react-router';\n\nimport AppComponent from './components/app';\nimport IndexComponent from './components/index';\nThe ReactDOM package provides react-dom/server which includes a renderToString method that takes a React component and produces the HTML string output of the component. It\u2019s this method that we\u2019ll use to render the HTML from the server, generated by React. From the React Router package we use match, a function used to find a matching route for a URL; and RoutingContext, a React component provided by React Router that we\u2019ll need to render. This wraps up our components and provides some functionality that ties React Router together with our app. Generally you don\u2019t need to concern yourself about how this component works, so don\u2019t worry too much.\nNow for the good bit: we can update our app.get('*') route with the code that matches the URL against the React routes:\napp.get('*', (req, res) => {\n // routes is our object of React routes defined above\n match({ routes, location: req.url }, (err, redirectLocation, props) => {\n if (err) {\n // something went badly wrong, so 500 with a message\n res.status(500).send(err.message);\n } else if (redirectLocation) {\n // we matched a ReactRouter redirect, so redirect from the server\n res.redirect(302, redirectLocation.pathname + redirectLocation.search);\n } else if (props) {\n // if we got props, that means we found a valid component to render\n // for the given route\n const markup = renderToString(<RoutingContext {...props} />);\n\n // render `index.ejs`, but pass in the markup we want it to display\n res.render('index', { markup })\n\n } else {\n // no route match, so 404. In a real app you might render a custom\n // 404 view here\n res.sendStatus(404);\n }\n });\n});\nWe call match, giving it the routes object we defined earlier and req.url, which contains the URL of the request. It calls a callback function we give it, with err, redirectLocation and props as the arguments. The first two conditionals in the callback function just deal with an error occuring or a redirect (React Router has built in redirect support). The most interesting bit is the third conditional, else if (props). If we got given props and we\u2019ve made it this far it means we found a matching component to render and we can use this code to render it:\n...\n} else if (props) {\n // if we got props, that means we found a valid component to render\n // for the given route\n const markup = renderToString(<RoutingContext {...props} />);\n\n // render `index.ejs`, but pass in the markup we want it to display\n res.render('index', { markup })\n} else {\n ...\n}\nThe renderToString method from ReactDOM takes that RoutingContext component we mentioned earlier and renders it with the properties required. Again, you need not concern yourself with what this specific component does or what the props are. Most of this is data that React Router provides for us on top of our components.\nNote the {...props}, which is a neat bit of JSX syntax that spreads out our object into key value properties. To see this better, note the two pieces of JSX code below, both of which are equivalent:\n<MyComponent a=\"foo\" b=\"bar\" />\n\n// OR:\n\nconst props = { a: \"foo\", b: \"bar\" };\n<MyComponent {...props} />\nRunning the server again\nI know that felt like a lot of work, but the good news is that once you\u2019ve set this up you are free to focus on building your React components, safe in the knowledge that your server-side rendering is working. To check, restart the server and head to http://localhost:3003 once more. You should see it all working!\n\nRefactoring and one more route\nBefore we move on to getting this code running on the client, let\u2019s add one more route and do some tidying up. First, move our routes object out into routes.js:\nimport AppComponent from './components/app';\nimport IndexComponent from './components/index';\n\nconst routes = {\n path: '',\n component: AppComponent,\n childRoutes: [\n {\n path: '/',\n component: IndexComponent\n }\n ]\n}\n\nexport { routes };\nAnd then update server.js. You can remove the two component imports and replace them with:\nimport { routes } from './routes';\nFinally, let\u2019s add one more route for ./about and links between them. Create components/about.js:\nimport React from 'react';\n\nexport default class AboutComponent extends React.Component {\n render() {\n return (\n <div>\n <p>A little bit about me.</p>\n </div>\n );\n }\n}\nAnd then you can add it to routes.js too:\nimport AppComponent from './components/app';\nimport IndexComponent from './components/index';\nimport AboutComponent from './components/about';\n\nconst routes = {\n path: '',\n component: AppComponent,\n childRoutes: [\n {\n path: '/',\n component: IndexComponent\n },\n {\n path: '/about',\n component: AboutComponent\n }\n ]\n}\n\nexport { routes };\nIf you now restart the server and head to http://localhost:3003/about` you\u2019ll see the about page!\n\nFor the finishing touch we\u2019ll use the React Router link component to add some links between the pages. Edit components/app.js to look like so:\nimport React from 'react';\nimport { Link } from 'react-router';\n\nexport default class AppComponent extends React.Component {\n render() {\n return (\n <div>\n <h2>Welcome to my App</h2>\n <ul>\n <li><Link to='/'>Home</Link></li>\n <li><Link to='/about'>About</Link></li>\n </ul>\n { this.props.children }\n </div>\n );\n }\n}\nYou can now click between the pages to navigate. However, everytime we do so the requests hit the server. Now we\u2019re going to make our final change, such that after the app has been rendered on the server once, it gets rendered and managed in the client, providing that snappy client-side app experience.\nClient-side rendering\nFirst, we\u2019re going to make a small change to views/index.ejs. React doesn\u2019t like rendering directly into the body and will give a warning when you do so. To prevent this we\u2019ll wrap our app in a div:\n<body>\n <div id=\"app\"><%- markup %></div>\n <script src=\"build.js\"></script>\n</body>\nI\u2019ve also added in a script tag to build.js, which is the file we\u2019ll generate containing all our client-side code.\nNext, create client-render.js. This is going to be the only bit of JavaScript that\u2019s exclusive to the client side. In it we need to pull in our routes and render them to the DOM.\nimport React from 'react';\nimport ReactDOM from 'react-dom';\nimport { Router } from 'react-router';\n\nimport { routes } from './routes';\n\nimport createBrowserHistory from 'history/lib/createBrowserHistory';\n\nReactDOM.render(\n <Router routes={routes} history={createBrowserHistory()} />,\n document.getElementById('app')\n)\nThe first thing you might notice is the mention of createBrowserHistory. React Router is built on top of the history module, a module that listens to the browser\u2019s address bar and parses the new location. It has many modes of operation: it can keep track using a hashbang, such as http://localhost/#!/about (this is the default), or you can tell it to use the HTML5 history API by calling createBrowserHistory, which is what we\u2019ve done. This will keep the URLs nice and neat and make sure the client and the server are using the same URL structure. You can read more about React Router and histories in the React Router documentation.\nFinally we use ReactDOM.render and give it the Router component, telling it about all our routes, and also tell ReactDOM where to render, the #app element.\nGenerating build.js\nWe\u2019re actually almost there! The final thing we need to do is generate our client side bundle. For this we\u2019re going to use webpack, a module bundler that can take our application, follow all the imports and generate one large bundle from them. We\u2019ll install it and babel-loader, a webpack plugin for transforming code through Babel.\nnpm install --save-dev webpack babel-loader\nTo run webpack we just need to create a configuration file, called webpack.config.js. Create the file in the root of our application and add the following code:\nvar path = require('path');\nmodule.exports = {\n entry: path.join(process.cwd(), 'client-render.js'),\n output: {\n path: './public/',\n filename: 'build.js'\n },\n module: {\n loaders: [\n {\n test: /.js$/,\n loader: 'babel'\n }\n ]\n }\n}\nNote first that this file can\u2019t be written in ES6 as it doesn\u2019t get transformed. The first thing we do is tell webpack the main entry point for our application, which is client-render.js. We use process.cwd() because webpack expects an exact location \u2013 if we just gave it the string \u2018client-render.js\u2019, webpack wouldn\u2019t be able to find it.\nNext, we tell webpack where to output our file, and here I\u2019m telling it to place the file in public/build.js. Finally we tell webpack that every time it hits a file that ends in .js, it should use the babel-loader plugin to transform the code first.\nNow we\u2019re ready to generate the bundle!\n./node_modules/.bin/webpack\nThis will take a fair few seconds to run (on my machine it\u2019s about seven or eight), but once it has it will have created public/build.js, a client-side bundle of our application. If you restart your server once more you\u2019ll see that we can now navigate around our application without hitting the server, because React on the client takes over. Perfect!\nThe first bundle that webpack generates is pretty slow, but if you run webpack -w it will go into watch mode, where it watches files for changes and regenerates the bundle. The key thing is that it only regenerates the small pieces of the bundle it needs, so while the first bundle is very slow, the rest are lightning fast. I recommend leaving webpack constantly running in watch mode when you\u2019re developing.\nConclusions\nFirst, if you\u2019d like to look through this code yourself you can find it all on GitHub. Feel free to raise an issue there or tweet me if you have any problems or would like to ask further questions.\nNext, I want to stress that you shouldn\u2019t use this as an excuse to build all your apps in this way. Some of you might be wondering whether a static site like the one we built today is worth its complexity, and you\u2019d be right. I used it as it\u2019s an easy example to work with but in the future you should carefully consider your reasons for wanting to build a universal React application and make sure it\u2019s a suitable infrastructure for you.\nWith that, all that\u2019s left for me to do is wish you a very merry Christmas and best of luck with your React applications!", "year": "2015", "author": "Jack Franklin", "author_slug": "jackfranklin", "published": "2015-12-05T00:00:00+00:00", "url": "https://24ways.org/2015/universal-react/", "topic": "code"} {"rowid": 52, "title": "Git Rebasing: An Elfin Workshop Workflow", "contents": "This year Santa\u2019s helpers have been tasked with making a garland. It\u2019s a pretty simple task: string beads onto yarn in a specific order. When the garland reaches a specific length, add it to the main workshop garland. Each elf has a specific sequence they\u2019re supposed to chain, which is given to them via a work order. (This is starting to sound like one of those horrible calculus problems. I promise it isn\u2019t. It\u2019s worse; it\u2019s about Git.)\nFor the most part, the system works really well. The elves are able to quickly build up a shared chain because each elf specialises on their own bit of garland, and then links the garland together. Because of this they\u2019re able to work independently, but towards the common goal of making a beautiful garland.\nAt first the elves are really careful with each bead they put onto the garland. They check with one another before merging their work, and review each new link carefully. As time crunches on, the elves pour a little more cheer into the eggnog cooler, and the quality of work starts to degrade. Tensions rise as mistakes are made and unkind words are said. The elves quickly realise they\u2019re going to need a system to change the beads out when mistakes are made in the chain.\nThe first common mistake is not looking to see what the latest chain is that\u2019s been added to the main garland. The garland is huge, and it sits on a roll in one of the corners of the workshop. It\u2019s a big workshop, so it is incredibly impractical to walk all the way to the roll to check what the last link is on the chain. The elves, being magical, have set up a monitoring system that allows them to keep a local copy of the main garland at their workstation. It\u2019s an imperfect system though, so the elves have to request a manual refresh to see the latest copy. They can request a new copy by running the command\ngit pull --rebase=preserve\n(They found that if they ran git pull on its own, they ended up with weird loops of extra beads off the main garland, so they\u2019ve opted to use this method.) This keeps the shared garland up to date, which makes things a lot easier. A visualisation of the rebase process is available.\nThe next thing the elves noticed is that if they worked on the main workshop garland, they were always running into problems when they tried to share their work back with the rest of the workshop. It was fine if they were working late at night by themselves, but in the middle of the day, it was horrible. (I\u2019ve been asked not to talk about that time the fight broke out.) Instead of trying to share everything on their local copy of the main garland, the elves have realised it\u2019s a lot easier to work on a new string and then knot this onto the main garland when their pattern repeat is finished. They generate a new string by issuing the following commands:\ngit checkout master\ngit checkout -b 1234_pattern-name\n1234 represents the work order number and pattern-name describes the pattern they\u2019re adding. Each bead is then added to the new link (git add bead.txt) and locked into place (git commit). Each elf repeats this process until the sequence of beads described in the work order has been added to their mini garland.\nTo combine their work with the main garland, the elves need to make a few decisions. If they\u2019re making a single strand, they issue the following commands:\ngit checkout master\ngit merge --ff-only 1234_pattern-name\nTo share their work they publish the new version of the main garland to the workshop spool with the command git push origin master.\nSometimes this fails. Sharing work fails because the workshop spool has gotten new links added since the elf last updated their copy of the main workshop spool. This makes the elves both happy and sad. It makes them happy because it means the other elves have been working too, but it makes them sad because they now need to do a bit of extra work to close their work order. \nTo update the local copy of the workshop spool, the elf first unlinks the chain they just linked by running the command:\ngit reset --merge ORIG_HEAD\nThis works because the garland magic notices when the elves are doing a particularly dangerous thing and places a temporary, invisible bookmark to the last safe bead in the chain before the dangerous thing happened. The garland no longer has the elf\u2019s work, and can be updated safely. The elf runs the command git pull --rebase=preserve and the changes all the other elves have made are applied locally.\nWith these new beads in place, the elf now has to restring their own chain so that it starts at the right place. To do this, the elf turns back to their own chain (git checkout 1234_pattern-name) and runs the command git rebase master. Assuming their bead pattern is completely unique, the process will run and the elf\u2019s beads will be restrung on the tip of the main workshop garland.\nSometimes the magic fails and the elf has to deal with merge conflicts. These are kind of annoying, so the elf uses a special inspector tool to figure things out. The elf opens the inspector by running the command git mergetool to work through places where their beads have been added at the same points as another elf\u2019s beads. Once all the conflicts are resolved, the elf saves their work, and quits the inspector. They might need to do this a few times if there are a lot of new beads, so the elf has learned to follow this update process regularly instead of just waiting until they\u2019re ready to close out their work order.\nOnce their link is up to date, the elf can now reapply their chain as before, publish their work to the main workshop garland, and close their work order:\ngit checkout master\ngit merge --ff-only 1234_pattern-name\ngit push origin master\nGenerally this process works well for the elves. Sometimes, though, when they\u2019re tired or bored or a little drunk on festive cheer, they realise there\u2019s a mistake in their chain of beads. Fortunately they can fix the beads without anyone else knowing. These tools can be applied to the whole workshop chain as well, but it causes problems because the magic assumes that elves are only ever adding to the main chain, not removing or reordering beads on the fly. Depending on where the mistake is, the elf has a few different options.\nLet\u2019s pretend the elf has a sequence of five beads she\u2019s been working on. The work order says the pattern should be red-blue-red-blue-red.\n\nIf the sequence of beads is wrong (for example, blue-blue-red-red-red), the elf can remove the beads from the chain, but keep the beads in her workstation using the command git reset --soft HEAD~5.\n\nIf she\u2019s been using the wrong colours and the wrong pattern (for example, green-green-yellow-yellow-green), she can remove the beads from her chain and discard them from her workstation using the command git reset --hard HEAD~5.\n\nIf one of the beads is missing (for example, red-blue-blue-red), she can restring the beads using the first method, or she can use a bit of magic to add the missing bead into the sequence.\n\nUsing a tool that\u2019s a bit like orthoscopic surgery, she first selects a sequence of beads which contains the problem. A visualisation of this process is available.\nStart the garland surgery process with the command:\ngit rebase --interactive HEAD~4\nA new screen comes up with the following information (the oldest bead is on top):\npick c2e4877 Red bead\npick 9b5555e Blue bead\npick 7afd66b Blue bead\npick e1f2537 Red bead\nThe elf adjusts the list, changing \u201cpick\u201d to \u201cedit\u201d next to the first blue bead:\npick c2e4877 Red bead\nedit 9b5555e Blue bead\npick 7afd66b Blue bead\npick e1f2537 Red bead\nShe then saves her work and quits the editor. The garland magic has placed her back in time at the moment just after she added the first blue bead.\n\nShe needs to manually fix up her garland to add the new red bead. If the beads were files, she might run commands like vim beads.txt and edit the file to make the necessary changes.\nOnce she\u2019s finished her changes, she needs to add her new bead to the garland (git add --all) and lock it into place (git commit). This time she assigns the commit message \u201cRed bead \u2013 added\u201d so she can easily find it.\n\nThe garland magic has replaced the bead, but she still needs to verify the remaining beads on the garland. This is a mostly automatic process which is started by running the command git rebase --continue.\nThe new red bead has been assigned a position formerly held by the blue bead, and so the elf must deal with a merge conflict. She opens up a new program to help resolve the conflict by running git mergetool.\n\nShe knows she wants both of these beads in place, so the elf edits the file to include both the red and blue beads.\n\nWith the conflict resolved, the elf saves her changes and quits the mergetool.\nBack at the command line, the elf checks the status of her work using the command git status.\nrebase in progress; onto 4a9cb9d\nYou are currently rebasing branch '2_RBRBR' on '4a9cb9d'.\n (all conflicts fixed: run \"git rebase --continue\")\n\nChanges to be committed:\n (use \"git reset HEAD <file>...\" to unstage)\n\n modified: beads.txt\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\n beads.txt.orig\nShe removes the file added by the mergetool with the command rm beads.txt.orig and commits the edits she just made to the bead file using the commands:\ngit add beads.txt\ngit commit --message \"Blue bead -- resolved conflict\"\n\nWith the conflict resolved, the elf is able to continue with the rebasing process using the command git rebase --continue. There is one final conflict the elf needs to resolve. Once again, she opens up the visualisation tool and takes a look at the two conflicting files.\n\nShe incorporates the changes from the left and right column to ensure her bead sequence is correct.\n\nOnce the merge conflict is resolved, the elf saves the file and quits the mergetool. Once again, she cleans out the backup file added by the mergetool (rm beads.txt.orig) and commits her changes to the garland:\ngit add beads.txt\ngit commit --message \"Red bead -- resolved conflict\"\nand then runs the final verification steps in the rebase process (git rebase --continue).\n\nThe verification process runs through to the end, and the elf checks her work using the command git log --oneline.\n9269914 Red bead -- resolved conflict\n4916353 Blue bead -- resolved conflict\naef0d5c Red bead -- added\n9b5555e Blue bead\nc2e4877 Red bead\nShe knows she needs to read the sequence from bottom to top (the oldest bead is on the bottom). Reviewing the list she sees that the sequence is now correct.\nSometimes, late at night, the elf makes new copies of the workshop garland so she can play around with the bead sequencer just to see what happens. It\u2019s made her more confident at restringing beads when she\u2019s found real mistakes. And she doesn\u2019t mind helping her fellow elves when they run into trouble with their beads. The sugar cookies they leave her as thanks don\u2019t hurt either. If you would also like to play with the bead sequencer, you can get a copy of the branches the elf worked.\n\nOur lessons from the workshop:\n\nBy using rebase to update your branches, you avoid merge commits and keep a clean commit history.\nIf you make a mistake on one of your local branches, you can use reset to take commits off your branch. If you want to save the work, but uncommit it, add the parameter --soft. If you want to completely discard the work, use the parameter, --hard.\nIf you have merged working branch changes to the local copy of your master branch and it is preventing you from pushing your work to a remote repository, remove these changes using the command reset with the parameter --merge ORIG_HEAD before updating your local copy of the remote master branch.\nIf you want to make a change to work that was committed a little while ago, you can use the command rebase with the parameter --interactive. You will need to include how many commits back in time you want to review.", "year": "2015", "author": "Emma Jane Westby", "author_slug": "emmajanewestby", "published": "2015-12-07T00:00:00+00:00", "url": "https://24ways.org/2015/git-rebasing/", "topic": "code"} {"rowid": 54, "title": "Putting My Patterns through Their Paces", "contents": "Over the last few years, the conversation around responsive design has shifted subtly, focusing not on designing pages, but on patterns: understanding the small, reusable elements that comprise a larger design system. And given that many of those patterns are themselves responsive, learning to manage these small layout systems has become a big part of my work.\nThe thing is, the more pattern-driven work I do, the more I realize my design process has changed in a number of subtle, important ways. I suppose you might even say that pattern-driven design has, in a few ways, redesigned me.\nMeet the Teaser\nHere\u2019s a recent example. A few months ago, some friends and I redesigned The Toast. (It was a really, really fun project, and we learned a lot.) Each page of the site is, as you might guess, stitched together from a host of tiny, reusable patterns. Some of them, like the search form and footer, are fairly unique, and used once per page; others are used more liberally, and built for reuse. The most prevalent example of these more generic patterns is the teaser, which is classed as, uh, .teaser. (Look, I never said I was especially clever.)\nIn its simplest form, a teaser contains a headline, which links to an article:\n\nFairly straightforward, sure. But it\u2019s just the foundation: from there, teasers can have a byline, a description, a thumbnail, and a comment count. In other words, we have a basic building block (.teaser) that contains a few discrete content types \u2013 some required, some not. In fact, very few of those pieces need to be present; to qualify as a teaser, all we really need is a link and a headline. But by adding more elements, we can build slight variations of our teaser, and make it much, much more versatile.\n\n Nearly every element visible on this page is built out of our generic \u201cteaser\u201d pattern.\n \nBut the teaser variation I\u2019d like to call out is the one that appears on The Toast\u2019s homepage, on search results or on section fronts. In the main content area, each teaser in the list features larger images, as well as an interesting visual treatment: the byline and comment count were the most prominent elements within each teaser, appearing above the headline.\n\n The approved visual design of our teaser, as it appears on lists on the homepage and the section fronts.\n \nAnd this is, as it happens, the teaser variation that gave me pause. Back in the old days \u2013 you know, like six months ago \u2013 I probably would\u2019ve marked this module up to match the design. In other words, I would\u2019ve looked at the module\u2019s visual hierarchy (metadata up top, headline and content below) and written the following HTML:\n<div class=\"teaser\">\n <p class=\"article-byline\">By <a href=\"#\">Author Name</a></p>\n <a class=\"comment-count\" href=\"#\">126 <i>comments</i></a>\n <h1 class=\"article-title\"><a href=\"#\">Article Title</a></h1>\n <p class=\"teaser-excerpt\">Lorem ipsum dolor sit amet, consectetur\u2026</p>\n</div>\nBut then I caught myself, and realized this wasn\u2019t the best approach.\nMoving Beyond Layout\nSince I\u2019ve started working responsively, there\u2019s a question I work into every step of my design process. Whether I\u2019m working in Sketch, CSSing a thing, or researching a project, I try to constantly ask myself:\n\nWhat if someone doesn\u2019t browse the web like I do?\n\n\u2026Okay, that doesn\u2019t seem especially fancy. (And maybe you came here for fancy.) But as straightforward as that question might seem, it\u2019s been invaluable to so many aspects of my practice. If I\u2019m working on a widescreen layout, that question helps me remember the constraints of the small screen; if I\u2019m working on an interface that has some enhancements for touch, it helps me consider other input modes as I work. It\u2019s also helpful as a reminder that many might not see the screen the same way I do, and that accessibility (in all its forms) should be a throughline for our work on the web.\nAnd that last point, thankfully, was what caught me here. While having the byline and comment count at the top was a lovely visual treatment, it made for a terrible content hierarchy. For example, it\u2019d be a little weird if the page was being read aloud in a speaking browser: the name of the author and the number of comments would be read aloud before the title of the article with which they\u2019re associated.\nThat\u2019s why I find it\u2019s helpful to begin designing a pattern\u2019s hierarchy before its layout: to move past the visual presentation in front of me, and focus on the underlying content I\u2019m trying to support. In other words, if someone\u2019s encountering my design without the CSS I\u2019ve written, what should their experience be?\nSo I took a step back, and came up with a different approach:\n<div class=\"teaser\">\n <h1 class=\"article-title\"><a href=\"#\">Article Title</a></h1>\n <h2 class=\"article-byline\">By <a href=\"#\">Author Name</a></h2>\n <p class=\"teaser-excerpt\">\n Lorem ipsum dolor sit amet, consectetur\u2026\n <a class=\"comment-count\" href=\"#\">126 <i>comments</i></a>\n </p>\n</div>\nMuch, much better. This felt like a better match for the content I was designing: the headline \u2013 easily most important element \u2013 was at the top, followed by the author\u2019s name and an excerpt. And while the comment count is visually the most prominent element in the teaser, I decided it was hierarchically the least critical: that\u2019s why it\u2019s at the very end of the excerpt, the last element within our teaser. And with some light styling, we\u2019ve got a respectable-looking hierarchy in place:\n\nYeah, you\u2019re right \u2013 it\u2019s not our final design. But from this basic-looking foundation, we can layer on a bit more complexity. First, we\u2019ll bolster the markup with an extra element around our title and byline:\n<div class=\"teaser\">\n <div class=\"teaser-hed\">\n <h1 class=\"article-title\"><a href=\"#\">Article Title</a></h1>\n <h2 class=\"article-byline\">By <a href=\"#\">Author Name</a></h2>\n </div>\n \u2026\n</div>\nWith that in place, we can use flexbox to tweak our layout, like so:\n.teaser-hed {\n display: flex;\n flex-direction: column-reverse;\n}\nflex-direction: column-reverse acts a bit like a change in gravity within our teaser-hed element, vertically swapping its two children.\n\nGetting closer! But as great as flexbox is, it doesn\u2019t do anything for elements outside our container, like our little comment count, which is, as you\u2019ve probably noticed, still stranded at the very bottom of our teaser.\nFlexbox is, as you might already know, wonderful! And while it enjoys incredibly broad support, there are enough implementations of old versions of Flexbox (in addition to plenty of bugs) that I tend to use a feature test to check if the browser\u2019s using a sufficiently modern version of flexbox. Here\u2019s the one we used:\nvar doc = document.body || document.documentElement;\nvar style = doc.style;\n\nif ( style.webkitFlexWrap == '' ||\n style.msFlexWrap == '' ||\n style.flexWrap == '' ) {\n doc.className += \" supports-flex\";\n}\nEagle-eyed readers will note we could have used @supports feature queries to ask browsers if they support certain CSS properties, removing the JavaScript dependency. But since we wanted to serve the layout to IE we opted to write a little question in JavaScript, asking the browser if it supports flex-wrap, a property used elsewhere in the design. If the browser passes the test, then a class of supports-flex gets applied to our html element. And with that class in place, we can safely quarantine our flexbox-enabled layout from less-capable browsers, and finish our teaser\u2019s design:\n.supports-flex .teaser-hed {\n display: flex;\n flex-direction: column-reverse;\n}\n.supports-flex .teaser .comment-count {\n position: absolute;\n right: 0;\n top: 1.1em;\n}\nIf the supports-flex class is present, we can apply our flexbox layout to the title area, sure \u2013 but we can also safely use absolute positioning to pull our comment count out of its default position, and anchor it to the top right of our teaser. In other words, the browsers that don\u2019t meet our threshold for our advanced styles are left with an attractive design that matches our HTML\u2019s content hierarchy; but the ones that pass our test receive the finished, final design.\n\nAnd with that, our teaser\u2019s complete.\nDiving Into Device-Agnostic Design\nThis is, admittedly, a pretty modest application of flexbox. (For some truly next-level work, I\u2019d recommend Heydon Pickering\u2019s \u201cFlexbox Grid Finesse\u201d, or anything Zoe Mickley Gillenwater publishes.) And for such a simple module, you might feel like this is, well, quite a bit of work. And you\u2019d be right! In fact, it\u2019s not one layout, but two: a lightly styled content hierarchy served to everyone, with the finished design served conditionally to the browsers that can successfully implement it. But I\u2019ve found that thinking about my design as existing in broad experience tiers \u2013 in layers \u2013 is one of the best ways of designing for the modern web. And what\u2019s more, it works not just for simple modules like our teaser, but for more complex or interactive patterns as well.\nOpen video\n \n Even a simple search form can be conditionally enhanced, given a little layered thinking.\n \nThis more layered approach to interface design isn\u2019t a new one, mind you: it\u2019s been championed by everyone from Filament Group to the BBC. And with all the challenges we keep uncovering, a more device-agnostic approach is one of the best ways I\u2019ve found to practice responsive design. As Trent Walton once wrote,\n\nLike cars designed to perform in extreme heat or on icy roads, websites should be built to face the reality of the web\u2019s inherent variability.\n\nWe have a weird job, working on the web. We\u2019re designing for the latest mobile devices, sure, but we\u2019re increasingly aware that our definition of \u201csmartphone\u201d is much too narrow. Browsers have started appearing on our wrists and in our cars\u2019 dashboards, but much of the world\u2019s mobile data flows over sub-3G networks. After all, the web\u2019s evolution has never been charted along a straight line: it\u2019s simultaneously getting slower and faster, with devices new and old coming online every day. With all the challenges in front of us, including many we don\u2019t yet know about, a more device-agnostic, more layered design process can better prepare our patterns \u2013 and ourselves \u2013 for the future.\n(It won\u2019t help you get enough to eat at holiday parties, though.)", "year": "2015", "author": "Ethan Marcotte", "author_slug": "ethanmarcotte", "published": "2015-12-10T00:00:00+00:00", "url": "https://24ways.org/2015/putting-my-patterns-through-their-paces/", "topic": "code"} {"rowid": 55, "title": "How Tabs Should Work", "contents": "Tabs in browsers (not browser tabs) are one of the oldest custom UI elements in a browser that I can think of. They\u2019ve been done to death. But, sadly, most of the time I come across them, the tabs have been badly, or rather partially, implemented.\nSo this post is my definition of how a tabbing system should work, and one approach of implementing that.\nBut\u2026 tabs are easy, right?\nI\u2019ve been writing code for tabbing systems in JavaScript for coming up on a decade, and at one point I was pretty proud of how small I could make the JavaScript for the tabbing system:\nvar tabs = $('.tab').click(function () {\n tabs.hide().filter(this.hash).show();\n}).map(function () {\n return $(this.hash)[0];\n});\n\n$('.tab:first').click();\nSimple, right? Nearly fits in a tweet (ignoring the whole jQuery library\u2026). Still, it\u2019s riddled with problems that make it a far from perfect solution.\nRequirements: what makes the perfect tab?\n\nAll content is navigable and available without JavaScript (crawler-compatible and low JS-compatible).\nARIA roles.\nThe tabs are anchor links that:\n\nare clickable\nhave block layout\nhave their href pointing to the id of the panel element\nuse the correct cursor (i.e. cursor: pointer).\n\nSince tabs are clickable, the user can open in a new tab/window and the page correctly loads with the correct tab open.\nRight-clicking (and Shift-clicking) doesn\u2019t cause the tab to be selected.\nNative browser Back/Forward button correctly changes the state of the selected tab (think about it working exactly as if there were no JavaScript in place).\n\nThe first three points are all to do with the semantics of the markup and how the markup has been styled. I think it\u2019s easy to do a good job by thinking of tabs as links, and not as some part of an application. Links are navigable, and they should work the same way other links on the page work.\nThe last three points are JavaScript problems. Let\u2019s investigate that.\nThe shitmus test\nLike a litmus test, here\u2019s a couple of quick ways you can tell if a tabbing system is poorly implemented:\n\nChange tab, then use the Back button (or keyboard shortcut) and it breaks\nThe tab isn\u2019t a link, so you can\u2019t open it in a new tab\n\nThese two basic things are, to me, the bare minimum that a tabbing system should have.\nWhy is this important?\nThe people who push their so-called native apps on users can\u2019t have more reasons why the web sucks. If something as basic as a tab doesn\u2019t work, obviously there\u2019s more ammo to push a closed native app or platform on your users.\nIf you\u2019re going to be a web developer, one of your responsibilities is to maintain established interactivity paradigms. This doesn\u2019t mean don\u2019t innovate. But it does mean: stop fucking up my scrolling experience with your poorly executed scroll effects. </rant> :breath:\nURI fragment, absolute URL or query string?\nA URI fragment (AKA the # hash bit) would be using mysite.com/config#content to show the content panel. A fully addressable URL would be mysite.com/config/content. Using a query string (by way of filtering the page): mysite.com/config?tab=content.\nThis decision really depends on the context of your tabbing system. For something like GitHub\u2019s tabs to view a pull request, it makes sense that the full URL changes.\nFor our problem though, I want to solve the issue when the page doesn\u2019t do a full URL update; that is, your regular run-of-the-mill tabbing system.\nI used to be from the school of using the hash to show the correct tab, but I\u2019ve recently been exploring whether the query string can be used. The biggest reason is that multiple hashes don\u2019t work, and comma-separated hash fragments don\u2019t make any sense to control multiple tabs (since it doesn\u2019t actually link to anything).\nFor this article, I\u2019ll keep focused on using a single tabbing system and a hash on the URL to control the tabs.\nMarkup\nI\u2019m going to assume subcontent, so my markup would look like this (yes, this is a cat demo\u2026):\n<ul class=\"tabs\">\n <li><a class=\"tab\" href=\"#dizzy\">Dizzy</a></li>\n <li><a class=\"tab\" href=\"#ninja\">Ninja</a></li>\n <li><a class=\"tab\" href=\"#missy\">Missy</a></li>\n</ul>\n\n<div id=\"dizzy\">\n <!-- panel content -->\n</div>\n<div id=\"ninja\">\n <!-- panel content -->\n</div>\n<div id=\"missy\">\n <!-- panel content -->\n</div>\nIt\u2019s important to note that in the markup the link used for an individual tab references its panel content using the hash, pointing to the id on the panel. This will allow our content to connect up without JavaScript and give us a bunch of features for free, which we\u2019ll see once we\u2019re on to writing the code.\nURL-driven tabbing systems\nInstead of making the code responsive to the user\u2019s input, we\u2019re going to exclusively use the browser URL and the hashchange event on the window to drive this tabbing system. This way we get Back button support for free.\nWith that in mind, let\u2019s start building up our code. I\u2019ll assume we have the jQuery library, but I\u2019ve also provided the full code working without a library (vanilla, if you will), but it depends on relatively new (polyfillable) tech like classList and dataset (which generally have IE10 and all other browser support).\nNote that I\u2019ll start with the simplest solution, and I\u2019ll refactor the code as I go along, like in places where I keep calling jQuery selectors.\nfunction show(id) {\n // remove the selected class from the tabs,\n // and add it back to the one the user selected\n $('.tab').removeClass('selected').filter(function () {\n return (this.hash === id);\n }).addClass('selected');\n\n // now hide all the panels, then filter to\n // the one we're interested in, and show it\n $('.panel').hide().filter(id).show();\n}\n\n$(window).on('hashchange', function () {\n show(location.hash);\n});\n\n// initialise by showing the first panel\nshow('#dizzy');\nThis works pretty well for such little code. Notice that we don\u2019t have any click handlers for the user and the Back button works right out of the box.\nHowever, there\u2019s a number of problems we need to fix:\n\nThe initialised tab is hard-coded to the first panel, rather than what\u2019s on the URL.\nIf there\u2019s no hash on the URL, all the panels are hidden (and thus broken).\nIf you scroll to the bottom of the example, you\u2019ll find a \u201ctop\u201d link; clicking that will break our tabbing system.\nI\u2019ve purposely made the page long, so that when you click on a tab, you\u2019ll see the page scrolls to the top of the tab. Not a huge deal, but a bit annoying.\n\nFrom our criteria at the start of this post, we\u2019ve already solved items 4 and 5. Not a terrible start. Let\u2019s solve items 1 through 3 next.\nUsing the URL to initialise correctly and protect from breakage\nInstead of arbitrarily picking the first panel from our collection, the code should read the current location.hash and use that if it\u2019s available.\nThe problem is: what if the hash on the URL isn\u2019t actually for a tab?\nThe solution here is that we need to cache a list of known panel IDs. In fact, well-written DOM scripting won\u2019t continuously search the DOM for nodes. That is, when the show function kept calling $('.tab').each(...) it was wasteful. The result of $('.tab') should be cached.\nSo now the code will collect all the tabs, then find the related panels from those tabs, and we\u2019ll use that list to double the values we give the show function (during initialisation, for instance).\n// collect all the tabs\nvar tabs = $('.tab');\n\n// get an array of the panel ids (from the anchor hash)\nvar targets = tabs.map(function () {\n return this.hash;\n}).get();\n\n// use those ids to get a jQuery collection of panels\nvar panels = $(targets.join(','));\n\nfunction show(id) {\n // if no value was given, let's take the first panel\n if (!id) {\n id = targets[0];\n }\n // remove the selected class from the tabs,\n // and add it back to the one the user selected\n tabs.removeClass('selected').filter(function () {\n return (this.hash === id);\n }).addClass('selected');\n\n // now hide all the panels, then filter to\n // the one we're interested in, and show it\n panels.hide().filter(id).show();\n}\n\n$(window).on('hashchange', function () {\n var hash = location.hash;\n if (targets.indexOf(hash) !== -1) {\n show(hash);\n }\n});\n\n// initialise\nshow(targets.indexOf(location.hash) !== -1 ? location.hash : '');\nThe core of working out which tab to initialise with is solved in that last line: is there a location.hash? Is it in our list of valid targets (panels)? If so, select that tab.\nThe second breakage we saw in the original demo was that clicking the \u201ctop\u201d link would break our tabs. This was due to the hashchange event firing and the code didn\u2019t validate the hash that was passed. Now this happens, the panels don\u2019t break.\nSo far we\u2019ve got a tabbing system that:\n\nWorks without JavaScript.\nSupports right-click and Shift-click (and doesn\u2019t select in these cases).\nLoads the correct panel if you start with a hash.\nSupports native browser navigation.\nSupports the keyboard.\n\nThe only annoying problem we have now is that the page jumps when a tab is selected. That\u2019s due to the browser following the default behaviour of an internal link on the page. To solve this, things are going to get a little hairy, but it\u2019s all for a good cause.\nRemoving the jump to tab\nYou\u2019d be forgiven for thinking you just need to hook a click handler and return false. It\u2019s what I started with. Only that\u2019s not the solution. If we add the click handler, it breaks all the right-click and Shift-click support.\nThere may be another way to solve this, but what follows is the way I found \u2013 and it works. It\u2019s just a bit\u2026 hairy, as I said.\nWe\u2019re going to strip the id attribute off the target panel when the user tries to navigate to it, and then put it back on once the show code starts to run. This change will mean the browser has nowhere to navigate to for that moment, and won\u2019t jump the page.\nThe change involves the following:\n\nAdd a click handle that removes the id from the target panel, and cache this in a target variable that we\u2019ll use later in hashchange (see point 4).\nIn the same click handler, set the location.hash to the current link\u2019s hash. This is important because it forces a hashchange event regardless of whether the URL actually changed, which prevents the tabs breaking (try it yourself by removing this line).\nFor each panel, put a backup copy of the id attribute in a data property (I\u2019ve called it old-id).\nWhen the hashchange event fires, if we have a target value, let\u2019s put the id back on the panel.\n\nThese changes result in this final code:\n/*global $*/\n\n// a temp value to cache *what* we're about to show\nvar target = null;\n\n// collect all the tabs\nvar tabs = $('.tab').on('click', function () {\n target = $(this.hash).removeAttr('id');\n\n // if the URL isn't going to change, then hashchange\n // event doesn't fire, so we trigger the update manually\n if (location.hash === this.hash) {\n // but this has to happen after the DOM update has\n // completed, so we wrap it in a setTimeout 0\n setTimeout(update, 0);\n }\n});\n\n// get an array of the panel ids (from the anchor hash)\nvar targets = tabs.map(function () {\n return this.hash;\n}).get();\n\n// use those ids to get a jQuery collection of panels\nvar panels = $(targets.join(',')).each(function () {\n // keep a copy of what the original el.id was\n $(this).data('old-id', this.id);\n});\n\nfunction update() {\n if (target) {\n target.attr('id', target.data('old-id'));\n target = null;\n }\n\n var hash = window.location.hash;\n if (targets.indexOf(hash) !== -1) {\n show(hash);\n }\n}\n\nfunction show(id) {\n // if no value was given, let's take the first panel\n if (!id) {\n id = targets[0];\n }\n // remove the selected class from the tabs,\n // and add it back to the one the user selected\n tabs.removeClass('selected').filter(function () {\n return (this.hash === id);\n }).addClass('selected');\n\n // now hide all the panels, then filter to\n // the one we're interested in, and show it\n panels.hide().filter(id).show();\n}\n\n$(window).on('hashchange', update);\n\n// initialise\nif (targets.indexOf(window.location.hash) !== -1) {\n update();\n} else {\n show();\n}\nThis version now meets all the criteria I mentioned in my original list, except for the ARIA roles and accessibility. Getting this support is actually very cheap to add.\nARIA roles\nThis article on ARIA tabs made it very easy to get the tabbing system working as I wanted.\nThe tasks were simple:\n\nAdd aria-role set to tab for the tabs, and tabpanel for the panels.\nSet aria-controls on the tabs to point to their related panel (by id).\nI use JavaScript to add tabindex=0 to all the tab elements.\nWhen I add the selected class to the tab, I also set aria-selected to true and, inversely, when I remove the selected class I set aria-selected to false.\nWhen I hide the panels I add aria-hidden=true, and when I show the specific panel I set aria-hidden=false.\n\nAnd that\u2019s it. Very small changes to get full sign-off that the tabbing system is bulletproof and accessible.\nCheck out the final version (and the non-jQuery version as promised).\nIn conclusion\nThere\u2019s a lot of tab implementations out there, but there\u2019s an equal amount that break the browsing paradigm and the simple linkability of content. Clearly there\u2019s a special hell for those tab systems that don\u2019t even use links, but I think it\u2019s clear that even in something that\u2019s relatively simple, it\u2019s the small details that make or break the user experience.\nObviously there are corners I\u2019ve not explored, like when there\u2019s more than one set of tabs on a page, and equally whether you should deliver the initial markup with the correct tab selected. I think the answer lies in using query strings in combination with hashes on the URL, but maybe that\u2019s for another year!", "year": "2015", "author": "Remy Sharp", "author_slug": "remysharp", "published": "2015-12-22T00:00:00+00:00", "url": "https://24ways.org/2015/how-tabs-should-work/", "topic": "code"} {"rowid": 63, "title": "Be Fluid with Your Design Skills: Build Your Own Sites", "contents": "Just five years ago in 2010, when we were all busy trying to surprise and delight, learning CSS3 and trying to get whole websites onto one page, we had a poster on our studio wall. It was entitled \u2018Designers Vs Developers\u2019, an infographic that showed us the differences between the men(!) who created websites. \nDesigners wore skinny jeans and used Macs and developers wore cargo pants and brought their own keyboards to work. We began to learn that designers and developers were not only doing completely different jobs but were completely different people in every way. This opinion was backed up by hundreds of memes, millions of tweets and pages of articles which used words like void and battle and versus.\nThankfully, things move quickly in this industry; the wide world of web design has moved on in the last five years. There are new devices, technologies, tools \u2013 and even a few women. Designers have been helped along by great apps, software, open source projects, conferences, and a community of people who, to my unending pride, love to share their knowledge and their work.\nSo the world has moved on, and if Miley Cyrus, Ruby Rose and Eliot Sumner are identifying as gender fluid (an identity which refers to a gender which varies over time or is a combination of identities), then I would like to come out as discipline fluid! \nOK, I will probably never identify as a developer, but I will identify as fluid! How can we be anything else in an industry that moves so quickly? That\u2019s how we should think of our skills, our interests and even our job titles. After all, Steve Jobs told us that \u201cDesign is not just what it looks like and feels like. Design is how it works.\u201d Sorry skinny-jean-wearing designers \u2013 this means we\u2019re all designing something together. And it\u2019s not just about knowing the right words to use: you have to know how it feels. How it feels when you make something work, when you fix that bug, when you make it work on IE.\nLike anything in life, things run smoothly when you make the effort to share experiences, empathise and deeply understand the needs of others. How can designers do that if they\u2019ve never built their own site? I\u2019m not talking the big stuff, I\u2019m talking about your portfolio site, your mate\u2019s business website, a website for that great idea you\u2019ve had. I\u2019m talking about doing it yourself to get an unique insight into how it feels.\nWe all know that designers and developers alike love an <ol>, so here it is.\nTen reasons designers should be fluid with their skills and build their own sites\n1. It\u2019s never been easier\nNow here\u2019s where the definition of \u2018build\u2019 is going to get a bit loose and people are going to get angry, but when I say it\u2019s never been easier I mean because of the existence of apps and software like WordPress, Squarespace, Tumblr, et al. It\u2019s easy to make something and get it out there into the world, and these are all gateway drugs to hard coding!\n2. You\u2019ll understand how it feels\nHow it feels to be so proud that something actually works that you momentarily don\u2019t notice if the kerning is off or the padding is inconsistent. How it feels to see your site appear when you\u2019ve redirected a URL. How it feels when you just can\u2019t work out where that one extra space is in a line of PHP that has killed your whole site.\n3. It makes you a designer\nNot a better designer, it makes you a designer when you are designing how things look and how they work. \n4. You learn about movement\nPhotoshop and Sketch just don\u2019t cut it yet. Until you see your site in a browser or your app on a phone, it\u2019s hard to imagine how it moves. Building your own sites shows you that it\u2019s not just about how the content looks on the screen, but how it moves, interacts and feels.\n5. You make techie friends\nAll the tutorials and forums in the world can\u2019t beat your network of techie friends. Since I started working in web design I have worked with, sat next to, and co-created with some of the greatest developers. Developers who\u2019ve shared their knowledge, encouraged me to build things, patiently explained HTML, CSS, servers, divs, web fonts, iOS development. There has been no void, no versus, very few battles; just people who share an interest and love of making things. \n6. You will own domain names\nWhen something is paid for, online and searchable then it\u2019s real and you\u2019ve got to put the work in. Buying domains has taught me how to stop procrastinating, but also about DNS, FTP, email, and how servers work.\n7. People will ask you to do things\u2028\nLearning about code and development opens a whole new world of design. When you put your own personal websites and projects out there people ask you to do more things. OK, so sometimes those things are \u201cMake me a website for free\u201d, but more often it\u2019s cool things like \u201cCome and speak at my conference\u201d, \u201cWrite an article for my magazine\u201d and \u201cCollaborate with me.\u201d\n8. The young people are coming!\nThey love typography, they love print, they love layout, but they\u2019ve known how to put a website together since they started their first blog aged five and they show me clever apps they\u2019ve knocked together over the weekend! They\u2019re new, they\u2019re fluid, and they\u2019re better than us!\n9. Your portfolio is your portfolio\nOK, it\u2019s an obvious one, but as designers our work is our CV, our legacy! We need to show our skill, our attention to detail and our creativity in the way we showcase our work. Building your portfolio is the best way to start building your own websites. (And please be that designer who\u2019s bothered to work out how to change the Squarespace favicon!) \n10. It keeps you fluid!\nBuilding your own websites is tough. You\u2019ll never be happy with it, you\u2019ll constantly be updating it to keep up with technology and fashion, and by the time you\u2019ve finished it you\u2019ll want to start all over again. Perfect for forcing you to stay up-to-date with what\u2019s going on in the industry.\n</ol>", "year": "2015", "author": "Ros Horner", "author_slug": "roshorner", "published": "2015-12-12T00:00:00+00:00", "url": "https://24ways.org/2015/be-fluid-with-your-design-skills-build-your-own-sites/", "topic": "code"} {"rowid": 64, "title": "Being Responsive to the Small Things", "contents": "It\u2019s that time of the year again to trim the tree with decorations. Or maybe a DOM tree?\nAny web page is made of HTML elements that lay themselves out in a tree structure. We start at the top and then have multiple branches with branches that branch out from there. \n\nTo decorate our tree, we use CSS to specify which branches should receive the tinsel we wish to adorn upon it. It\u2019s all so lovely.\nIn years past, this was rather straightforward. But these days, our trees need to be versatile. They need to be responsive!\nResponsive web design is pretty wonderful, isn\u2019t it? Based on our viewport, we can decide how elements on the page should change their appearance to accommodate various constraints using media queries.\nClearleft have a delightfully clean and responsive site\nAlas, it\u2019s not all sunshine, lollipops, and rainbows. \nWith complex layouts, we may have design chunks \u2014 let\u2019s call them components \u2014 that appear in different contexts. Each context may end up providing its own constraints on the design, both in its default state and in its possibly various responsive states.\n\nMedia queries, however, limit us to the context of the entire viewport, not individual containers on the page. For every container our component lives in, we need to specify how to rearrange things in that context. The more complex the system, the more contexts we need to write code for.\n@media (min-width: 800px) {\n .features > .component { }\n .sidebar > .component {}\n .grid > .component {}\n}\nEach new component and each new breakpoint just makes the entire system that much more difficult to maintain. \n@media (min-width: 600px) {\n .features > .component { }\n .grid > .component {}\n}\n\n@media (min-width: 800px) {\n .features > .component { }\n .sidebar > .component {}\n .grid > .component {}\n}\n\n@media (min-width: 1024px) {\n .features > .component { }\n}\nEnter container queries\nContainer queries, also known as element queries, allow you to specify conditional CSS based on the width (or maybe height) of the container that an element lives in. In doing so, you no longer have to consider the entire page and the interplay of all the elements within. \nWith container queries, you\u2019ll be able to consider the breakpoints of just the component you\u2019re designing. As a result, you end up specifying less code and the components you develop have fewer dependencies on the things around them. (I guess that makes your components more independent.)\nAwesome, right?\nThere\u2019s only one catch.\nBrowsers can\u2019t do container queries. There\u2019s not even an official specification for them yet. The Responsive Issues (n\u00e9e Images) Community Group is looking into solving how such a thing would actually work. \nSee, container queries are tricky from an implementation perspective. The contents of a container can affect the size of the container. Because of this, you end up with troublesome circular references. \nFor example, if the width of the container is under 500px then the width of the child element should be 600px, and if the width of the container is over 500px then the width of the child element should be 400px. \nCan you see the dilemma? When the container is under 500px, the child element resizes to 600px and suddenly the container is 600px. If the container is 600px, then the child element is 400px! And so on, forever. This is bad.\nI guess we should all just go home and sulk about how we just got a pile of socks when we really wanted the Millennium Falcon. \nOur saviour this Christmas: JavaScript\nThe three wise men \u2014 Tim Berners-Lee, H\u00e5kon Wium Lie, and Brendan Eich \u2014 brought us the gifts of HTML, CSS, and JavaScript. \nTo date, there are a handful of open source solutions to fill the gap until a browser implementation sees the light of day.\n\nElementary by Scott Jehl\nElementQuery by Tyson Matanich\nEQ.js by Sam Richards\nCSS Element Queries from Marcj\n\nUsing any of these can sometimes feel like your toy broke within ten minutes of unwrapping it.\nEach take their own approach on how to specify the query conditions. For example, Elementary, the smallest of the group, only supports min-width declarations made in a :before selector.\n.mod-foo:before {\n content: \u201c300 410 500\u201d;\n}\nThe script loops through all the elements that you specify, reading the content property and then setting an attribute value on the HTML element, allowing you to use CSS to style that condition. \n.mod-foo[data-minwidth~=\"300\"] {\n background: blue;\n}\nTo get the script to run, you\u2019ll need to set up event handlers for when the page loads and for when it resizes. \nwindow.addEventListener( \"load\", window.elementary, false );\nwindow.addEventListener( \"resize\", window.elementary, false );\nThis works okay for static sites but breaks down on pages where elements can expand or contract, or where new content is dynamically inserted.\nIn the case of EQ.js, the implementation requires the creation of the breakpoints in the HTML. That means that you have implementation details in HTML, JavaScript, and CSS. (Although, with the JavaScript, once it\u2019s in the build system, it shouldn\u2019t ever be much of a concern unless you\u2019re tracking down a bug.)\nAnother problem you may run into is the use of content delivery networks (CDNs) or cross-origin security issues. The ElementQuery and CSS Element Queries libraries need to be able to read the CSS file. If you are unable to set up proper cross-origin resource sharing (CORS) headers, these libraries won\u2019t help.\nAt Shopify, for example, we had all of these problems. The admin that store owners use is very dynamic and the CSS and JavaScript were being loaded from a CDN that prevented the JavaScript from reading the CSS. \nTo go responsive, the team built their own solution \u2014 one similar to the other scripts above, in that it loops through elements and adds or removes classes (instead of data attributes) based on minimum or maximum width.\nThe caveat to this particular approach is that the declaration of breakpoints had to be done in JavaScript. \n elements = [\n { \u2018module\u2019: \u201c.carousel\u201d, \u201cclassName\u201d:\u2019alpha\u2019, minWidth: 768, maxWidth: 1024 },\n { \u2018module\u2019: \u201c.button\u201d, \u201cclassName\u201d:\u2019beta\u2019, minWidth: 768, maxWidth: 1024 } ,\n { \u2018module\u2019: \u201c.grid\u201d, \u201cclassName\u201d:\u2019cappa\u2019, minWidth: 768, maxWidth: 1024 }\n ]\nWith that done, the script then had to be set to run during various events such as inserting new content via Ajax calls. This sometimes reveals itself in flashes of unstyled breakpoints (FOUB). An unfortunate side effect but one largely imperceptible.\nUsing this approach, however, allowed the Shopify team to make the admin responsive really quickly. Each member of the team was able to tackle the responsive story for a particular component without much concern for how all the other components would react. \n\nEach element responds to its own breakpoint that would amount to dozens of breakpoints using traditional breakpoints. This approach allows for a truly fluid and adaptive interface for all screens.\nChristmas is over\nI wish I were the bearer of greater tidings and cheer. It\u2019s not all bad, though. We may one day see browsers implement container queries natively. At which point, we shall all rejoice!", "year": "2015", "author": "Jonathan Snook", "author_slug": "jonathansnook", "published": "2015-12-19T00:00:00+00:00", "url": "https://24ways.org/2015/being-responsive-to-the-small-things/", "topic": "code"} {"rowid": 65, "title": "The Accessibility Mindset", "contents": "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.\nIndeed, it is an additional skill set to acquire, quite like learning new JavaScript frameworks, CSS layout techniques or new HTML elements. But it isn\u2019t particularly harder to learn than those other skills.\nA World Health Organization (WHO) report on disabilities states that,\n\n[i]ncluding children, over a billion people (or about 15% of the world\u2019s population) were estimated to be living with disability.\n\nBeing 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.\nAccessibility 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\u2019 needs when they are built in an accessible fashion.\nBeyond the bare minimum\nIn the time of table layouts, web developers could create code that passed validation rules but didn\u2019t 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\u2019t do is measure how well you met them. \nW3C 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.\nThe 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:\nOpen video\n \nThe 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:\nOpen video\n \nThe 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:\nOpen video\n \nYou can also set the label to display:block; to further increase the clickable area:\nOpen video\n \nAnd while we\u2019re at it, users might expect the whole box to be clickable anyway. Let\u2019s apply the CSS that was on a wrapping div element to the label directly:\nOpen video\n \nThe 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.\n<form action=\"#\"> \n <label for=\"uniquecheckboxid\">\n <input type=\"checkbox\" name=\"checkbox\" id=\"uniquecheckboxid\" />\n Checkbox 4\n </label>\n</form> \nButton Example\nThe 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 \u201cbutton\u201d without any indication of what this button is for.\nOpen video\n A screen reader announcing a button. Contains audio.\nThe code snippet shows why the button is not properly announced:\n<button>\n <span class=\"icon icon-pencil\"></span>\n</button>\nAn icon font is used to display the icon and no text alternative is given. A possible solution to this problem is to use the title or aria-label attributes, which solves the alternative text use case for screen reader users:\nOpen video\n A screen reader announcing a button with a title.\nHowever, screen readers are not the only way people with and without disabilities interact with websites. For example, users can reset or change font families and sizes at will. This helps many users make websites easier to read, including people with dyslexia. Your icon font might be replaced by a font that doesn\u2019t include the glyphs that are icons. Additionally, the icon font may not load for users on slow connections, like on mobile phones inside trains, or because users decided to block external fonts altogether. The following screenshots show the mobile GitHub view with and without external fonts:\nThe mobile GitHub view with and without external fonts.\nEven if the title/aria-label approach was used, the lack of visual labels is a barrier for most people under those circumstances. One way to tackle this is using the old-fashioned img element with an appropriate alt attribute, but surprisingly not every browser displays the alternative text visually when the image doesn\u2019t load.\n<button>\n <img src=\"icon-pencil.svg\" alt=\"Edit\">\n</button>\nProviding always visible text is an alternative that can work well if you have the space. It also helps users understand the meaning of the icons.\n<button>\n <span class=\"icon icon-pencil\"></span> Edit\n</button>\nThis also reads just fine in screen readers:\nOpen video\n A screen reader announcing the revised button.\nClever usability enhancements don\u2019t stop at a technical implementation level. Take the BBC iPlayer pages as an example: when a user navigates the \u201ccaptioned videos\u201d or \u201caudio description\u201d categories and clicks on one of the videos, captions or audio descriptions are automatically switched on. Small things like this enhance the usability and don\u2019t need a lot of engineering resources. It is more about connecting the usability dots for people with disabilities. Read more about the BBC iPlayer accessibility case study.\nMore information\nW3C has created several documents that make it easier to get the gist of what web accessibility is and how it can benefit everyone. You can find out \u201cHow People with Disabilities Use the Web\u201d, there are \u201cTips for Getting Started\u201d for developers, designers and content writers. And for the more seasoned developer there is a set of tutorials on web accessibility, including information on crafting accessible forms and how to use images in an accessible way.\nConclusion\nYou can only produce a web project with long-lasting accessibility if accessibility is not an afterthought. Your organization, your division, your team need to think about accessibility as something that is the foundation of your website or project. It needs to be at the same level as performance, code quality and design, and it needs the same attention. Users often don\u2019t notice when those fundamental aspects of good website design and development are done right. But they\u2019ll always know when they are implemented poorly.\nIf you take all this into consideration, you can create accessibility solutions based on the available data and bring accessibility to people who didn\u2019t know they\u2019d need it:\nOpen video\n \nIn this video from the latest Apple keynote, the Apple TV is operated by voice input through a remote. When the user asks \u201cWhat did she say?\u201d the video jumps back fifteen seconds and captions are switched on for a brief time. All three, the remote, voice input and captions have their roots in assisting people with disabilities. Now they benefit everyone.", "year": "2015", "author": "Eric Eggert", "author_slug": "ericeggert", "published": "2015-12-17T00:00:00+00:00", "url": "https://24ways.org/2015/the-accessibility-mindset/", "topic": "code"} {"rowid": 68, "title": "Grid, Flexbox, Box Alignment: Our New System for Layout", "contents": "Three years ago for 24 ways 2012, I wrote an article about a new CSS layout method I was excited about. A specification had emerged, developed by people from the Internet Explorer team, bringing us a proper grid system for the web. In 2015, that Internet Explorer implementation is still the only public implementation of CSS grid layout. However, in 2016 we should be seeing it in a new improved form ready for our use in browsers.\nGrid layout has developed hidden behind a flag in Blink, and in nightly builds of WebKit and, latterly, Firefox. By being developed in this way, breaking changes could be safely made to the specification as no one was relying on the experimental implementations in production work.\nAnother new layout method has emerged over the past few years in a more public and perhaps more painful way. Shipped prefixed in browsers, The flexible box layout module (flexbox) was far too tempting for developers not to use on production sites. Therefore, as changes were made to the specification, we found ourselves with three different flexboxes, and browser implementations that did not match one another in completeness or in the version of specified features they supported. \nOwing to the different ways these modules have come into being, when I present on grid layout it is often the very first time someone has heard of the specification. A question I keep being asked is whether CSS grid layout and flexbox are competing layout systems, as though it might be possible to back the loser in a CSS layout competition. The reality, however, is that these two methods will sit together as one system for doing layout on the web, each method playing to certain strengths and serving particular layout tasks. \nIf there is to be a loser in the battle of the layouts, my hope is that it will be the layout frameworks that tie our design to our markup. They have been a necessary placeholder while we waited for a true web layout system, but I believe that in a few years time we\u2019ll be easily able to date a website to circa 2015 by seeing <div class=\"row\"> or <div class=\"col-md-3\"> in the markup.\nIn this article, I\u2019m going to take a look at the common features of our new layout systems, along with a couple of examples which serve to highlight the differences between them.\nTo see the grid layout examples you will need to enable grid in your browser. The easiest thing to do is to enable the experimental web platform features flag in Chrome. Details of current browser support can be found here. \nRelationship\nItems only become flex or grid items if they are a direct child of the element that has display:flex, display:grid or display:inline-grid applied. Those direct children then understand themselves in the context of the complete layout. This makes many things possible. It\u2019s the lack of relationship between elements that makes our existing layout methods difficult to use. If we float two columns, left and right, we have no way to tell the shorter column to extend to the height of the taller one. We have expended a lot of effort trying to figure out the best way to make full-height columns work, using techniques that were never really designed for page layout.\nAt a very simple level, the relationship between elements means that we can easily achieve full-height columns. In flexbox:\nSee the Pen Flexbox equal height columns by rachelandrew (@rachelandrew) on CodePen.\n\nAnd in grid layout (requires a CSS grid-supporting browser):\nSee the Pen Grid equal height columns by rachelandrew (@rachelandrew) on CodePen.\n\nAlignment\nFull-height columns rely on our flex and grid items understanding themselves as part of an overall layout. They also draw on a third new specification: the box alignment module. If vertical centring is a gift you\u2019d like to have under your tree this Christmas, then this is the box you\u2019ll want to unwrap first.\nThe box alignment module takes the alignment and space distribution properties from flexbox and applies them to other layout methods. That includes grid layout, but also other layout methods. Once implemented in browsers, this specification will give us true vertical centring of all the things.\nOur examples above achieved full-height columns because the default value of align-items is stretch. The value ensured our columns stretched to the height of the tallest. If we want to use our new vertical centring abilities on all items, we would set align-items:center on the container. To align one flex or grid item, apply the align-self property.\nThe examples below demonstrate these alignment properties in both grid layout and flexbox. The portrait image of Widget the cat is aligned with the default stretch. The other three images are aligned using different values of align-self.\nTake a look at an example in flexbox:\nSee the Pen Flexbox alignment by rachelandrew (@rachelandrew) on CodePen.\n\nAnd also in grid layout (requires a CSS grid-supporting browser):\nSee the Pen Grid alignment by rachelandrew (@rachelandrew) on CodePen.\n\nThe alignment properties used with CSS grid layout.\nFluid grids\nA cornerstone of responsive design is the concept of fluid grids.\n\n\u201c[\u2026]every aspect of the grid\u2014and the elements laid upon it\u2014can be expressed as a proportion relative to its container.\u201d\n\u2014Ethan Marcotte, \u201cFluid Grids\u201d\n\nThe method outlined by Marcotte is to divide the target width by the context, then use that value as a percentage value for the width property on our element.\nh1 {\n margin-left: 14.575%; /*\u00a0144px / 988px = 0.14575\u00a0*/\n width: 70.85%; /*\u00a0700px / 988px = 0.7085\u00a0*/\n}\nIn more recent years, we\u2019ve been able to use calc() to simplify this (at least, for those of us able to drop support for Internet Explorer 8). However, flexbox and grid layout make fluid grids simple.\nThe most basic of flexbox demos shows this fluidity in action. The justify-content property \u2013 another property defined in the box alignment module \u2013 can be used to create an equal amount of space between or around items. As the available width increases, more space is assigned in proportion.\nIn this demo, the list items are flex items due to display:flex being added to the ul. I have given them a maximum width of 250 pixels. Any remaining space is distributed equally between the items as the justify-content property has a value of space-between.\nSee the Pen Flexbox: justify-content by rachelandrew (@rachelandrew) on CodePen.\n\nFor true fluid grid-like behaviour, your new flexible friends are flex-grow and flex-shrink. These properties give us the ability to assign space in proportion.\nThe flexbox flex property is a shorthand for:\n\nflex-grow\nflex-shrink\nflex-basis\n\nThe flex-basis property sets the default width for an item. If flex-grow is set to 0, then the item will not grow larger than the flex-basis value; if flex-shrink is 0, the item will not shrink smaller than the flex-basis value.\n\nflex: 1 1 200px: a flexible box that can grow and shrink from a 200px basis.\nflex: 0 0 200px: a box that will be 200px and cannot grow or shrink.\nflex: 1 0 200px: a box that can grow bigger than 200px, but not shrink smaller.\n\nIn this example, I have a set of boxes that can all grow and shrink equally from a 100 pixel basis.\nSee the Pen Flexbox: flex-grow by rachelandrew (@rachelandrew) on CodePen.\n\nWhat I would like to happen is for the first element, containing a portrait image, to take up less width than the landscape images, thus keeping it more in proportion. I can do this by changing the flex-grow value. By giving all the items a value of 1, they all gain an equal amount of the available space after the 100 pixel basis has been worked out.\nIf I give them all a value of 3 and the first box a value of 1, the other boxes will be assigned three parts of the available space while box 1 is assigned only one part. You can see what happens in this demo:\nSee the Pen Flexbox: flex-grow by rachelandrew (@rachelandrew) on CodePen.\n\nOnce you understand flex-grow, you should easily be able to grasp how the new fraction unit (fr, defined in the CSS grid layout specification) works. Like flex-grow, this unit allows us to assign available space in proportion. In this case, we assign the space when defining our track sizes.\nIn this demo (which requires a CSS grid-supporting browser), I create a four-column grid using the fraction unit to define my track sizes. The first track is 1fr in width, and the others 2fr.\ngrid-template-columns: 1fr 2fr 2fr 2fr;\nSee the Pen Grid fraction units by rachelandrew (@rachelandrew) on CodePen.\n\nThe four-track grid.\nSeparation of concerns\nMy younger self petitioned my peers to stop using tables for layout and to move to CSS. One of the rallying cries of that movement was the concept of separating our source and content from how they were displayed. It was something of a failed promise given the tools we had available: the display leaked into the markup with the need for redundant elements to cope with browser bugs, or visual techniques that just could not be achieved without supporting markup.\nBrowsers have improved, but even now we can find ourselves compromising the ideal document structure so we can get the layout we want at various breakpoints. In some ways, the situation has returned to tables-for-layout days. Many of the current grid frameworks rely on describing our layout directly in the markup. We add divs for rows, and classes to describe the number of desired columns. We nest these constructions of divs inside one another.\nHere is a snippet from the Bootstrap grid examples \u2013 two columns with two nested columns:\n<div class=\"row\">\n <div class=\"col-md-8\">\n .col-md-8\n <div class=\"row\">\n <div class=\"col-md-6\">\n .col-md-6\n </div>\n <div class=\"col-md-6\">\n .col-md-6\n </div>\n </div>\n </div>\n <div class=\"col-md-4\">\n .col-md-4\n </div>\n</div>\nNot a million miles away from something I might have written in 1999.\n<table>\n <tr>\n <td class=\"col-md-8\">\n .col-md-8\n <table>\n <tr>\n <td class=\"col-md-6\">\n .col-md-6\n </td>\n <td class=\"col-md-6\">\n .col-md-6\n </td>\n </tr>\n </table>\n </td>\n <td class=\"col-md-4\">\n .col-md-4\n </td>\n </tr>\n</table>\nGrid and flexbox layouts do not need to be described in markup. The layout description happens entirely in the CSS, meaning that elements can be moved around from within the presentation layer.\nFlexbox gives us the ability to reverse the flow of elements, but also to set the order of elements with the order property. This is demonstrated here, where Widget the cat is in position 1 in the source, but I have used the order property to display him after the things that are currently unimpressive to him.\nSee the Pen Flexbox: order by rachelandrew (@rachelandrew) on CodePen.\n\nGrid layout takes this a step further. Where flexbox lets us set the order of items in a single dimension, grid layout gives us the ability to position things in two dimensions: both rows and columns. Defined in the CSS, this positioning can be changed at any breakpoint without needing additional markup. Compare the source order with the display order in this example (requires a CSS grid-supporting browser):\nSee the Pen Grid positioning in two dimensions by rachelandrew (@rachelandrew) on CodePen.\n\nLaying out our items in two dimensions using grid layout.\nAs these demos show, a straightforward way to decide if you should use grid layout or flexbox is whether you want to position items in one dimension or two. If two, you want grid layout.\nA note on accessibility and reordering\nThe issues arising from this powerful ability to change the way items are ordered visually from how they appear in the source have been the subject of much discussion. The current flexbox editor\u2019s draft states\n\n\u201cAuthors must use order only for visual, not logical, reordering of content. Style sheets that use order to perform logical reordering are non-conforming.\u201d\n\u2014CSS Flexible Box Layout Module Level 1, Editor\u2019s Draft (3 December 2015)\n\nThis is to ensure that non-visual user agents (a screen reader, for example) can rely on the document source order as being correct. Take care when reordering that you do so from the basis of a sound document that makes sense in terms of source order. Avoid using visual order to convey meaning.\nAutomatic content placement with rules\nHaving control over the order of items, or placing items on a predefined grid, is nice. However, we can often do that already with one method or another and we have frameworks and tools to help us. Tools such as Susy mean we can even get away from stuffing our markup full of grid classes. However, our new layout methods give us some interesting new possibilities.\nSomething that is useful to be able to do when dealing with content coming out of a CMS or being pulled from some other source, is to define a bunch of rules and then say, \u201cDisplay this content, using these rules.\u201d\nAs an example of this, I will leave you with a Christmas poem displayed in a document alongside Widget the cat and some of the decorations that are bringing him no Christmas cheer whatsoever.\nThe poem is displayed first in the source as a set of paragraphs. I\u2019ve added a class identifying each of the four paragraphs but they are displayed in the source as one text. Below that are all my images, some landscape and some portrait; I\u2019ve added a class of landscape to the landscape ones.\nThe mobile-first grid is a single column and I use line-based placement to explicitly position my poem paragraphs. The grid layout auto-placement rules then take over and place the images into the empty cells left in the grid.\nAt wider screen widths, I declare a four-track grid, and position my poem around the grid, keeping it in a readable order.\nI also add rules to my landscape class, stating that these items should span two tracks. Once again the grid layout auto-placement rules position the rest of my images without my needing to position them. You will see that grid layout takes items out of source order to fill gaps in the grid. It does this because I have set the property grid-auto-flow to dense. The default is sparse meaning that grid will not attempt this backfilling behaviour.\nTake a look and play around with the full demo (requires a CSS grid layout-supporting browser):\nSee the Pen Grid auto-flow with rules by rachelandrew (@rachelandrew) on CodePen.\n\nThe final automatic placement example.\nMy wish for 2016\nI really hope that in 2016, we will see CSS grid layout finally emerge from behind browser flags, so that we can start to use these features in production \u2014 that we can start to move away from using the wrong tools for the job.\nHowever, I also hope that we\u2019ll see developers fully embracing these tools as the new system that they are. I want to see people exploring the possibilities they give us, rather than trying to get them to behave like the grid systems of 2015. As you discover these new modules, treat them as the new paradigm that they are, get creative with them. And, as you find the edges of possibility with them, take that feedback to the CSS Working Group. Help improve the layout systems that will shape the look of the future web.\nSome further reading\n\nI maintain a site of grid layout examples and resources at Grid by Example.\nThe three CSS specifications I\u2019ve discussed can be found as editor\u2019s drafts: CSS grid, flexbox, box alignment.\nI wrote about the last three years of my interest in CSS grid layout, which gives something of a history of the specification.\nMore examples of box alignment and grid layout.\nMy presentation at Fronteers earlier this year, in which I explain more about these concepts.", "year": "2015", "author": "Rachel Andrew", "author_slug": "rachelandrew", "published": "2015-12-15T00:00:00+00:00", "url": "https://24ways.org/2015/grid-flexbox-box-alignment-our-new-system-for-layout/", "topic": "code"} {"rowid": 70, "title": "Bringing Your Code to the Streets", "contents": "\u2014 or How to Be a Street VJ\nOur amazing world of web code is escaping out of the browser at an alarming rate and appearing in every aspect of the environment around us. Over the past few years we\u2019ve already seen JavaScript used server-side, hardware coded with JavaScript, a rise of native style and desktop apps created with HTML, CSS and JavaScript, and even virtual reality (VR) is getting its fair share of front-end goodness.\nYou can go ahead and play with JavaScript-powered hardware such as the Tessel or the Espruino to name a couple. Just check out the Tessel project page to see JavaScript in the world of coffee roasting or sleep tracking your pet. With the rise of the internet of things, JavaScript can be seen collecting information on flooding among other things. And if that\u2019s not enough \u2018outside the browser\u2019 implementations, Node.js servers can even be found in aircraft!\nI previously mentioned VR and with three.js\u2019s extra StereoEffect.js module it\u2019s relatively simple to get browser 3D goodness to be Google Cardboard-ready, and thus set the stage for all things JavaScript and VR. It\u2019s been pretty popular in the art world too, with interactive works such as Seb Lee-Delisle\u2019s Lunar Trails installation, featuring the old arcade game Lunar Lander, which you can now play in your browser while others watch (it is the web after all). The Science Museum in London held Chrome Web Lab, an interactive exhibition featuring five experiments, showcasing the magic of the web. And it\u2019s not even the connectivity of the web that\u2019s being showcased; we can even take things offline and use web code for amazing things, such as fighting Ebola.\nOne thing is for sure, JavaScript is awesome. Hell, if you believe those telly programs (as we all do), JavaScript can even take down the stock market, purely through the witchcraft of canvas! Go JavaScript!\nNow it\u2019s our turn\nSo I wanted to create a little project influenced by this theme, and as it\u2019s Christmas, take it to the streets for a little bit of party fun! Something that could take code anywhere. Here\u2019s how I made a portable visual projection pack, a piece of video mixing software and created some web-coded street art.\nStep one: The equipment\nYou will need:\n\nOne laptop: with HDMI output and a modern browser installed, such as Google Chrome.\nOne battery-powered mini projector: I\u2019ve used a Texas Instruments DLP; for its 120 lumens it was the best cost-to-lumens ratio I could find.\nOne MIDI controller (optional): mine is an ICON iDJ as it suits mixing visuals. However, there is more affordable hardware on the market such as an Akai LPD8 or a Korg nanoPAD2. As you\u2019ll see in the article, this is optional as it can be emulated within the software.\nA case to carry it all around in.\n\n\nStep two: The software\nThe projected visuals, I imagined, could be anything you can create within a browser, whether that be simple HTML and CSS, images, videos, SVG or canvas. The only requirement I have is that they move or change with sound and that I can mix any one visual into another.\nYou may remember a couple of years ago I created a demo on this very site, allowing audio-triggered visuals from the ambient sounds your device mic was picking up. That was a great starting point \u2013 I used that exact method to pick up the audio and thus the first requirement was complete. If you want to see some more examples of visuals I\u2019ve put together for this, there\u2019s a showcase on CodePen.\nThe second requirement took a little more thought. I needed two screens, which could at any point show any of the visuals I had coded, but could be mixed from one into the other and back again. So let\u2019s start with two divs, both absolutely positioned so they\u2019re on top of each other, but at the start the second screen\u2019s opacity is set to zero.\nNow all we need is a slider, which when moved from one side to the other slowly sets the second screen\u2019s opacity to 1, thereby fading it in.\nSee the Pen Mixing Screens (Software Version) by Rumyra (@Rumyra) on CodePen.\nMixing Screens (CodePen)\n\nAs you saw above, I have a MIDI controller and although the software method works great, I\u2019d quite like to make use of this nifty piece of kit. That\u2019s easily done with the Web MIDI API. All I need to do is call it, and when I move one of the sliders on the controller (I\u2019ve allocated the big cross fader in the middle for this), pick up on the change of value and use that to control the opacity instead.\nvar midi, data;\n// start talking to MIDI controller\nif (navigator.requestMIDIAccess) {\n navigator.requestMIDIAccess({\n sysex: false\n }).then(onMIDISuccess, onMIDIFailure);\n} else {\n alert(\u201cNo MIDI support in your browser.\u201d);\n}\n\n// on success\nfunction onMIDISuccess(midiData) {\n // this is all our MIDI data\n midi = midiData;\n\n var allInputs = midi.allInputs.values();\n // loop over all available inputs and listen for any MIDI input\n for (var input = allInputs.next(); input && !input.done; input = allInputs.next()) {\n // when a MIDI value is received call the onMIDIMessage function\n input.value.onmidimessage = onMIDIMessage;\n }\n}\n\nfunction onMIDIMessage(message) {\n // data comes in the form [command/channel, note, velocity]\n data = message.data;\n\n // Opacity change for screen. The cross fader values are [176, 8, {0-127}]\n if ( (data[0] === 176) && (data[1] === 8) ) {\n // this value will change as the fader is moved\n var opacity = data[2]/127;\n screenTwo.style.opacity = opacity;\n }\n}\n\nThe final code was slightly more complicated than this, as I decided to switch the two screens based on the frequencies of the sound that was playing, and use the cross fader to depict the frequency threshold value. This meant they flickered in and out of each other, rather than just faded. There\u2019s a very rough-and-ready first version of the software on GitHub.\nPhew, Great! Now we need to get all this to the streets!\nStep three: Portable kit\nDid you notice how I mentioned a case to carry it all around in? I wanted the case to be morphable, so I could use the equipment from it too, a sort of bag-to-usherette-tray-type affair. Well, I had an unused laptop bag\u2026\n\nI strengthened it with some MDF, so when I opened the bag it would hold like a tray where the laptop and MIDI controller would sit. The projector was Velcroed to the external pocket of the bag, so when it was a tray it would project from underneath. I added two durable straps, one for my shoulders and one round my waist, both attached to the bag itself. There was a lot of cutting and trimming. As it was a laptop bag it was pretty thick to start and sewing was tricky. However, I only broke one sewing machine needle; I\u2019ve been known to break more working with leather, so I figured I was doing well. By the way, you can actually buy usherette trays, but I just couldn\u2019t resist hacking my own :)\nStep four: Take to the streets\nFirst, make sure everything is charged \u2013 everything \u2013 a lot! The laptop has to power both the MIDI controller and the projector, and although I have a mobile phone battery booster pack, that\u2019ll only charge the projector should it run out. I estimated I could get a good hour of visual artistry before I needed to worry, though.\nI had a couple of ideas about time of day and location. Here in the UK at this time of year, it gets dark around half past four, so I could easily head out in a city around 5pm and it would be dark enough for the projections to be seen pretty well. I chose Bristol, around the waterfront, as there were some interesting locations to try it out in. The best was Millennium Square: busy but not crowded and plenty of surfaces to try projecting on to.\nMy first time out with the portable audio/visual pack (PAVP as it will now be named) was brilliant. I played music and projected visuals, like a one-woman band of A/V!\n\n\nYou might be thinking what the point of this was, besides, of course, it being a bit of fun. Well, this project got me to look at canvas and SVG more closely. The Web MIDI API was really interesting; MIDI as a data format has some great practical uses. I think without our side projects we may not have all these wonderful uses for our everyday code. Not only do they remind us coding can, and should, be fun, they also help us learn and grow as makers.\nMy favourite part? When I was projecting into a water feature in Millennium Square. For those who are familiar, you\u2019ll know it\u2019s like a wall of water so it produced a superb effect. I drew quite a crowd and a kid came to stand next to me and all I could hear him say with enthusiasm was, \u2018Oh wow! That\u2019s so cool!\u2019\nYes\u2026 yes, kid, it was cool. Making things with code is cool.\nMassive thanks to the lovely Drew McLellan for his incredibly well-directed photography, and also Simon Johnson who took a great hand in perfecting the kit while it was attached.", "year": "2015", "author": "Ruth John", "author_slug": "ruthjohn", "published": "2015-12-06T00:00:00+00:00", "url": "https://24ways.org/2015/bringing-your-code-to-the-streets/", "topic": "code"} {"rowid": 71, "title": "Upping Your Web Security Game", "contents": "When I started working in web security fifteen years ago, web development looked very different. The few non-static web applications were built using a waterfall process and shipped quarterly at best, making it possible to add security audits before every release; applications were deployed exclusively on in-house servers, allowing Info Sec to inspect their configuration and setup; and the few third-party components used came from a small set of well-known and trusted providers. And yet, even with these favourable conditions, security teams were quickly overwhelmed and called for developers to build security in.\nIf the web security game was hard to win before, it\u2019s doomed to fail now. In today\u2019s web development, every other page is an application, accepting inputs and private data from users; software is built continuously, designed to eliminate manual gates, including security gates; infrastructure is code, with servers spawned with little effort and even less security scrutiny; and most of the code in a typical application is third-party code, pulled in through open source repositories with rarely a glance at who provided them.\nSecurity teams, when they exist at all, cannot solve this problem. They are vastly outnumbered by developers, and cannot keep up with the application\u2019s pace of change. For us to have a shot at making the web secure, we must bring security into the core. We need to give it no less attention than that we give browser compatibility, mobile design or web page load times. More broadly, we should see security as an aspect of quality, expecting both ourselves and our peers to address it, and taking pride when we do it well.\nWhere To Start?\nEmbracing security isn\u2019t something you do overnight.\nA good place to start is by reviewing things you\u2019re already doing \u2013 and trying to make them more secure. Here are three concrete steps you can take to get going.\nHTTPS\nThreats begin when your system interacts with the outside world, which often means HTTP. As is, HTTP is painfully insecure, allowing attackers to easily steal and manipulate data going to or from the server. HTTPS adds a layer of crypto that ensures the parties know who they\u2019re talking to, and that the information exchanged can be neither modified nor sniffed.\nHTTPS is relevant to any site. If your non-HTTPS site holds opinions, reading it may get your users in trouble with employers or governments. If your users believe what you say, attackers can modify your non-HTTPS to take advantage of and abuse that trust. If you want to use new browser technologies like HTTP2 and service workers, your site will need to be HTTPS. And if you want to be discovered on the web, using HTTPS can help your Google ranking. For more details on why I think you should make the switch to HTTPS, check out this post, these slides and this video.\nUsing HTTPS is becoming easier and cheaper. Here are a few free tools that can help:\n\nGet free and easy HTTPS delivery from Cloudflare (be sure to use \u201cFull SSL\u201d!)\nGet a free and automation-friendly certificate from Let\u2019s Encrypt (now in open beta).\nTest how well your HTTPS is set up using SSLTest.\n\nOther vendors and platforms are rapidly simplifying and reducing the cost of their HTTPS offering, as demand and importance grows.\nTwo-Factor Authentication\nThe most sensitive data is usually stored behind a login, and the authentication process is the primary gate in front of this data. Making this process secure has many aspects, including using HTTPS when accepting credentials, having a strong password policy, never storing the password, and more.\nAll of these are important, but the best single step to boost your authentication security is to introduce two-factor authentication (2FA). Adding 2FA usually means prompting users for an additional one-time code when logging in, which they get via SMS or a mobile app (e.g. Google Authenticator). This code is short-lived and is extremely hard for a remote attacker to guess, thus vastly reducing the risk a leaked or easily guessed password presents.\nThe typical algorithm for 2FA is based on an IETF standard called the time-based one-time password (TOTP) algorithm, and it isn\u2019t that hard to implement. Joel Franusic wrote a great post on implementing 2FA; modules like speakeasy make it even easier; and you can swap SMS with Google Authenticator or your own app if you prefer. If you don\u2019t want to build 2FA support yourself, you can purchase two/multi-factor authentication services from vendors such as DuoSecurity, Auth0, Clef, Hypr and others.\nIf implementing 2FA still feels like too much work, you can also choose to offload your entire authentication process to an OAuth-based federated login. Many companies offer this today, including Facebook, Google, Twitter, GitHub and others. These bigger players tend to do authentication well and support 2FA, but you should consider what data you\u2019re sharing with them in the process.\nTracking Known Vulnerabilities\nMost of the code in a modern application was actually written by third parties, and pulled into your app as frameworks, modules and libraries. While using these components makes us much more productive, along with their functionality we also adopt their security flaws. To make things worse, some of these flaws are well-known vulnerabilities, making it easy for hackers to take advantage of them in an attack.\nThis is a real problem and happens on pretty much every platform. Do you develop in Java? In 2014, over 6% of Java modules downloaded from Maven had a known severe security issue, the typical Java applications containing 24 flaws. Are you coding in Node.js? Roughly 14% of npm packages carry a known vulnerability, and over 60% of dev shops find vulnerabilities in their code. 30% of Docker Hub containers include a high priority known security hole, and 60% of the top 100,000 websites use client-side libraries with known security gaps.\nTo find known security issues, take stock of your dependencies and match them against language-specific lists such as Snyk\u2019s vulnerability DB for Node.js, rubysec for Ruby, victims-db for Python and OWASP\u2019s Dependency Check for Java. Once found, you can fix most issues by upgrading the component in question, though that may be tricky for indirect dependencies. \nThis process is still way too painful, which means most teams don\u2019t do it. The Snyk team and I are hoping to change that by making it as easy as possible to find, fix and monitor known vulnerabilities in your dependencies. Snyk\u2019s wizard will help you find and fix these issues through guided upgrades and patches, and adding Snyk\u2019s test to your continuous integration and deployment (CI/CD) will help you stay secure as your code evolves.\nNote that newly disclosed vulnerabilities usually impact old code \u2013 the one you\u2019re running in production. This means you have to stay alert when new vulnerabilities are disclosed, so you can fix them before attackers can exploit them. You can do so by subscribing to vulnerability lists like US-CERT, OSVDB and NVD. Snyk\u2019s monitor will proactively let you know about new disclosures relevant to your code, but only for Node.js for now \u2013 you can register to get updated when we expand.\nSecuring Yourself\nIn addition to making your application secure, you should make the contributors to that application secure \u2013 including you. Earlier this year we\u2019ve seen attackers target mobile app developers with a malicious Xcode. The real target, however, wasn\u2019t these developers, but rather the users of the apps they create. That you create. Securing your own work environment is a key part of keeping your apps secure, and your users from being compromised.\nThere\u2019s no single step that will make you fully secure, but here are a few steps that can make a big impact:\n\nUse 2FA on all the services related to the application, notably source control (e.g. GitHub), cloud platform (e.g. AWS), CI/CD, CDN, DNS provider and domain registrar. If an attacker compromises any one of those, they could modify or replace your entire application. I\u2019d recommend using 2FA on all your personal services too.\nUse a password manager (e.g. 1Password, LastPass) to ensure you have a separate and complex password for each service. Some of these services will get hacked, and passwords will leak. When that happens, don\u2019t let the attackers access your other systems too.\nSecure your workstation. Be careful what you download, lock your screen when you walk away, change default passwords on services you install, run antivirus software, etc. Malware on your machine can translate to malware in your applications.\nBe very wary of phishing. Smart attackers use \u2018spear phishing\u2019 techniques to gain access to specific systems, and can trick even security savvy users. There are even phishing scams targeting users with 2FA. Be alert to phishy emails.\nDon\u2019t install things through curl <somewhere-on-the-web> | sudo bash, especially if the URL is on GitHub, meaning someone else controls it. Don\u2019t do it on your machines, and definitely don\u2019t do it in your CI/CD systems. Seriously.\n\nStaying secure should be important to you personally, but it\u2019s doubly important when you have privileged access to an application. Such access makes you a way to reach many more users, and therefore a more compelling target for bad actors.\nA Culture of Security\nUsing HTTPS, enabling two-factor authentication and fixing known vulnerabilities are significant steps in building security at your core. As you implement them, remember that these are just a few steps in a longer journey.\nThe end goal is to embrace security as an aspect of quality, and accept we all share the responsibility of keeping ourselves \u2013 and our users \u2013 safe.", "year": "2015", "author": "Guy Podjarny", "author_slug": "guypodjarny", "published": "2015-12-11T00:00:00+00:00", "url": "https://24ways.org/2015/upping-your-web-security-game/", "topic": "code"} {"rowid": 75, "title": "A Harder-Working Class", "contents": "Class is only becoming more important. Focusing on its original definition as an attribute for grouping (or classifying) as well as linking HTML to CSS, recent front-end development practices are emphasizing class as a vessel for structured, modularized style packages. These patterns reduce the need for repetitive declarations that can seriously bloat file sizes, and instil human-readable understanding of how the interface, layout, and aesthetics are constructed.\n\nIn the next handful of paragraphs, we will look at how these emerging practices \u2013 such as object-oriented CSS and SMACSS \u2013 are pushing the relevance of class. We will also explore how HTML and CSS architecture can be further simplified, performance can be boosted, and CSS utility sharpened by combining class with the attribute selector.\n\nA primer on attribute selectors\n\nWhile attribute selectors were introduced in the CSS 2 spec, they are still considered rather exotic. These well-established and well-supported features give us vastly improved flexibility in targeting elements in CSS, and offer us opportunities for smarter markup. With an attribute selector, you can directly style an element based on any of its unique \u2013 or uniquely shared \u2013 attributes, without the need for an ID or extra classes. Unlike pseudo-classes, pseudo-elements, and other exciting features of CSS3, attribute selectors do not require any browser-specific syntax or prefix, and are even supported in Internet Explorer 7. \n\nFor example, say we want to target all anchor tags on a page that link to our homepage. Where otherwise we might need to manually identify and add classes to the HTML for these specific links, we could simply write:\n\n[href=index.html] { }\n\nThis selector reads: target every element that has an href attribute of \u201cindex.html\u201d. \n\nAttribute selectors are more faceted, though, as they also give us some very simple regular expression-like logic that helps further narrow (or widen) a selector\u2019s scope. In our previous example, what if we wanted to also give indicative styles to any anchor tag linking to an external site? With no way to know what the exact href value would be for every external link, we need to use an expression to match a common aspect of those links. In this case, we know that all external links need to start with \u201chttp\u201d, so we can use that as a hook:\n\n[href^=http] { }\n\nThe selector here reads: target every element that has an href attribute that begins with \u201chttp\u201d (which will also include \u201chttps\u201d). The ^= means \u201cstarts with\u201d. There are a few other simple expressions that give us a lot of flexibility in targeting elements, and I have found that a deep understanding of these and other selector types to be very useful.\n\nThe class-attribute selector\n\nBy matching classes with the attribute selector, CSS can be pushed to accomplish some exciting new feats. What I call a class-attribute selector combines the advantages of classes with attribute selectors by targeting the class attribute, rather than a specific class. Instead of selecting .urgent, you could select [class*=urgent]. The latter may seem like a more verbose way of accomplishing the former, but each would actually match two subtly different groups of elements.\n\nEric Meyer first explored the possibility of using classes with attribute selectors over a decade ago. While his interest in this technique mostly explored the different facets of the syntax, I have found that using class-attribute selectors can have distinct advantages over either using an attribute selector or a straightforward class selector.\n\nFirst, let\u2019s explore some of the subtleties of why we would target class before other attributes:\n\n\n\tClasses are ubiquitous. They have been supported since the HTML 4 spec was released in 1999. Newer attributes, such as the custom data attribute, have only recently begun to be adopted by browsers.\n\tClasses have multiple ways of being targeted. You can use the class selector or attribute selector (.classname or [class=classname]), allowing more flexible specificity than resorting to an ID or !important.\n\tClasses are already widely used, so adding more classes will usually require less markup than adding more attributes.\n\tClasses were designed to abstractly group and specify elements, making them the most appropriate attribute for styling using object-oriented methods (as we will learn in a moment).\n\n\nAlso, as Meyer pointed out, we can use the class-attribute selector to be more strict about class declarations. Of these two elements:\n\n<h2 class=\"very urgent\">\n\n<h2 class=\"urgent\">\n\n\u2026only the second h2 would be selected by [class=urgent], while .urgent would select both. The use of = matches any element with the exact class value of \u201curgent\u201d. Eric explores these nuances further in his series on attribute selectors, but perhaps more dramatic is the added power that class-attribute selectors can bring to our CSS.\n\nMore object-oriented, more scalable and modular\n\nNicole Sullivan has been pushing abstracted, object-oriented thinking in CSS development for years now. She has shared stacks of knowledge on how behemoth sites have seen impressive gains in maintenance overhead and CSS file sizes by leaning heavier on classes derived from common patterns. Jonathan Snook also speaks, writes and is genuinely passionate about improving our markup by using more stratified and modular class name conventions. With SMACSS, he shows this to be highly useful across sites \u2013 both complex and simple \u2013 that exhibit repeated design patterns. Sullivan and Snook both push the use of class for styling over other attributes, and many front-end developers are fast advocating such thinking as best practice.\n\nWith class-attribute selectors, we can further abstract our CSS, pushing its scalability. In his chapter on modules, Snook gives the example of a .pod class that might represent a certain set of styles. A .pod style set might be used in varying contexts, leading to CSS that might normally look like this:\n\n.pod { }\nform .pod { }\naside .pod { }\n\nAccording to Snook, we can make these styles more portable by targeting more verbose classes, rather than context:\n\n.pod { }\n.pod-form { }\n.pod-sidebar { }\n\n\u2026resulting in the following HTML:\n\n<div class=\"pod\">\n<div class=\"pod pod-form\">\n<div class=\"pod pod-sidebar\">\n\nThis divorces the <div>\u2019s styles from its context, making it applicable to any situation in which it is needed. The markup is clean and portable, and the classes are imbued with meaning as to what module they belong to. \n\nUsing class-attribute selectors, we can simplify this further:\n\n[class*=pod] { }\n.pod-form { }\n.pod-sidebar { }\n\nThe *= tells the browser to look for any element with a class attribute containing \u201cpod\u201d, so it matches \u201cpod\u201d, \u201cpod-form\u201d, \u201cpod-sidebar\u201d, etc. This allows only one class per element, resulting in simpler HTML:\n\n<div class=\"pod\">\n<div class=\"pod-form\">\n<div class=\"pod-sidebar\">\n\nWe could further abstract the concept of \u201cform\u201d and \u201csidebar\u201d adjustments if we knew that each of those alterations would always need the same treatment.\n\n/* Modules */\n[class*=pod] { }\n[class*=btn] { }\n\n/* Alterations */\n[class*=-form] { }\n[class*=-sidebar] { }\n\nIn this case, all elements with classes appended \u201c-form\u201d or \u201c-sidebar\u201d would be altered in the same manner, allowing the markup to stay simple:\n\n<form>\n <h2 class=\"pod-form\">\n <a class=\"btn-form\" href=\"#\">\n\n<aside>\n <h2 class=\"pod-sidebar\">\n <a class=\"btn-sidebar\" href=\"#\">\n\n50+ shades of specificity\n\nClasses are just powerful enough to override element selectors and default styling, but still leave room to be trumped by IDs and !important styles. This makes them more suitable for object-oriented patterns and helps avoid messy specificity issues that can not only be a pain for developers to maintain, but can also affect a site\u2019s performance. As Sullivan notes, \u201cIn almost every case, classes work well and have fewer unintended consequences than either IDs or element selectors\u201d. Proper use of specificity and cascade is crucial in building straightforward, efficient CSS.\n\nOne interesting aspect of attribute selectors is that they can be compounded for increasing levels of specificity. Attribute selectors are assigned a specificity level of ten, the same as class selectors, but both class and attribute selectors can be chained together, giving them more and more specificity with each link. Some examples:\n\n.box { } \n/* Specificity of 10 */\n\n.box.promo { } \n/* Specificity of 20 */\n\n[class*=box] { } \n/* Specificity of 10 */\n\n[class*=box][class*=promo] { } \n/* Specificity of 20 */\n\nYou can chain both types together, too:\n\n.box[class*=promo] { } \n/* Specificity of 20 */\n\nI was amused to find, though, that you can chain the exact same class and attribute selectors for infinite levels of specificity\n\n.box { } \n/* Specificity of 10 */\n\n.box.box { } \n/* Specificity of 20 */\n\n.box.box.box { } \n/* Specificity of 30 */\n\n[class*=box] { }\n/* Specificity of 10 */\n\n[class*=box][class*=box] { }\n/* Specificity of 20 */\n\n[class*=box][class*=box][class*=box] { }\n/* Specificity of 30 */\n\n.box[class*=box].box[class*=box] { } \n/* Specificity of 40 */\n\nTo override .box styles for promo, we wouldn\u2019t need to add an ID, change the order of .promo and .box in the CSS, or resort to an !important style. Granted, any issue that might need this fine level of specificity tweaking could probably be better solved with clever cascades, but having options never hurts.\n\nSmarter CSS\n\nOne of the most powerful aspects of the class-attribute selector is its ability to expand the simple logic found in CSS. When developing Gridset (an online tool for building grids and outputting them as CSS), I realized that with the right class name conventions, class-attribute selectors would allow the CSS to be smart enough to automatically adjust for column offsets without the need for extra classes. This imbued the CSS output with logic that other frameworks lacked, and makes a developer\u2019s job much easier. \n\nSay you need an element that spans column five (c5) to column six (c6) on your grid, and is preceded by an element spanning column one (c1) to column three (c3). The CSS can anticipate such a scenario:\n\n.c1-c3 + .c5-c6 {\n margin-left: 25%; /* \u2026or the width of column four plus two gutter widths */\n}\n\n\u2026but to accommodate all of the margin offsets that could span that same gap, we would need to write a rather protracted list for just a six column grid:\n\n.c1-c3 + .c5-c6,\n.c1-c3 + .c5,\n.c2-c3 + .c5-c6,\n.c2-c3 + .c5,\n.c3 + .c5-c6,\n.c3 + .c5 {\n margin-left: 25%; \n}\n\nNow imagine how the verbosity compounds when we repeat this type of declaration for every possible margin in a grid. The more columns added to the grid, the longer this selector list would get, too, making the CSS harder for the developer to maintain and slowing the load time. Using class-attribute selectors, though, this can be much simpler:\n\n[class*=c3] + [class*=c5] {\n margin-left: 25%;\n}\n\nI\u2019ve detailed how we extract as much logic as possible from as little CSS as needed on the Gridset blog.\n\nMore flexible selectors\n\nIn a recent project, I was working with Drupal-generated classes to change styles for certain special pages on a site. Without being able to change the code base, I was left trying to find some specific aspect of the generated HTML to target. I noticed that every special page was given a prefixed class, unique to the page, resulting in CSS like this:\n\n.specialpage-about,\n.specialpage-contact,\n.specialpage-info,\n\u2026\n\n\u2026and the list kept growing with each new special page. Such bloat would lead to problems down the line, and add development overhead to editorial decisions, which was a situation we were trying to avoid. I was easily able to fix this, though, with a concise class-attribute selector:\n\n[class*=specialpage-]\n\nThe CSS was now flexible enough to accommodate both the editorial needs of the client, and the development restrictions of the CMS.\n\nSelector performance\n\nAs Snook tells us in his chapter on Selector Performance, selectors are read by the browser from right to left, matching every element that adheres to each rule (or part of the selector). The more specific we can make the right-most rules \u2013 and every other part of your selectors \u2013 the more performant your CSS will be. So this selector:\n\n.home-page .promo .main-header\n\n\u2026would be more performant than:\n\n.home-page div header\n\n\u2026because there are likely many more header and div elements on the page, but not so many elements with those specific classes.\n\nNow, the class-attribute selector could be more general than a class selector, but not by much. I ran numerous tests based on the work of Steve Souders (and a few others) to test a class-attribute selector against a normal class selector. Given that Javascript will freeze during style rendering, I created a script that will add, then remove, a stylesheet on a page 5000 times, and measure only the time that elapses during the rendering freeze. The script runs four tests, essentially: one where a class selector and class-attribute Selector match a single element, and one they match multiple elements on the page.\n\nAfter running the test over 100 times and averaging the results, I have not seen a significant difference in rendering times. (As of this writing, the class-attribute selector has been 0.398% slower on average.) View the results here.\n\nGiven the sheer amount of bytes potentially saved by reducing selector lists, though, I am confident class-attribute selectors could shorten load times on larger sites and, at the very least, save precious development time.\n\nConclusion\n\nWith its flexibility and broad remit, class has at times been derided as too lenient, allowing CMSes and lazy developers to fill its values with presentational hacks or verbose gibberish. There have even been calls for an early retirement. Class continues, though, to be one of our most crucial tools.\n\nFront-end developers are rightfully eager to expand production abilities through innovations such as Sass or LESS, but this should not preclude us from honing the tools we already know as well. Every technique demonstrated in this article was achievable over a decade ago and most of the same thinking could be applied to IDs, rels, or any other attribute (though the reasons listed above give class an edge). The recent advent of methods such as object-oriented CSS and SMACSS shows there is still much room left to expand what simple HTML and CSS can accomplish. Progress may not always be found in the innovation of our tools, but through sharpening our understanding of them.", "year": "2012", "author": "Nathan Ford", "author_slug": "nathanford", "published": "2012-12-15T00:00:00+00:00", "url": "https://24ways.org/2012/a-harder-working-class/", "topic": "code"} {"rowid": 76, "title": "Giving CSS Animations and Transitions Their Place", "contents": "CSS animations and transitions may not sit squarely in the realm of the behaviour layer, but they\u2019re stepping up into this area that used to be pure JavaScript territory. Heck, CSS might even perform better than its JavaScript equivalents in some cases. That\u2019s pretty serious! With CSS\u2019s new tricks blurring the lines between presentation and behaviour, it can start to feel bloated and messy in our CSS files. It\u2019s an uncomfortable feeling.\n\nHere are a pair of methods I\u2019ve found to be pretty helpful in keeping the potential bloat and wire-crossing under control when CSS has its hands in both presentation and behaviour.\n\nSame eggs, more baskets\n\nStructuring your CSS to have separate files for layout, typography, grids, and so on is a fairly common approach these days. But which one do you put your transitions and animations in? The initial answer, as always, is \u201cit depends\u201d.\n\nSmall effects here and there will likely sit just fine with your other styles. When you move into more involved effects that require multiple animations and some logic support from JavaScript, it\u2019s probably time to choose none of the above, and create a separate CSS file just for them.\n\nPutting all your animations in one file is a huge help for code organization. Even if you opt for a name less literal than animations.css, you\u2019ll know exactly where to go for anything CSS animation related. That saves time and effort when it comes to editing and maintenance. Keeping track of which animations are still currently used is easier when they\u2019re all grouped together as well. And as an added bonus, you won\u2019t have to look at all those horribly unattractive and repetitive prefixed @-keyframe rules unless you actually need to.\n\nAn animations.css file might look something like the snippet below. It defines each animation\u2019s keyframes and defines a class for each variation of that animation you\u2019ll be using. Depending on the situation, you may also want to include transitions here in a similar way. (I\u2019ve found defining transitions as their own class, or mixin, to be a huge help in past projects for me.)\n\n// defining the animation\n@keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n@-webkit-keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n@-moz-keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n@-ms-keyframes catFall {\n from { background-position: center 0;}\n to {background-position: center 1000px;}\n}\n\n\u2026\n\n// class that assigns the animation\n\n.catsBackground {\n height: 100%;\n background: transparent url(../endlessKittens.png) 0 0 repeat-y;\n animation: catFall 1s linear infinite;\n -webkit-animation: catFall 1s linear infinite;\n -moz-animation: catFall 1s linear infinite;\n -ms-animation: catFall 1s linear infinite;\n}\n\nIf we don\u2019t need it, why load it?\n\nHaving all those CSS animations and transitions in one file gives us the added flexibility to load them only when we want to. Loading a whole lot of things that will never be used might seem like a bit of a waste.\n\nWhile CSS has us impressed with its motion chops, it falls flat when it comes to the logic and fine-grained control. JavaScript, on the other hand, is pretty good at both those things. Chances are the content of your animations.css file isn\u2019t acting alone. You\u2019ll likely be adding and removing classes via JavaScript to manage your CSS animations at the very least. If your CSS animations are so entwined with JavaScript, why not let them hang out with the rest of the behaviour layer and only come out to play when JavaScript is supported?\n\nDynamically linking your animations.css file like this means it will be completely ignored if JavaScript is off or not supported. No JavaScript? No additional behaviour, not even the parts handled by CSS.\n\n<script>\ndocument.write('<link rel=\"stylesheet\" type=\"text/css\" href=\"animations.css\">');\n</script>\n\nThis technique comes up in progressive enhancement techniques as well, but it can help here to keep your presentation and behaviour nicely separated when more than one language is involved. The aim in both cases is to avoid loading files we won\u2019t be using.\n\nIf you happen to be doing something a bit fancier \u2013 like 3-D transforms or critical animations that require more nuanced fallbacks \u2013 you might need something like modernizr to step in to determine support more specifically. But the general idea is the same.\n\nSumming it all up\n\nUsing a couple of simple techniques like these, we get to pick where to best draw the line between behaviour and presentation based on the situation at hand, not just on what language we\u2019re using. The power of when to separate and how to reassemble the individual pieces can be even greater if you use preprocessors as part of your process. We\u2019ve got a lot of options! The important part is to make forward-thinking choices to save your future self, and even your current self, unnecessary headaches.", "year": "2012", "author": "Val Head", "author_slug": "valhead", "published": "2012-12-08T00:00:00+00:00", "url": "https://24ways.org/2012/giving-css-animations-and-transitions-their-place/", "topic": "code"} {"rowid": 79, "title": "Responsive Images: What We Thought We Needed", "contents": "If you were to read a web designer\u2019s Christmas wish list, it would likely include a solution for displaying images responsively. For those concerned about users downloading unnecessary image data, or serving images that look blurry on high resolution displays, finding a solution has become a frustrating quest.\n\nHaving experimented with complex and sometimes devilish hacks, consensus is forming around defining new standards that could solve this problem. Two approaches have emerged.\n\nThe <picture> element markup pattern was proposed by Mat Marquis and is now being developed by the Responsive Images Community Group. By providing a means of declaring multiple sources, authors could use media queries to control which version of an image is displayed and under what conditions:\n\n<picture width=\"500\" height=\"500\">\n <source media=\"(min-width: 45em)\" src=\"large.jpg\">\n <source media=\"(min-width: 18em)\" src=\"med.jpg\">\n <source src=\"small.jpg\">\n <img src=\"small.jpg\" alt=\"\">\n <p>Accessible text</p>\n</picture>\n\nA second proposal put forward by Apple, the srcset attribute, uses a more concise syntax intended for use with the <img> element, although it could be compatible with the <picture> element too. This would allow authors to provide a set of images, but with the decision on which to use left to the browser:\n\n<img src=\"fallback.jpg\" alt=\"\" srcset=\"small.jpg 640w 1x, small-hd.jpg 640w 2x, med.jpg 1x, med-hd.jpg 2x \">\n\nEnter Scrooge\n\n\n\tMen\u2019s courses will foreshadow certain ends, to which, if persevered in, they must lead.\nEbenezer Scrooge\n\n\nGiven the complexity of this issue, there\u2019s a heated debate about which is the best option. Yet code belies a certain truth. That both feature verbose and opaque syntax, I\u2019m not sure either should find its way into the browser \u2013 especially as alternative approaches have yet to be fully explored.\n\nSo, as if to dampen the festive cheer, here are five reasons why I believe both proposals are largely redundant.\n\n1. We need better formats, not more markup\n\nAs we move away from designs defined with fixed pixel values, bitmap images look increasingly unsuitable. While simple images and iconography can use scalable vector formats like SVG, for detailed photographic imagery, raster formats like GIF, PNG and JPEG remain the only suitable option.\n\nThere is scope within current formats to account for varying bandwidth but this requires cooperation from browser vendors. Newer formats like JPEG2000 and WebP generate higher quality images with smaller file sizes, but aren\u2019t widely supported.\n\nWhile it\u2019s tempting to try to solve this issue by inventing new markup, the crux of it remains at the file level.\n\nDaan Jobsis\u2019s experimentation with image compression strengthens this argument. He discovered that by increasing the dimensions of a JPEG image while simultaneously reducing its quality, a smaller files could be produced, with the resulting image looking just as good on both standard and high-resolution displays.\n\nThis may be a hack in lieu of a more permanent solution, but it\u2019s applied in the right place. Easy to accomplish with existing tools and without compatibility issues, it has few downsides. Further experimentation in this area should be encouraged, with standardisation efforts more helpful if focused on developing new image formats or, preferably, extending existing ones.\n\n2. Art direction doesn\u2019t belong in markup\n\nA desired benefit of the <picture> markup pattern is to allow for greater art direction. For example, rather than scaling down images on smaller displays to the point that their content is hard to discern, we could present closer crops instead:\n\n\n\nThis can be achieved with CSS of course, although with a download penalty for those parts of an image not shown. This point may be negligible, however, since in the context of adaptable layouts, these hidden areas may end up being revealed anyway.\n\nArt direction concerns design, not content. If we wish to maintain a separation of concerns, including presentation within our markup seems misguided.\n\n3. The size of a display has little relation to the size of an image\n\nBy using media queries, the <picture> element allows authors to choose which characteristics of the screen or viewport to query for different images to be displayed.\n\nIn developing sites at Clearleft, we have noticed that the viewport is essentially arbitrary, with the size of an image\u2019s containing element more important. For example, look at how this grid of images may adapt at different viewport widths:\n\n\n\nAs we build more modular systems, components need to be adaptable in and of themselves. There is a case to be made for developing more contextual methods of querying, rather than those based on attributes of the display.\n\n4. We haven\u2019t lived with the problem long enough\n\nA key strength of the web is that the underlying platform can be continually iterated. This can also be problematic if snap judgements are made about what constitutes an improvement.\n\nThe early history of the web is littered with such examples, be it the perceived need for blinking text or inline typographic styling. To build a platform for the future, additions to it should be carefully considered. And if we want more consistent support across browsers, burdening vendors with an ever increasing list of features seems counterproductive.\n\nOnly once the need for a new feature is sufficiently proven, should we look to standardise it. Before we could declare hover effects, rounded corners and typographic styling in CSS, we used JavaScript as a polyfill. Sure, doing so was painful, but use cases were fully explored, and the CSS specification better reflected the needs of authors.\n\n5. Images and the web aesthetic\n\nThe srcset proposal has emerged from a company that markets its phones as being able to browse the real \u2013 yet squashed down, tapped and zoomable \u2013 web. Perhaps Apple should make its own website responsive before suggesting how the rest of us should do so.\n\nConverserly, while the <picture> proposal has the backing of a few respected developers and designers, it was born out of the work Mat Marquis and Filament Group did for the Boston Globe. As the first large-scale responsive design, this was a landmark project that ignited the responsive web design movement and proved its worth. But it was the first.\n\nIts design shares a vernacular to that of contemporary newspaper websites, with a columnar, image-laden and densely packed layout. Compared to more recent examples \u2013 Quartz, The Next Web and the New York Times Skimmer \u2013 it feels out of step with the future direction of news sites. In seeking out a truer aesthetic for the web in which software interfaces have greater influence, we might discover that the need for responsive images isn\u2019t as great as originally thought.\n\n\n\nBuilding for the future\n\nWith responsive design, we\u2019ve accepted the idea that a fully fluid layout, rather than a set of fixed layouts, is best suited to the web\u2019s unpredictable nature. Current responsive image proposals are antithetical to this approach.\n\nWe need solutions that lack complexity, are device-agnostic and work within existing workflows. Any proposal that requires different versions of the same image to be created, is likely to have to acquiesce under the pressure of reality.\n\nWhile it\u2019s easy to get distracted about the size and quality of an image, and how we might choose to serve it, often the simplest solution is not to include it at all. After years of gluttonous design practice, in which fast connections and expansive display sizes were an accepted norm, we have got use to filling pages with needless images and countless items of page furniture.\n\nTo design more adaptable experiences, the presence of every element needs to be questioned, for its existence requires additional data to be downloaded or futher complexity within a design system. Conditional loading techniques mean that the inclusion of images is no longer a binary choice, but can instead appear in a progressively enhanced manner.\n\nSo here is my proposal. Instead of spending the next year worrying about responsive images, let\u2019s embrace the constraints of the medium, and seek out new solutions that can work within them.", "year": "2012", "author": "Paul Lloyd", "author_slug": "paulrobertlloyd", "published": "2012-12-11T00:00:00+00:00", "url": "https://24ways.org/2012/responsive-images-what-we-thought-we-needed/", "topic": "code"} {"rowid": 80, "title": "HTML5 Video Bumpers", "contents": "Video is a bigger part of the web experience than ever before. With native browser support for HTML5 video elements freeing us from the tyranny of plugins, and the availability of faster internet connections to the workplace, home and mobile networks, it\u2019s now pretty straightforward to publish video in a way that can be consumed in all sorts of ways on all sorts of different web devices.\n\nI recently worked on a project where the client had shot some dedicated video shorts to publish on their site. They also had some five-second motion graphics produced to top and tail the videos with context and branding. This pretty common requirement is a great idea on the web, where a user might land at your video having followed a link and be viewing a page without much context.\n\nKnown as bumpers, these short introduction clips help brand a video and make it look a lot more professional.\n\n\n\nAdding bumpers to a video\n\nThe simplest way to add bumpers to a video would be to edit them on to the start and end of the video file itself. Cooking the bumpers into the video file is easy, but should you ever want to update them it can become a real headache. If the branding needs updating, for example, you\u2019d need to re-edit and re-encode all your videos. Not a fun task.\n\nWhat if the bumpers could be added dynamically? That would enable you to use the same bumper for multiple videos (decreasing download time for users who might watch more than one) and to update the bumpers whenever you wanted. You could change them seasonally, update them for special promotions, run different advertising slots, perform multivariate testing, or even target different bumpers to different users.\n\nThe trade-off, of course, is that if you dynamically add your bumpers, there\u2019s a chance that a user in a given circumstance might not see the bumper. For example, if the main video feature was uploaded to YouTube, you\u2019d have no way to control the playback. As always, you need to weigh up the pros and cons and make your choice.\n\nHTML5 bumpers\n\nIf you wanted to dynamically add bumpers to your HTML5 video, how would you go about it? That was the question I found myself needing to answer for this particular client project.\n\nMy initial thought was to treat it just like an image slideshow. If I were building a slideshow that moved between images, I\u2019d use CSS absolute positioning with z-index to stack the images up on top of each other in a pile, with the first image on top. To transition to the second image, I\u2019d use JavaScript to fade the top image out, revealing the second image beneath it.\n\n\n\nNow that video is just a native object in the DOM, just like an image, why not do the same? Stack the videos up with the opening bumper on top, listen for the video\u2019s onended event, and fade it out to reveal the main feature behind. Good idea, right?\n\nWrong\n\nRemember that this is the web. It\u2019s never going to be that easy. The problem here is that many non-desktop devices use native, dedicated video players. Think about watching a video on a mobile phone \u2013 when you play the video, the phone often goes full-screen in its native player, leaving the web page behind. There\u2019s no opportunity to fade or switch z-index, as the video isn\u2019t being viewed in the page. Your page is left powerless. Powerless!\n\n\n\nSo what can we do? What can we control?\n\nThose of us with particularly long memories might recall a time before CSS, when we\u2019d have to use JavaScript to perform image rollovers. As CSS background images weren\u2019t a practical reality, we would use lots of <img> elements, and perform a rollover by modifying the src attribute of the image. \n\nTurns out, this old trick of modifying the source can help us out with video, too. In most cases, modifying the src attribute of a <video> element, or perhaps more likely the src attribute of a source element, will swap from one video to another.\n\nSwappin\u2019 it\n\nLet\u2019s take a deliberately simple example of a super-basic video tag:\n\n<video src=\"mycat.webm\" controls>no fallback coz i is lame, innit.</video>\n\nWe could very simply write a script to find all video tags and give them a new src to show our bumper.\n\n<script>\n\tvar videos, i, l;\n\tvideos = document.getElementsByTagName('video');\n\tfor(i=0, l=videos.length; i<l; i++) {\n\t\tvideos[i].setAttribute('src', 'bumper-in.webm');\n\t}\n</script>\n\nView the example in a browser with WebM support. You\u2019ll see that the video is swapped out for the opening bumper. Great!\n\nBeefing it up\n\nOf course, we can\u2019t just publish video in one format. In practical use, you need a <video> element with multiple <source> elements containing your different source formats.\n\n<video controls>\n <source src=\"mycat.mp4\" type=\"video/mp4\" />\n <source src=\"mycat.webm\" type=\"video/webm\" />\n <source src=\"mycat.ogv\" type=\"video/ogg\" />\n</video>\n\nThis time, our script needs to loop through the sources, not the videos. We\u2019ll use a regular expression replacement to swap out the file name while maintaining the correct file extension.\n\n<script>\n var sources, i, l, orig;\n sources = document.getElementsByTagName('source');\n for(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('src');\n sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));\n // reload the video\n sources[i].parentNode.load();\n }\n</script>\n\nThe difference this time is that when changing the src of a <source> we need to call the .load() method on the video to get it to acknowledge the change.\n\nSee the code in action, this time in a wider range of browsers.\n\nBut, my video!\n\nI guess we should get the original video playing again. Keeping the same markup, we need to modify the script to do two things:\n\n\n\tStore the original src in a data- attribute so we can access it later\n\tAdd an event listener so we can detect the end of the bumper playing, and load the original video back in\n\n\nAs we need to loop through the videos this time to add the event listener, I\u2019ve moved the .load() call into that loop. It\u2019s a bit more efficient to call it only once after modifying all the video\u2019s sources.\n\n<script>\nvar videos, sources, i, l, orig;\nsources = document.getElementsByTagName('source');\nfor(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('src');\n sources[i].setAttribute('data-orig', orig);\n sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));\n}\nvideos = document.getElementsByTagName('video');\nfor(i=0, l=videos.length; i<l; i++) {\n videos[i].load();\n videos[i].addEventListener('ended', function(){\n sources = this.getElementsByTagName('source');\n for(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('data-orig');\n if (orig) {\n sources[i].setAttribute('src', orig);\n }\n sources[i].setAttribute('data-orig','');\n }\n this.load();\n this.play();\n });\n}\n</script>\n\nAgain, view the example to see the bumper play, followed by our spectacular main feature. (That\u2019s my cat, Widget. His interests include sleeping and internet marketing.)\n\nTidying things up\n\nThe final thing to do is add our closing bumper after the main video has played. This involves the following changes:\n\n\n\tWe need to keep track of whether the src has been changed, so we only play the video if it\u2019s changed. I\u2019ve added the modified variable to track this, and it stops us getting into a situation where the video just loops forever.\n\tAdd an else to the event listener, for when the orig is false (so the main feature has been playing) to load in the end bumper. We also check that we\u2019re not already playing the end bumper. Because looping.\n\n\n<script>\nvar videos, sources, i, l, orig, current, modified;\nsources = document.getElementsByTagName('source');\nfor(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('src');\n sources[i].setAttribute('data-orig', orig);\n sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));\n}\nvideos = document.getElementsByTagName('video');\nfor(i=0, l=videos.length; i<l; i++) {\n videos[i].load();\n modified = false;\n videos[i].addEventListener('ended', function(){\n sources = this.getElementsByTagName('source');\n for(i=0, l=sources.length; i<l; i++) {\n orig = sources[i].getAttribute('data-orig');\n if (orig) {\n sources[i].setAttribute('src', orig);\n modified = true;\n }else{\n current = sources[i].getAttribute('src');\n if (current.indexOf('bumper-out')==-1) {\n sources[i].setAttribute('src', current.replace(/([w]+).(w+)/, 'bumper-out.$2'));\n modified = true;\n }else{\n this.pause();\n modified = false;\n }\n }\n sources[i].setAttribute('data-orig','');\n }\n if (modified) {\n this.load();\n this.play();\n }\n });\n}\n</script>\n\nYo ho ho, that\u2019s a lot of JavaScript. See it in action \u2013 you should get a bumper, the cat video, and an end bumper.\n\nOf course, this code works fine for demonstrating the principle, but it\u2019s very procedural. Nothing wrong with that, but to do something similar in production, you\u2019d probably want to make the code more modular to ease maintainability. Besides, you may want to use a framework, rather than basic JavaScript. \n\nThe end credits\n\nOne really important principle here is that of progressive enhancement. If the browser doesn\u2019t support JavaScript, the user won\u2019t see your bumper, but they will get the main video. If the browser supports JavaScript but doesn\u2019t allow you to modify the src (as was the case with older versions of iOS), the user won\u2019t see your bumper, but they will get the main video.\n\nIf a search engine or social media bot grabs your page and looks for content, they won\u2019t see your bumper, but they will get the main video \u2013 which is absolutely what you want.\n\nThis means that if the bumper is absolutely crucial, you may still need to cook it into the video. However, for many applications, running it dynamically can work quite well.\n\nAs always, it comes down to three things:\n\n\n\tMeasure your audience: know how people access your site\n\tTest the solution: make sure it works for your audience\n\tPlan for failure: it\u2019s the web and that\u2019s how things work \u2018round these parts\n\n\nBut most of all play around with it, have fun and build something awesome.", "year": "2012", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2012-12-01T00:00:00+00:00", "url": "https://24ways.org/2012/html5-video-bumpers/", "topic": "code"} {"rowid": 83, "title": "Cut Copy Paste", "contents": "Long before I got into this design thing, I was heavily into making my own music inspired by the likes of Coldcut and Steinski. I would scour local second-hand record shops in search of obscure beats, loops and bits of dialogue in the hope of finding that killer sample I could then splice together with other things to make a huge hit that everyone would love. While it did eventually lead to a record contract and getting to release a few 12\u2033 singles, ultimately I knew I\u2019d have to look for something else to pay the bills.\n\nI may not make my own records any more, but the approach I took back then \u2013 finding (even stealing) things, cutting and pasting them into interesting combinations \u2013 is still at the centre of how I work, only these days it\u2019s pretty much bits of code rather than bits of vinyl. Over the years I\u2019ve stored these little bits of code (some I\u2019ve found, some I\u2019ve created myself) in Evernote, ready to be dialled up whenever I need them. \n\nSo when Drew got in touch and asked if I\u2019d like to do something for this year\u2019s 24 ways I thought it might be kind of cool to share with you a few of these snippets that I find really useful. Think of these as a kind of coding mix tape; but remember \u2013 don\u2019t just copy as is: play around, combine and remix them into other wonderful things. \n\nSome of this stuff is dirty; some of it will make hardcore programmers feel ill. For those people, remember this \u2013 while you were complaining about the syntax, I made something.\n\nCreate unique colours\n\nLet\u2019s start right away with something I stole. Well, actually it was given away at the time by Matt Biddulph who was then at Dopplr before Nokia destroyed it. Imagine you have thousands of words and you want to assign each one a unique colour. Well, Matt came up with a crazily simple but effective way to do that using an MD5 hash. Just encode said word using an MD5 hash, then take the first six characters of the string you get back to create a hexadecimal colour representation. \n\nI can\u2019t guarantee that it will be a harmonious colour palette, but it\u2019s still really useful. The thing I love the most about this technique is the left-field thinking of using an encryption system to create colours! Here\u2019s an example using JavaScript:\n\n// requires the MD5 library available at http://pajhome.org.uk/crypt/md5\n\n function MD5Hex(str){\n result = MD5.hex(str).substring(0, 6);\n return result;\n }\n\nMake something breathe using a sine wave\n\nI never paid attention in school, especially during double maths. As a matter of fact, the only time I received corporal punishment \u2013 several strokes of the ruler \u2013 was in maths class. Anyway, if they had shown me then how beautiful mathematics actually is, I might have paid more attention. Here\u2019s a little example of how a sine wave can be used to make something appear to breathe. \n\nI recently used this on an Arduino project where an LED ring surrounding a button would gently breathe. Because of that it felt much more inviting. I love mathematics.\n\nfor(int i = 0; i<360; i++){ \n float rad = DEG_TO_RAD * i;\n int sinOut = constrain((sin(rad) * 128) + 128, 0, 255);\n analogWrite(LED, sinOut);\n delay(10); \n}\n\nSnap position to grid\n\nThis is so elegant I love it, and it was shown to me by Gary Burgess, or Boom Boom as myself and others like to call him. It snaps a position, in this case the X-position, to a grid. Just define your grid size (say, twenty pixels) and you\u2019re good.\n\nsnappedXpos = floor( xPos / gridSize) * gridSize;\n\nCalculate the distance between two objects\n\nFor me, interaction design is about the relationship between two objects: you and another object; you and another person; or simply one object to another. How close these two things are to each other can be a handy thing to know, allowing you to react to that information within your design. Here\u2019s how to calculate the distance between two objects in a 2-D plane:\n\ndeltaX = round(p2.x-p1.x);\ndeltaY = round(p2.y-p1.y);\ndiff = round(sqrt((deltaX*deltaX)+(deltaY*deltaY)));\n\nFind the X- and Y-position between two objects\n\nWhat if you have two objects and you want to place something in-between them? A little bit of interruption and disruption can be a good thing. This small piece of code will allow you to place an object in-between two other objects:\n\n// set the position: 0.5 = half-way\t\n\nfloat position = 0.5;\nfloat x = x1 + (x2 - x1) *position; \nfloat y = y1 + (y2 - y1) *position; \n\nDistribute objects equally around a circle \t\n\nMore fun with maths, this time adding cosine to our friend sine. Let\u2019s say you want to create a circular navigation of arbitrary elements (yeah, Jakob, you heard), or you want to place images around a circle. Well, this piece of code will do just that. You can adjust the size of the circle by changing the distance variable and alter the number of objects with the numberOfObjects variable. Example below is for use in Processing.\n\n// Example for Processing available for free download at processing.org\n\nvoid setup() {\n\n size(800,800);\n int numberOfObjects = 12;\n int distance = 100;\n float inc = (TWO_PI)/numberOfObjects;\n float x,y;\n float a = 0;\n\n for (int i=0; i < numberOfObjects; i++) {\n x = (width/2) + sin(a)*distance;\n y = (height/2) + cos(a)*distance;\n ellipse(x,y,10,10);\n a += inc;\n\n }\n}\n\nUse modulus to make a grid\n\nThe modulus operator, represented by %, returns the remainder of a division. Fallen into a coma yet? Hold on a minute \u2013 this seemingly simple function is very powerful in lots of ways. At a simple level, you can use it to determine if a number is odd or even, great for creating alternate row colours in a table for instance:\n\nboolean checkForEven(numberToCheck) {\n if (numberToCheck % 2 == 0) \n return true;\n } else {\n return false; \n }\n}\n\nThat\u2019s all well and good, but here\u2019s a use of modulus that might very well blow your mind. Construct a grid with only a few lines of code. Again the example is in Processing but can easily be ported to any other language.\n\nvoid setup() {\n\nsize(600,600);\nint numItems = 120;\nint numOfColumns = 12;\nint xSpacing = 40;\nint ySpacing = 40;\nint totalWidth = xSpacing*numOfColumns;\n\nfor (int i=0; i < numItems; i++) {\n\nellipse(floor((i*xSpacing)%totalWidth),floor((i*xSpacing)/totalWidth)*ySpacing,10,10);\n\n}\n}\n\nNot all the bits of code I keep around are for actual graphical output. I also have things that are very utilitarian, but which I still consider part of the design process. Here\u2019s a couple of things that I\u2019ve found really handy lately in my design workflow. They may be a little specific, but I hope they demonstrate that it\u2019s not about working harder, it\u2019s about working smarter. \n\nMerge CSV files into one file\n\nRecently, I\u2019ve had to work with huge \u2013 about 1GB \u2013 CSV text files that I then needed to combine into one master CSV file so I could then process the data. Opening up each text file and then copying and pasting just seemed really dumb, not to mention slow, so I thought there must be a better way. After some Googling I found this command line script that would combine .txt files into one file and add a new line after each: \n\nawk 1 *.txt > finalfile.txt\n\nBut that wasn\u2019t what I was ideally after. I wanted to merge the CSV files, keeping the first row of the first file (the column headings) and then ignore the first row of subsequent files. Sure enough I found the answer after some Googling and it worked like a charm. Apologies to the original author but I can\u2019t remember where I found it, but you, sir or madam, are awesome. Save this as a shell script:\n\nFIRST=\n\nfor FILE in *.csv\n do\n exec 5<\"$FILE\" # Open file\n read LINE <&5 # Read first line\n [ -z \"$FIRST\" ] && echo \"$LINE\" # Print it only from first file\n FIRST=\"no\"\n\n cat <&5 # Print the rest directly to standard output\n exec 5<&- # Close file\n # Redirect stdout for this section into file.out \n\ndone > file.out\n\nCreate a symbolic link to another file or folder\n\nOftentimes, I\u2019ll find myself hunting through a load of directories to load a file to be processed, like a CSV file. Use a symbolic link (in the Terminal) to place a link on your desktop or wherever is most convenient and it\u2019ll save you loads of time. Especially great if you\u2019re going through a Java file dialogue box in Processing or something that doesn\u2019t allow the normal Mac dialog box or aliases.\n\ncd /DirectoryYouWantShortcutToLiveIn\nln -s /Directory/You/Want/ShortcutTo/ TheShortcut\n\nYou can do it, in the mix\n\nI hope you\u2019ve found some of the above useful and that they\u2019ve inspired a few ideas here and there. Feel free to tell me better ways of doing things or offer up any other handy pieces of code. Most of all though, collect, remix and combine the things you discover to make lovely new things.", "year": "2012", "author": "Brendan Dawes", "author_slug": "brendandawes", "published": "2012-12-17T00:00:00+00:00", "url": "https://24ways.org/2012/cut-copy-paste/", "topic": "code"} {"rowid": 86, "title": "Flashless Animation", "contents": "Animation in a Flashless world\n\nWhen I splashed down in web design four years ago, the first thing I wanted to do was animate a cartoon in the browser. I\u2019d been drawing comics for years, and I\u2019ve wanted to see them come to life for nearly as long. Flash animation was still riding high, but I didn\u2019t want to learn Flash. I wanted to learn JavaScript!\n\nSadly, animating with JavaScript was limiting and resource-intensive. My initial foray into an infinitely looping background did more to burn a hole in my CPU than amaze my friends (although it still looks pretty cool). And there was still no simple way to incorporate audio. The browser technology just wasn\u2019t there.\n\nThings are different now. CSS3 transitions and animations can do most of the heavy lifting and HTML5 audio can serve up the music and audio clips. You can do a lot without leaning on JavaScript at all, and when you lean on JavaScript, you can do so much more!\n\nIn this project, I\u2019m going to show you how to animate a simple walk cycle with looping audio. I hope this will inspire you to do something really cool and impress your friends. I\u2019d love to see what you come up with, so please send your creations my way at rachelnabors.com!\n\nNote: Because every browser wants to use its own prefixes with CSS3 animations, and I have neither the time nor the space to write all of them out, I will use the W3C standard syntaxes; that is, going prefix-less. You can implement them out of the box with something like Prefixfree, or you can add prefixes on your own. If you take the latter route, I recommend using Sass and Compass so you can focus on your animations, not copying and pasting.\n\nThe walk cycle\n\nWalk cycles are the \u201cHello world\u201d of animation. One of the first projects of animation students is to spend hours drawing dozens of frames to complete a simple loopable animation of a character walking.\n\nMost animators don\u2019t have to draw every frame themselves, though. They draw a few key frames and send those on to production animators to work on the between frames (or tween frames). This is meticulous, grueling work requiring an eye for detail and natural movement. This is also why so much production animation gets shipped overseas where labor is cheaper.\n\nLuckily, we don\u2019t have to worry about our frame count because we can set our own frames-per-second rate on the fly in CSS3. Since we\u2019re trying to impress friends, not animation directors, the inconsistency shouldn\u2019t be a problem. (Unless your friend is an animation director.)\n\nThis is a simple walk cycle I made of my comic character Tuna for my CSS animation talk at CSS Dev Conference this year:\n\n\n\nThe magic lies here:\n\nanimation: walk-cycle 1s steps(12) infinite;\n\nBreaking those properties down:\n\nanimation: <name> <duration> <timing-function> <iteration-count>;\n\nwalk-cycle is a simple @keyframes block that moves the background sprite on .tuna around:\n\n@keyframes walk-cycle { \n 0% {background-position: 0 0; }\n 100% {background-position: 0 -2391px;}\n}\n\nThe background sprite has exactly twelve images of Tuna that complete a full walk cycle. We\u2019re setting it to cycle through the entire sprite every second, infinitely. So why isn\u2019t the background image scrolling down the .tuna container? It\u2019s all down to the timing function steps(). Using steps() let us tell the CSS to make jumps instead of the smooth transitions you\u2019d get from something like linear. Chris Mills at dev.opera wrote in his excellent intro to CSS3 animation :\n\n\n\tInstead of giving a smooth animation throughout, [steps()] causes the animation to jump between a set number of steps placed equally along the duration. For example, steps(10) would make the animation jump along in ten equal steps. There\u2019s also an optional second parameter that takes a value of start or end. steps(10, start) would specify that the change in property value should happen at the start of each step, while steps(10, end) means the change would come at the end.\n\n\n(Seriously, go read his full article. I\u2019m not going to touch on half the stuff he does because I cannot improve on the basics any more than he already has.)\n\nThe background\n\nA cat walking in a void is hardly an impressive animation and certainly your buddy one cube over could do it if he chopped up some of those cat GIFs he keeps using in group chat. So let\u2019s add a parallax background! Yes, yes, all web designers signed a peace treaty to not abuse parallax anymore, but this is its true calling\u2014treaty be damned.\n\n\n\nAnd to think we used to need JavaScript to do this! It\u2019s still pretty CPU intensive but much less complicated. We start by splitting up the page into different layers, .foreground, .midground, and .background. We put .tuna in the .midground.\n\n.background has multiple background images, all set to repeat horizontally:\n\nbackground-image:\n url(background_mountain5.png),\n url(background_mountain4.png),\n url(background_mountain3.png),\n url(background_mountain2.png),\n url(background_mountain1.png);\nbackground-repeat: repeat-x;\n\nWith parallax, things in the foreground move faster than those in the background. Next time you\u2019re driving, notice how the things closer to you move out of your field of vision faster than something in the distance, like a mountain or a large building. We can imitate that here by making the background images on top (in the foreground, closer to us) wider than those on the bottom of the stack (in the distance).\n\nThe different lengths let us use one animation to move all the background images at different rates in the same interval of time: \n\nanimation: parallax_bg linear 40s infinite;\n\nThe shorter images have less distance to cover in the same amount of time as the longer images, so they move slower.\n\n\n\nLet\u2019s have a look at the background\u2019s animation:\n\n@keyframes parallax_bg { \n 0% {\n background-position: -2400px 100%, -2000px 100%, -1800px 100%, -1600px 100%, -1200px 100%;\n }\n 100% {\n background-position: 0 100%, 0 100%, 0 100%, 0 100%, 0 100%;\n }\n}\n\nAt 0%, all the background images are positioned at the negative value of their own widths. Then they start moving toward background-position: 0 100%. If we wanted to move them in the reverse direction, we\u2019d remove the negative values at 0% (so they would start at 2400px 100%, 2000px 100%, etc.). Try changing the values in the codepen above or changing background-repeat to none to see how the images play together.\n\n.foreground and .midground operate on the same principles, only they use single background images.\n\nThe music\n\nAfter finishing the first draft of my original walk cycle, I made a GIF with it and posted it on YTMND with some music from the movie Paprika, specifically the track \u201cThe Girl in Byakkoya.\u201d After showing it to some colleagues in my community, it became clear that this was a winning combination sure to drive away dresscode blues. So let\u2019s use HTML5 to get a clip of that music looping in there!\n\nWarning, there is sound. Please adjust your volume or apply headphones as needed.\n\n\n\nWe\u2019re using HTML5 audio\u2019s loop and autoplay abilities to automatically play and loop a sound file on page load:\n\n<audio loop autoplay>\n <source src=\"http://music.com/clip.mp3\" />\n</audio>\n\nUnfortunately, you may notice there is a small pause between loops. HTML5 audio, thou art half-baked still. Let\u2019s hope one day the Web Audio API will be able to help us out, but until things improve, we\u2019ll have to hack our way around these shortcomings.\n\nTurns out there\u2019s a handy little script called seamlessLoop.js which we can use to patch this. Mind you, if we were really getting crazy with the Cheese Whiz, we\u2019d want to get out big guns like sound.js. But that\u2019d be overkill for a mere loop (and explaining the Web Audio API might bore, rather than impress your friends)!\n\nInstalling seamlessLoop.js will get rid of the pause, and now our walk cycle is complete.\n\n(I\u2019ve done some very rough sniffing to see if the browser can play MP3 files. If not, we fall back to using .ogg formatted clips (Opera and Firefox users, you\u2019re welcome).)\n\nReally impress your friends by adding a run cycle\n\nSo we have music, we have a walk cycle, we have parallax. It will be a snap to bring them all together and have a simple, endless animation. But let\u2019s go one step further and knock the socks off our viewers by adding a run cycle.\n\nThe run cycle\n\nTacking a run cycle on to our walk cycle will require a third animation sequence: a transitional animation of Tuna switching from walking to running. I have added all these to the sprite:\n\n\n\nLet\u2019s work on getting that transition down. We\u2019re going to use multiple animations on the same .tuna div, but we\u2019re going to kick them off at different intervals using animation-delay\u2014no JavaScript required! Isn\u2019t that magical?\n\n\n\nIt requires a wee bit of math (not much, it doesn\u2019t hurt) to line them up. We want to:\n\n\n\tLoop the walk animation twice\n\tPlay the transitional cycle once (it has a finite beginning and end perfectly drawn to pick up between the last frame of the walk cycle and the first frame of the run cycle\u2014no looping this baby)\n\tRUN FOREVER.\n\n\nUsing the pattern animation: <name> <duration> <timing-function> <delay> <iteration-count>, here\u2019s what that looks like:\n\nanimation:\n walk-cycle 1s steps(12) 2,\n walk-to-run .75s steps(12) 2s 1,\n run-cycle .75s steps(13) 2.75s infinite;\n\nI played with the times to get make the movement more realistic. You may notice that the running animation looks smoother than the walking animation. That\u2019s because it has 13 keyframes running over .75 second instead of 12 running in one second. Remember, professional animation studios use super-high frame counts. This little animation isn\u2019t even up to PBS\u2019s standards!\n\nThe music: extended play with HTML5 audio sprites\n\nMy favorite part in the The Girl in Byakkoya is when the calm opening builds and transitions into a bouncy motif. I want to start with Tuna walking during the opening, and then loop the running and bounciness together for infinity.\n\n\n\tThe intro lasts for 24 seconds, so we set our 1 second walk cycle to run for 24 repetitions: \nwalk-cycle 1s steps(12) 24\n\tWe delay walk-to-run by 24 seconds so it runs for .75 seconds before\u2026\n\tWe play run-cycle at 24.75 seconds and loop it infinitely\n\n\nFor the music, we need to think of it as two parts: the intro and the bouncy loop. We can do this quite nicely with audio sprites: using one HTML5 audio element and using JavaScript to change the play head location, like skipping tracks with a CD player. Although this technique will result in a small gap in music shifts, I think it\u2019s worth using here to give you some ideas.\n\n// Get the audio element\nvar byakkoya = document.querySelector('audio');\n// create function to play and loop audio\nfunction song(a){\n //start playing at 0\n a.currentTime = 0;\n a.play();\n //when we hit 64 seconds...\n setTimeout(function(){\n // skip back to 24.5 seconds and keep playing...\n a.currentTime = 24.55;\n // then loop back when we hit 64 again, or every 59.5 seconds.\n setInterval(function(){\n a.currentTime = 24.55;\n },39450);\n },64000);\n}\n\nThe load screen\n\nI\u2019ve put it off as long as I can, but now that the music and the CSS are both running on their own separate clocks, it\u2019s imperative that both images and music be fully downloaded and ready to run when we kick this thing off. So we need a load screen (also, it\u2019s nice to give people a heads-up that you\u2019re about to blast them with music, no matter how wonderful that music may be).\n\nSince the two timers are so closely linked, we\u2019d best not run the animations until we run the music:\n\n* { animation-play-state: paused; }\n\nanimation-play-state can be set to paused or running, and it\u2019s the most useful thing you will learn today.\n\nFirst we use an event listener to see when the browser thinks we can play through from the beginning to end of the music without pause for buffering:\n\nbyakkoya.addEventListener(\"canplaythrough\", function () { });\n\n(More on HTML5 audio\u2019s media events at HTML5doctor.com)\n\nInside our event listener, I use a bit of jQuery to add class of .playable to the body when we\u2019re ready to enable the play button:\n\n$(\"body\").addClass(\"playable\");\n $(\"#play-me\").html(\"Play me.\").click(function(){\n song(byakkoya);\n $(\"body\").addClass(\"playing\");\n });\n\nThat .playing class is special because it turns on the animations at the same time we start playing the song:\n\n.playing * { animation-play-state: running; }\n\nThe background\n\nWe\u2019re almost done here! When we add the background, it needs to speed up at the same time that Tuna starts running. The music picks up speed around 24.75 seconds in, and so we\u2019re going to use animation-delay on those backgrounds, too.\n\nThis will require some math. If you try to simply shorten the animation\u2019s duration at the 24.75s mark, the backgrounds will, mid-scroll, jump back to their initial background positions to start the new animation! Argh! So let\u2019s make a new @keyframe and calculate where the background position would be just before we speed up the animation.\n\nHere\u2019s the formula:\n\nnew 0% value = delay \u00f7 old duration \u00d7 length of image\n\nnew 100% value = new 0% value + length of image\n\nHere\u2019s the formula put to work on a smaller scale:\n\n\n\nVoil\u00e0! The finished animation!\n\n\n\nI\u2019ve always wanted to bring my illustrations to life. Then I woke up one morning and realized that I had all the tools to do so in my browser and in my head. Now I have fallen in love with Flashless animation.\n\nI\u2019m sure there will be detractors who say HTML wasn\u2019t meant for this and it\u2019s a gross abuse of the DOM! But I say that these explorations help us expand what we expect from devices and software and challenge us in good ways as artists and programmers. The browser might not be the most appropriate place for animation, but is certainly a fun place to start.\n\nThere is so much you can do with the spec implemented today, and so much of the territory is still unexplored. I have not yet begun to show you everything. In eight months I expect this demo will represent the norm, not the bleeding edge. I look forward to seeing the wonderful things you create.\n\n(Also, someone, please, do something about that gappy HTML5 audio looping. It\u2019s a crying shame!)", "year": "2012", "author": "Rachel Nabors", "author_slug": "rachelnabors", "published": "2012-12-06T00:00:00+00:00", "url": "https://24ways.org/2012/flashless-animation/", "topic": "code"} {"rowid": 89, "title": "Direction, Distance and Destinations", "contents": "With all these new smartphones in the hands of lost and confused owners, we need a better way to represent distances and directions to destinations. The immediate examples that jump to mind are augmented reality apps which let you see another world through your phone\u2019s camera. While this is interesting, there is a simpler way: letting people know how far away they are and if they are getting warmer or colder. \n\nIn the app world, you can easily tap into the phone\u2019s array of sensors such as the GPS and compass, but what people rarely know is that you can do the same with HTML. The native versus web app debate will never subside, but at least we can show you how to replicate some of the functionality progressively in HTML and JavaScript.\n\nIn this tutorial, we\u2019ll walk through how to create a simple webpage listing distances and directions of a few popular locations around the world. We\u2019ll use JavaScript to access the device\u2019s geolocation API and also attempt to access the compass to get a heading. Both of these APIs are documented, to be included in the W3C geolocation API specification, and can be used on both desktop and mobile devices today.\n\nTo get started, we need a list of a few locations around the world. I have chosen the highest mountain peak on each continent so you can see a diverse set of distances and directions. \n\n\n\t\t\n\t\t\tMountain \n\t\t\t\u00b0Latitude \n\t\t\t\u00b0Longitude \n\t\t\n\t\t\n\t\t\tKilimanjaro\n\t\t\t-3.075833\n\t\t\t37.353333\n\t\t\n\t\t\n\t\t\tVinson Massif\n\t\t\t-78.525483\n\t\t\t-85.617147\n\t\t\n\t\t\n\t\t\tPuncak Jaya\n\t\t\t-4.078889\n\t\t\t137.158333\n\t\t\n\t\t\n\t\t\tEverest\n\t\t\t27.988056\n\t\t\t86.925278\n\t\t\n\t\t\n\t\t\tElbrus\n\t\t\t43.355\n\t\t\t42.439167\n\t\t\n\t\t\n\t\t\tMount McKinley\n\t\t\t63.0695\n\t\t\t-151.0074\n\t\t\n\t\t\n\t\t\tAconcagua\n\t\t\t-32.653431\n\t\t\t-70.011083\n\t\t\n\n\nSource: Wikipedia \n\nWe can put those into an HTML list to be styled and accessed by JavaScript to create some distance and directions calculations.\n\nThe next thing we need to do is check to see if the browser and operating system have geolocation support. To do this we test to see if the function is available or not using a single JavaScript if statement.\n\n<script>\n// If this is true, then the method is supported and we can try to access the location\nif (navigator.geolocation) {\n\tnavigator.geolocation.getCurrentPosition(geo_success, geo_error);\n}\n</script>\n\nThe if statement will be false if geolocation support is not present, and then it is up to you to do something else instead as a fallback. For this example, we\u2019ll do nothing since our page should work as is and only get progressively better if more functionality is available. \n\nThe if statement will be true if there is support and therefore will continue inside the curly brackets to try to get the location. This should prompt the reader to accept or deny the request to get their location. If they say no, the second function callback is processed, in this case a function called geo_error; whereas if the location is available, it fires the geo_success function callback.\n\nThe function geo_error(){ } isn\u2019t that exciting. You can handle this in any way you see fit. The success function is more interesting. We get a position object passed into the function which contains a series of exciting attributes, namely the latitude and longitude of the device\u2019s current location.\n\nfunction geo_success(position){\n\tgLat = position.coords.latitude;\n\tgLon = position.coords.longitude;\n}\n\nNow, in the variables gLat and gLon we have the user\u2019s approximate geographical position. We can use this information to start to calculate some distances between where they are and all the destinations.\n\nAt the time of writing, you can also get position.coords.heading, but on Windows and iOS devices this returned NULL. In the future, if and when this is supported, this is also where you can easily grab the compass information.\n\nInside the geo_success function, we want to loop through the HTML to get all of the mountain peaks\u2019 latitudes and longitudes and compute the distance.\n\n...\n$('.geo').each(function(){\n\t// Get the lat/lon from the HTML\n\ttLat = $(this).find('.lat').html()\n\ttLon = $(this).find('.lon').html()\n\n\t// compute the distances between the current location and this points location\n\tdist = distance(tLat,tLon,gLat,gLon);\n\n\t// set the return values into something useful\n\td = parseInt(dist[0]*10)/10;\n\ta = parseFloat(dist[1]);\n\n\t// display the value in the HTML and style the arrow\n\t$(this).find('.distance').html(d+' km away');\n\t$(this).find('.direction').css('-webkit-transform','rotate(-' + a + 'deg)');\n\n\t// store the arc for later use if compass is available\n\t$(this).attr('data-arc',a);\n}\n\nIn the variable d we have the distance between the current location and the location of the mountain peak based on the Haversine Formula. The variable a is the arc, which has a value from 0 to 359.99. This will be useful later if we have compass support. Given these two values we have a distance and a heading to style the HTML.\n\nThe next thing we want to do is check to see if the device has a compass and then get access to the the current heading. As we\u2019ll see, there are several ways to do this, some of which work on certain devices but not others. The W3C geolocation spec says that, along with the coordinates, there are several other attributes: accuracy; altitude; and heading. Heading is the direction to true north, which is different than magnetic north! WebKit and Windows return NULL for the heading value, but WebKit has an experimental method to fetch the heading. If you get into accessing these sensors, you\u2019ll have to try to catch a few of these methods to finally get a value. Assuming you do, we can move on to the more interesting display opportunities.\n\nIn an ideal world, this would succeed and set a variable we\u2019ll call compassHeading to get a value between 0 and 359.99 degrees. Now we know which direction north is, we also know the direction relative to north of the path to our destination, so we can can subtract the two values to get an arrow to display on the screen. But we\u2019re not finished yet: we also need to get the device\u2019s orientation (landscape or portrait) and subtract the correct amount from the angle for the arrow. Once we have a value, we can use CSS to rotate the arrow the correct number of degrees.\n\n-webkit-transform: rotate(-180deg)\n\nNot all devices support a standard way to access compass information, so in the meantime we need to use a work around. On iOS, you can use the experimental event method e.webkitCompassHeading. We want the compass to update in real time as the device is moved around, so we\u2019ll put this inside an event listener.\n\nwindow.addEventListener('deviceorientation', function(e) {\n\t// Loop through all the locations on the page\n\t$('.geo').each(function(){\n\t\t// get the arc value from north we computed and stored earlier\n\t\tdestination_arc = parseInt($(this).attr('data-arc'))\n\t\tcompassHeading = e.webkitCompassHeading + window.orientation + destination_arc;\n\t\t// find the arrow element and rotate it accordingly\n\t\t$(this).find('.direction').css('-webkit-transform','rotate(-' + compassHeading + 'deg)');\t\t\n\t}\n}\n\nAs the device is rotated, the compass arrow will constantly be updated. If you want to see an example, you can have a look at this page which shows the distances to all the peaks on each continent.\n\nWith progressive enhancement, we slowly layer on additional functionality as we go. The reader will first see the list of locations with a latitude and longitude. If the device is capable and permissions allow, it will then compute the distance. If a compass is available, with the correct permissions it will then add the final layer which is direction.\n\nYou should consider this code a stub for your projects. If you are making a hyperlocal webpage with restaurant locations, for example, then consider adding these features. Knowing not only how far away a place is, but also the direction can be hugely important, and since the compass is always active, it acts as a guide to the location. \n\nFuture developments\n\nImprovements to this could include setting a timer and recalling the navigator.geolocation.getCurrentPosition() function and updating the distances. I chose very distant mountains so kilometres made sense, but you can divide again by 1,000 to convert to metres if you are dealing with much nearer places. Walking or driving would change the distances so the ability to refresh would be important. \n\nIt is outside the scope of this article, but if you manage to get this HTML to work offline, then you can make a nice web app which sits on your devices\u2019 homescreens and works even without an internet connection. This could be ideal for travellers in an unknown city looking for your destination. Just with offline storage, base64 encoding and data URIs, it is possible to embed plenty of design and functionality into a small offline webpage.\n\nNow you know how to use JavaScript to look up a destination\u2019s location and figure out the distance and direction \u2013 never get lost again.", "year": "2012", "author": "Brian Suda", "author_slug": "briansuda", "published": "2012-12-19T00:00:00+00:00", "url": "https://24ways.org/2012/direction-distance-and-destinations/", "topic": "code"} {"rowid": 91, "title": "Infinite Canvas: Moving Beyond the Page", "contents": "Remember Web 2.0? I do. In fact, that phrase neatly bifurcates my life on the internet. Pre-2.0, I was occupied by chatting on AOL and eventually by learning HTML so I could build sites on Geocities. Around 2002, however, I saw a WYSIWYG demo in Dreamweaver. The instructor was dragging boxes and images around a canvas. With a few clicks he was able to build a dynamic, single-page interface. Coming from the world of tables and inline HTML styles, I was stunned.\n\nAs I entered college the next year, the web was blossoming: broadband, Wi-Fi, mobile (proud PDA owner, right here), CSS, Ajax, Bloglines, Gmail and, soon, Google Maps. I was a technology fanatic and a hobbyist web developer. For me, the web had long been informational. It was now rapidly becoming something else, something more: sophisticated, presentational, actionable.\n\nIn 2003 we watched as the internet changed. The predominant theme of those early Web 2.0 years was the withering of Internet Explorer 6 and the triumph of web standards. Upon cresting that mountain, we looked around and collectively breathed the rarefied air of pristine HMTL and CSS, uncontaminated by toxic hacks and forks \u2013 only to immediately begin hurtling down the other side at what is, frankly, terrifying speed.\n\nTen years later, we are still riding that rocket. Our days (and nights) are spent cramming for exams on CSS3 and RWD and Sass and RESS. We are the proud, frazzled owners of tiny pocket computers that annihilate the best laptops we could have imagined, and the architects of websites that are no longer restricted to big screens nor even segregated by device. We dragoon our sites into working any time, anywhere. At this point, we can hardly ask the spec developers to slow down to allow us to catch our breath, nor should we. It is, without a doubt, a most wonderful time to be a web developer.\n\nBut despite the newfound luxury of rounded corners, gradients, embeddable fonts, low-level graphics APIs, and, glory be, shadows, the canyon between HTML and native appears to be as wide as ever. The improvements in HTML and CSS have, for the most part, been conveniences rather than fundamental shifts. What I\u2019d like to do now, if you\u2019ll allow me, is outline just a few of the remaining gaps that continue to separate web sites and applications from their native companions.\n\nWhat I\u2019d like for Christmas\n\nThere is one irritant which is the grandfather of them all, the one from which all others flow and have their being, and it is, simply, the page refresh. That\u2019s right, the foundational principle of the web is our single greatest foe. To paraphrase a patron saint of designers everywhere, if you see a page refresh, we blew it.\n\nThe page refresh brings with it, of course, many noble and lovely benefits: addressability, for one; and pagination, for another. (See also caching, resource loading, and probably half a dozen others.) Still, those concerns can be answered (and arguably answered more compellingly) by replacing the weary page with the young and hearty document. Flash may be dead, but it has many lessons yet to bequeath.\n\nPreparing a single document when the site loads allows us to engage the visitor in a smooth and engrossing experience. We have long known this, of course. Twitter was not the first to attempt, via JavaScript, to envelop the user in a single-page application, nor the first to abandon it. Our shared task is to move those technologies down the stack, to make them more primitive, so that the next Twitter can be built with the most basic combination of HTML and CSS rather than relying on complicated, slow, and unreliable scripted solutions.\n\nSo, let\u2019s take a look at what we can do, right now, that we might have a better idea of where our current tools fall short.\n\nA print magazine in HTML clothing\n\nLike many others, I suspect, one of my earliest experiences with publishing was laying out newsletters and newspapers on a computer for print. If you\u2019ve ever used InDesign or Quark or even Microsoft Publisher, you\u2019ll remember reflowing content from page to page. The advent of the internet signaled, in many ways, the abandonment of that model. Articles were no longer constrained by the physical limitations of paper. In shedding our chains, however, it is arguable that we\u2019ve lost something useful. We had a self-contained and complete package, a closed loop. It was a thing that could be handled and finished, and doing so provided a sense of accomplishment that our modern, infinitely scrolling, ever-fractal web of content has stolen.\n\nFor our purposes today, we will treat 24 ways as the online equivalent of that newspaper or magazine. A single year\u2019s worth of articles could easily be considered an issue. Right now, navigating between articles means clicking on the article you\u2019d like to view and being taken to that specific address via a page reload. If Drew wanted to, it wouldn\u2019t be difficult to update the page in place (via JavaScript) and change the address (again via JavaScript with the History API) to reflect the new content found at the new location. But what if Drew wanted to do that without JavaScript? And what if he wanted the site to not merely load the content but actually whisk you along the page in a compelling and delightful way, \u00e0 la the Mag+ demo we all saw a few years ago when the iPad was first introduced? Uh, no.\n\nWe\u2019re all familiar with websites that have attempted to go beyond the page by weaving many chunks of content together into a large document and for good reason. There is tremendous appeal in opening and exploring the canvas beyond the edges of our screens.\n\nIn one rather straightforward example from last year, Mozilla contacted Full Stop to build a website promoting Aza Raskin\u2019s proposal for a set of Creative Commons-style privacy icons. Like a lot of the sites we build (including our own), the amount of information we were presenting was minimal. In these instances, we encourage our clients to consider including everything on a single page. The result was a horizontally driven site that was, if not whimsical, at least clever and attractive to the intended audience. An experience that is taken for granted when using device-native technology is utterly, maddeningly impossible to replicate on the web without jumping through JavaScript hoops.\n\nIn another, more complex example, we again had the pleasure of working with Aza earlier this year, this time on a redesign of the Massive Health website. Our assignment was to design and build a site that communicated Massive\u2019s commitment to modern personal health. The site had to be visually and interactively stunning while maintaining a usable and clear interface for the casual visitor. Our solution was to extend the infinite company logo into a ribbon that carried the visitor through the site narrative. It also meant we\u2019d be asking the browser to accommodate something it was never designed to handle: a non-linear design. (Be sure to play around. There\u2019s a lot going on under the hood. We were also this close to a ZUI, if WebKit didn\u2019t freak out when pages were scaled beyond 10\u00d7.) Despite the apparent and deliberate design simplicity, the techniques necessary to implement it are anything but. From updating the URL to moving the visitor from section to section, we\u2019re firmly in JavaScript territory. And that\u2019s a shame.\n\nWhat can we do?\n\nWe might not be able to specify these layouts in HTML and CSS just yet, but that doesn\u2019t mean we can\u2019t learn a few new tricks while we wait. Let\u2019s see how close we can come to recreating the privacy icons design, the Massive design, or the Mag+ design without resorting to JavaScript.\n\nA horizontally paginated site\n\nThe first thing we\u2019re going to need is the concept of a page within our HTML document. Using plain old HTML and CSS, we can stack a series of <div>s sideways (with a little assist from our new friend, the viewport-width unit, not that he was strictly necessary). All we need to know is how many pages we have. (And, boy, wouldn\u2019t it be nice to be able to know that without having to predetermine it or use JavaScript?)\n\n.window {\noverflow: hidden;\n width: 100%;\n}\n.pages {\n width: 200vw;\n}\n.page {\n float: left;\n overflow: hidden;\n width: 100vw;\n}\n\nIf you look carefully, you\u2019ll see that the conceit we\u2019ll use in the rest of the demos is in place. Despite the document containing multiple pages, only one is visible at any given time. This allows us to keep the user focused on the task (or content) at hand.\n\nBy the way, you\u2019ll need to use a modern, WebKit-based browser for these demos. I recommend downloading the WebKit nightly builds, Chrome Canary, or being comfortable with setting flags in Chrome.\n\nA horizontally paginated site, with transitions\n\nAh, here\u2019s the rub. We have functional navigation, but precious few cues for the user. It\u2019s not much good shoving the visitor around various parts of the document if they don\u2019t get the pleasant whooshing experience of the journey. You might be thinking, what about that new CSS selector, target-something\u2026? Well, my friend, you\u2019re on the right track. Let\u2019s test it. We\u2019re going to need to use a bit of sleight of hand. While we\u2019d like to simply offset the containing element by the number of pages we\u2019re moving (like we did on Massive), CSS alone can\u2019t give us that information, and that means we\u2019re going to need to fake it by expanding and collapsing pages as you navigate. Here are the bits we\u2019re going to need:\n\n.page {\n -webkit-transition: width 1s; // Naturally you're going to want to include all the relevant prefixes here\n float: left;\n left: 0;\n overflow: hidden;\n position: relative;\n width: 100vw;\n}\n.page:not(:target) {\n width: 0;\n}\n\nAh, but we\u2019re not fooling anyone with that trick. As soon as you move beyond a single page, the visitor\u2019s disbelief comes tumbling down when the linear page transitions are unaffected by the distance the pages are allegedly traveling. And you may have already noticed an even more fatal flaw: I secretly linked you to the first page rather than the unadorned URL. If you visit the same page with no URL fragment, you get a blank screen. Sure, we could force a redirect with some server-side trickery, but that feels like cheating. Perhaps if we had the CSS4 subject selector we could apply styles to the parent based on the child being targeted by the URL. We might also need a few more abilities, like determining the total number of pages and having relative sibling selectors (e.g. nth-sibling), but we\u2019d sure be a lot closer.\n\nA horizontally paginated site, with transitions \u2013 no cheating\n\nWell, what other cards can we play? How about the checkbox hack? Sure, it\u2019s a garish trick, but it might be the best we can do today. Check it out. \n\nlabel {\n cursor: pointer;\n}\ninput {\n display: none;\n}\ninput:not(:checked) + .page {\n max-height: 100vh;\n width: 0;\n}\n\nFinally, we can see the first page thanks to the state we are able to set on the appropriate radio button. Of course, now we don\u2019t have URLs, so maybe this isn\u2019t a winning plan after all. While our HTML and CSS toolkit may feel primitive at the moment, we certainly don\u2019t want to sacrifice the addressability of the web. If there\u2019s one bedrock principle, that\u2019s it.\n\nA horizontally paginated site, with transitions \u2013 no cheating and a gorgeous homepage\n\nGorgeous may not be the right word, but our little magazine is finally shaping up. Thanks to the CSS regions spec, we\u2019ve got an exciting new power, the ability to begin an article in one place and bend it to our will. (Remember, your everyday browser isn\u2019t going to work for these demos. Try the WebKit nightly build to see what we\u2019re talking about.) As with the rest of the examples, we\u2019re clearly abusing these features. Off-canvas layouts (you can thank Luke Wroblewski for the name) are simply not considered to be normal patterns\u2026 yet.\n\nHere\u2019s a quick look at what\u2019s going on:\n\n.excerpt-container {\n float: left;\n padding: 2em;\n position: relative;\n width: 100%;\n}\n.excerpt {\n height: 16em;\n}\n.excerpt_name_article-1,\n.page-1 .article-flow-region {\n -webkit-flow-from: article-1;\n}\n.article-content_for_article-1 {\n -webkit-flow-into: article-1;\n}\n\nThe regions pattern is comprised of at least three components: a beginning; an ending; and a source. Using CSS, we\u2019re able to define specific elements that should be available for the content to flow through. If magazine-style layouts are something you\u2019re interested in learning more about (and you should be), be sure to check out the great work Adobe has been doing.\n\nLooking forward, and backward\n\nAs designers, builders, and consumers of the web, we share a desire to see the usability and enjoyability of websites continue to rise. We are incredibly lucky to be working in a time when a three-month-old website can be laughably outdated. Our goal ought to be to improve upon both the weaknesses and the strengths of the web platform. We seek not only smoother transitions and larger canvases, but fine-grained addressability. Our URLs should point directly and unambiguously to specific content elements, be they pages, sections, paragraphs or words. Moreover, off-screen design patterns are essential to accommodating and empowering the multitude of devices we use to access the web. We should express the desire that interpage links take advantage of the CSS transitions which have been put to such good effect in every other aspect of our designs. Transitions aren\u2019t just nice to have, they\u2019re table stakes in the highly competitive world of native applications. \n\nThe tools and technologies we have right now allow us to create smart, beautiful, useful webpages. With a little help, we can begin removing the seams and sutures that bind the web to an earlier, less sophisticated generation.", "year": "2012", "author": "Nathan Peretic", "author_slug": "nathanperetic", "published": "2012-12-21T00:00:00+00:00", "url": "https://24ways.org/2012/infinite-canvas-moving-beyond-the-page/", "topic": "code"} {"rowid": 92, "title": "Redesigning the Media Query", "contents": "Responsive web design is showing us that designing content is more important than designing containers. But if you\u2019ve given RWD a serious try, you know that shifting your focus from the container is surprisingly hard to do. There are many factors and\ninstincts working against you, and one culprit is a perpetrator you\u2019d least suspect.\n\nThe media query is the ringmaster of responsive design. It lets us establish the rules of the game and gives us what we need most: control. However, like some kind of evil double agent, the media query is actually working against you.\n\nIts very nature diverts your attention away from content and forces you to focus on the container.\n\nThe very act of choosing a media query value means choosing a screen size.\n\nLook at the history of the media query\u2014it\u2019s always been about the container. Values like screen, print, handheld and tv don\u2019t have anything to do with content. The modern media query lets us choose screen dimensions, which is great because it makes RWD possible. But it\u2019s still the act of choosing something that is completely unpredictable.\n\nContent should dictate our breakpoints, not the container. In order to get our focus back to the only thing that matters, we need a reengineered media query\u2014one that frees us from thinking about screen dimensions. A media query that works for your content, not the window. Fortunately, Sass 3.2 is ready and willing to take on this challenge.\n\nThinking in Columns\n\nFluid grids never clicked for me. I feel so disoriented and confused by their squishiness. Responsive design demands their use though, right?\n\nI was ready to surrender until I found a grid that turned my world upright again. The Frameless Grid by Joni Korpi demonstrates that column and gutter sizes can stay fixed. As the screen size changes, you simply add or remove columns to accommodate. This made sense to me and armed with this concept I was able to give Sass the first component it needs to rewrite the media query: fixed column and gutter size variables.\n\n$grid-column: 60px;\n$grid-gutter: 20px;\n\nWe\u2019re going to want some resolution independence too, so let\u2019s create a function that converts those nasty pixel values into ems.\n\n@function em($px, $base: $base-font-size) {\n\t@return ($px / $base) * 1em;\n}\n\nWe now have the components needed to figure out the width of multiple columns in ems. Let\u2019s put them together in a function that will take any number of columns and return the fixed width value of their size.\n\n@function fixed($col) {\n\t@return $col * em($grid-column + $grid-gutter)\n}\n\nWith the math in place we can now write a mixin that takes a column count as a parameter, then generates the perfect media query necessary to fit that number of columns on the screen. We can also build in some left and right margin for our layout by adding an additional gutter value (remembering that we already have one gutter built into our fixed function).\n\n@mixin breakpoint($min) {\n\t@media (min-width: fixed($min) + em($grid-gutter)) {\n\t\t@content\n\t}\n}\n\nAnd, just like that, we\u2019ve rewritten the media query. Instead of picking a minimum screen size for our layout, we can simply determine the number of columns needed. Let\u2019s add a wrapper class so that we can center our content on the screen.\n\n@mixin breakpoint($min) {\n @media (min-width: fixed($min) + em($grid-gutter)) {\n\t.wrapper {\n\t\twidth: fixed($min) - em($grid-gutter);\n\t\tmargin-left: auto; margin-right: auto;\n\t}\n\t@content\n }\n}\n\nDesigning content with a column count gives us nice, easy, whole numbers to work with. Sizing content, sidebars or widgets is now as simple as specifying a single-digit number.\n\n@include breakpoint(8) {\n\t.main { width: fixed(5); }\n\t.sidebar { width: fixed(3); }\n}\n\nThose four lines of Sass just created a responsive layout for us. When the screen is big enough to fit eight columns, it will trigger a fixed width layout. And give widths to our main content and sidebar. The following is the outputted CSS\u2026\n\n@media (min-width: 41.25em) {\n .wrapper {\n width: 38.75em;\n margin-left: auto; margin-right: auto;\n }\n .main { width: 25em; }\n .sidebar { width: 15em; }\n}\n\nDemo\n\nI\u2019ve created a Codepen demo that demonstrates what we\u2019ve covered so far. I\u2019ve added to the demo some grid classes based on Griddle by Nicolas Gallagher to create a floatless layout. I\u2019ve also added a CSS gradient overlay to help you visualize columns. Try changing the column variable sizes or the breakpoint includes to see how the layout reacts to different screen sizes.\n\nResponsive Images\n\nResponsive images are a serious problem, but I\u2019m excited to see the community talk so passionately about a solution. Now, there are some excellent stopgaps while we wait for something official, but these solutions require you to mirror your breakpoints in JavaScript or HTML. This poses a serious problem for my Sass-generated media queries, because I have no idea what the real values of my breakpoints are anymore. For responsive images to work, JavaScript needs to recognize which media query is active so that proper images can be loaded for that layout.\n\nWhat I need is a way to label my breakpoints. Fortunately, people much smarter than I have figured this out. Jeremy Keith devised a labeling method by using CSS-generated content as the storage method for breakpoint labels. We can use this technique in our breakpoint mixin by passing a label as another argument.\n\n@include breakpoint(8, 'desktop') { /* styles */ }\n\nSass can take that label and use it when writing the corresponding media query. We just need to slightly modify our breakpoint mixin.\n\n@mixin breakpoint($min, $label) {\n @media (min-width: fixed($min) + em($grid-gutter)) {\n\n // label our mq with CSS generated content\n\tbody::before { content: $label; display: none; }\n\n\t.wrapper {\n\t\twidth: fixed($min) - em($grid-gutter);\n\t\tmargin-left: auto; margin-right: auto;\n\t}\n\t@content\n }\n}\n\nThis allows us to label our breakpoints with a user-friendly string. Now that our media queries are defined and labeled, we just need JavaScript to step in and read which label is active.\n\n// get css generated label for active media query\nvar label = getComputedStyle(document.body, '::before')['content'];\n\nJavaScript now knows which layout is active by reading the label in the current media query\u2014we just need to match that label to an image. I prefer to store references to different image sizes as data attributes on my image tag.\n\n<img class=\"responsive-image\" data-mobile=\"mobile.jpg\" data-desktop=\"desktop.jpg\" />\n<noscript><img src=\"desktop.jpg\" /></noscript>\n\nThese data attributes have names that match the labels set in my CSS. So while there is some duplication going on, setting a keyword like \u2018tablet\u2019 in two places is much easier than hardcoding media query values. With matching labels in CSS and HTML our script can marry the two and load the right sized image for our layout.\n\n// get css generated label for active media query\nvar label = getComputedStyle(document.body, '::before')['content'];\n\n// select image\nvar $image = $('.responsive-image');\n\n// create source from data attribute\n$image.attr('src', $image.data(label));\n\nDemo\n\nWith some slight additions to our previous Codepen demo you can see this responsive image technique in action. While the above JavaScript will work it is not nearly robust enough for production so the demo uses a jQuery plugin that can accomodate multiple images, reloading on screen resize and fallbacks if something doesn\u2019t match up.\n\nCreating a Framework\n\nThis media query mixin and responsive image JavaScript are the center piece of a front end framework I use to develop websites. It\u2019s a fluid, mobile first foundation that uses the breakpoint mixin to structure fixed width layouts for tablet and desktop. Significant effort was focused on making this framework completely cross-browser. For example, one of the problems with using media queries is that essential desktop structure code ends up being hidden from legacy Internet Explorer. Respond.js is an excellent polyfill, but if you\u2019re comfortable serving a single desktop layout to older IE, we don\u2019t need JavaScript. We simply need to capture layout code outside of a media query and sandbox it under an IE only class name.\n\n// set IE fallback layout to 8 columns\n$ie-support = 8;\n\n// inside of our breakpoint mixin (but outside the media query)\n@if ($ie-support and $min <= $ie-support) {\n\t.lt-ie9 { @content; }\n}\n\nPerspective Regained\n\nThinking in columns means you are thinking about content layout. How big of a screen do you need for 12 columns? Who cares? Having Sass write media queries means you can use intuitive numbers for content layout. A fixed grid means more layout control and less edge cases to test than a fluid grid. Using CSS labels for activating responsive images means you don\u2019t have to duplicate breakpoints across separations of concern. \n\nIt\u2019s a harmonious blend of approaches that gives us something we need\u2014responsive design that feels intuitive. And design that, from the very outset, focuses on what matters most. Just like our kindergarten teachers taught us: It\u2019s what\u2019s inside that counts.", "year": "2012", "author": "Les James", "author_slug": "lesjames", "published": "2012-12-13T00:00:00+00:00", "url": "https://24ways.org/2012/redesigning-the-media-query/", "topic": "code"} {"rowid": 95, "title": "Giving Content Priority with CSS3 Grid Layout", "contents": "Browser support for many of the modules that are part of CSS3 have enabled us to use CSS for many of the things we used to have to use images for. The rise of mobile browsers and the concept of responsive web design has given us a whole new way of looking at design for the web. However, when it comes to layout, we haven\u2019t moved very far at all. We have talked for years about separating our content and source order from the presentation of that content, yet most of us have had to make decisions on source order in order to get a certain visual layout. \n\nOwing to some interesting specifications making their way through the W3C process at the moment, though, there is hope of change on the horizon. In this article I\u2019m going to look at one CSS module, the CSS3 grid layout module, that enables us to define a grid and place elements on to it. This article comprises a practical demonstration of the basics of grid layout, and also a discussion of one way in which we can start thinking of content in a more adaptive way.\n\nBefore we get started, it is important to note that, at the time of writing, these examples work only in Internet Explorer 10. CSS3 grid layout is a module created by Microsoft, and implemented using the -ms prefix in IE10. My examples will all use the -ms prefix, and not include other prefixes simply because this is such an early stage specification, and by the time there are implementations in other browsers there may be inconsistencies. The implementation I describe today may well change, but is also there for your feedback.\n\nIf you don\u2019t have access to IE10, then one way to view and test these examples is by signing up for an account with Browserstack \u2013 the free trial would give you time to have a look. I have also included screenshots of all relevant stages in creating the examples.\n\nWhat is CSS3 grid layout?\n\nCSS3 grid layout aims to let developers divide up a design into a grid and place content on to that grid. Rather than trying to fabricate a grid from floats, you can declare an actual grid on a container element and then use that to position the elements inside. Most importantly, the source order of those elements does not matter. \n\nDeclaring a grid\n\nWe declare a grid using a new value for the display property: display: grid. As we are using the IE10 implementation here, we need to prefix that value: display: -ms-grid;.\n\nOnce we have declared our grid, we set up the columns and rows using the grid-columns and grid-rows properties.\n\n.wrapper {\n display: -ms-grid;\n -ms-grid-columns: 200px 20px auto 20px 200px;\n -ms-grid-rows: auto 1fr;\n}\n\nIn the above example, I have declared a grid on the .wrapper element. I have used the grid-columns property to create a grid with a 200 pixel-wide column, a 20 pixel gutter, a flexible width auto column that will stretch to fill the available space, another 20 pixel-wide gutter and a final 200 pixel sidebar: a flexible width layout with two fixed width sidebars. Using the grid-rows property I have created two rows: the first is set to auto so it will stretch to fill whatever I put into it; the second row is set to 1fr, a new value used in grids that means one fraction unit. In this case, one fraction unit of the available space, effectively whatever space is left.\n\nPositioning items on the grid\n\nNow I have a simple grid, I can pop items on to it. If I have a <div> with a class of .main that I want to place into the second row, and the flexible column set to auto I would use the following CSS:\n\n.content {\n -ms-grid-column: 3;\n -ms-grid-row: 2;\n -ms-grid-row-span: 1;\n}\n\nIf you are old-school, you may already have realised that we are essentially creating an HTML table-like layout structure using CSS. I found the concept of a table the most helpful way to think about the grid layout module when trying to work out how to place elements.\n\nCreating grid systems\n\nAs soon as I started to play with CSS3 grid layout, I wanted to see if I could use it to replicate a flexible grid system like this fluid 16-column 960 grid system.\n\nI started out by defining a grid on my wrapper element, using fractions to make this grid fluid.\n\n.wrapper {\t \n width: 90%;\n margin: 0 auto 0 auto;\n display: -ms-grid;\n -ms-grid-columns: 1fr (4.25fr 1fr)[16];\n -ms-grid-rows: (auto 20px)[24];\n}\n\nLike the 960 grid system I was using as an example, my grid starts with a gutter, followed by the first actual column, plus another gutter repeated sixteen times. What this means is that if I want to span two columns, as far as the grid layout module is concerned that is actually three columns: two wide columns, plus one gutter. So this needs to be accounted for when positioning items.\n\nI created a CSS class for each positioning option: column position; rows position; and column span. For example:\n\n.grid1 {-ms-grid-column: 2;} /* applying this class positions an item in the first column (the gutter is column 1) */\n.grid2 {-ms-grid-column: 4;} /* 2nd column - gutter|column 1|gutter */\n.grid3 {-ms-grid-column: 6;} /* 3rd column - gutter|column 1|gutter|column2|gutter */\n\n.row1 {-ms-grid-row:1;}\n.row2 {-ms-grid-row:3;}\n.row3 {-ms-grid-row:5;}\n\n.colspan1 {-ms-grid-column-span:1;}\n.colspan2 {-ms-grid-column-span:3;}\n.colspan3 {-ms-grid-column-span:5;}\n\nI could then add multiple classes to each element to set the position on on the grid.\n\n\n\nThis then gives me a replica of the fluid grid using CSS3 grid layout. To see this working fire up IE10 and view Example 1.\n\nThis works, but\u2026\n\nThis worked, but isn\u2019t ideal. I considered not showing this stage of my experiment \u2013 however, I think it clearly shows how the grid layout module works and is a useful starting point. That said, it\u2019s not an approach I would take in production. First, we have to add classes to our markup that tie an element to a position on the grid. This might not be too much of a problem if we are always going to maintain the sixteen-column grid, though, as I will show you that the real power of the grid layout module appears once you start to redefine the grid, using different grids based on media queries. If you drop to a six-column layout for small screens, positioning items into column 16 makes no sense any more.\n\nCalculating grid position using LESS\n\nAs we\u2019ve seen, if you want to use a grid with main columns and gutters, you have to take into account the spacing between columns as well as the actual columns. This means we have to do some calculating every time we place an item on the grid. In my example above I got around this by creating a CSS class for each position, allowing me to think in sixteen rather than thirty-two columns. But by using a CSS preprocessor, I can avoid using all the classes yet still think in main columns.\n\nI\u2019m using LESS for my example. My simple grid framework consists of one simple mixin.\n\n.position(@column,@row,@colspan,@rowspan) {\n -ms-grid-column: @column*2;\n -ms-grid-row: @row*2-1;\n -ms-grid-column-span: @colspan*2-1;\n -ms-grid-row-span: @rowspan*2-1;\n}\n\nMy mixin takes four parameters: column; row; colspan; and rowspan. So if I wanted to place an item on column four, row three, spanning two columns and one row, I would write the following CSS:\n\n.box {\n .position(4,3,2,1);\n}\n\nThe mixin would return:\n\n.box {\n -ms-grid-column: 8;\n -ms-grid-row: 5;\n -ms-grid-column-span: 3;\n -ms-grid-row-span: 1;\n}\n\nThis saves me some typing and some maths. I could also add other prefixed values into my mixin as other browsers started to add support.\n\nWe can see this in action creating a new grid. Instead of adding multiple classes to each element, I can add one class; that class uses the mixin to create the position. I have also played around with row spans using my mixin and you can see we end up with a quite complicated arrangement of boxes. Have a look at example two in IE10. I\u2019ve used the JavaScript LESS parser so that you can view the actual LESS that I use. Note that I have needed to escape the -ms prefixed properties with ~\"\" to get LESS to accept them.\n\n\n\nThis is looking better. I don\u2019t have direct positioning information on each element in the markup, just a class name \u2013 I\u2019ve used grid(x), but it could be something far more semantic. We can now take the example a step further and redefine the grid based on screen width.\n\nMedia queries and the grid\n\nThis example uses exactly the same markup as the previous example. However, we are now using media queries to detect screen width and redefine the grid using a different number of columns depending on that width.\n\nI start out with a six-column grid, defining that on .wrapper, then setting where the different items sit on this grid:\n\n.wrapper {\t \n width: 90%;\n margin: 0 auto 0 auto;\n display: ~\"-ms-grid\"; /* escaped for the LESS parser */\n -ms-grid-columns: ~\"1fr (4.25fr 1fr)[6]\"; /* escaped for the LESS parser */\n -ms-grid-rows: ~\"(auto 20px)[40]\"; /* escaped for the LESS parser */\n}\n.grid1 { .position(1,1,1,1); } \n.grid2 { .position(2,1,1,1); } \n/* ... see example for all declarations ... */\n\n\n\nUsing media queries, I redefine the grid to nine columns when we hit a minimum width of 700 pixels.\n\n@media only screen and (min-width: 700px) {\n.wrapper {\n -ms-grid-columns: ~\"1fr (4.25fr 1fr)[9]\";\n -ms-grid-rows: ~\"(auto 20px)[50]\";\n}\n.grid1 { .position(1,1,1,1); } \n.grid2 { .position(2,1,1,1); } \n/* ... */\n}\n\n\n\nFinally, we redefine the grid for 960 pixels, back to the sixteen-column grid we started out with.\n\n@media only screen and (min-width: 940px) {\n.wrapper {\t \n -ms-grid-columns:~\" 1fr (4.25fr 1fr)[16]\";\n -ms-grid-rows:~\" (auto 20px)[24]\";\n}\n.grid1 { .position(1,1,1,1); } \n.grid2 { .position(2,1,1,1); } \n/* ... */\n}\n\nIf you view example three in Internet Explorer 10 you can see how the items reflow to fit the window size. You can also see, looking at the final set of blocks, that source order doesn\u2019t matter. You can pick up a block from anywhere and place it in any position on the grid.\n\nLaying out a simple website\n\nSo far, like a toddler on Christmas Day, we\u2019ve been playing with boxes rather than thinking about what might be in them. So let\u2019s take a quick look at a more realistic layout, in order to see why the CSS3 grid layout module can be really useful. At this time of year, I am very excited to get out of storage my collection of odd nativity sets, prompting my family to suggest I might want to open a museum. Should I ever do so, I\u2019ll need a website, and here is an example layout.\n\n\n\nAs I am using CSS3 grid layout, I can order my source in a logical manner. In this example my document is as follows, though these elements could be in any order I please:\n\n<div class=\"wrapper\">\n <div class=\"welcome\">\n ...\n </div>\n <article class=\"main\">\n ...\n </article>\n <div class=\"info\">\n ...\n </div>\n <div class=\"ads\">\n ...\n </div>\n</div>\n\nFor wide viewports I can use grid layout to create a sidebar, with the important information about opening times on the top righ,t with the ads displayed below it. This creates the layout shown in the screenshot above.\n\n@media only screen and (min-width: 940px) {\n .wrapper {\t \n -ms-grid-columns:~\" 1fr (4.25fr 1fr)[16]\";\n -ms-grid-rows:~\" (auto 20px)[24]\";\n }\n .welcome {\n .position(1,1,12,1);\n padding: 0 5% 0 0;\n }\n .info {\n .position(13,1,4,1);\n border: 0;\n padding:0;\n }\n .main {\n .position(1,2,12,1);\n padding: 0 5% 0 0;\n } \n .ads {\n .position(13,2,4,1);\n display: block;\n margin-left: 0;\n }\n}\n\nIn a floated layout, a sidebar like this often ends up being placed under the main content at smaller screen widths. For my situation this is less than ideal. I want the important information about opening times to end up above the main article, and to push the ads below it. With grid layout I can easily achieve this at the smallest width .info ends up in row two and .ads in row five with the article between.\n\n.wrapper {\t \n display: ~\"-ms-grid\";\n -ms-grid-columns: ~\"1fr (4.25fr 1fr)[4]\";\n -ms-grid-rows: ~\"(auto 20px)[40]\";\n}\n.welcome {\n .position(1,1,4,1);\n}\n.info {\n .position(1,2,4,1);\n border: 4px solid #fff;\n padding: 10px;\n}\n.content {\n .position(1,3,4,5);\n}\n.main {\n .position(1,3,4,1);\n}\n.ads {\n .position(1,4,4,1);\n}\n\n\n\nFinally, as an extra tweak I add in a breakpoint at 600 pixels and nest a second grid on the ads area, arranging those three images into a row when they sit below the article at a screen width wider than the very narrow mobile width but still too narrow to support a sidebar. \n\n@media only screen and (min-width: 600px) {\n .ads {\n display: ~\"-ms-grid\";\n -ms-grid-columns: ~\"20px 1fr 20px 1fr 20px 1fr\";\n -ms-grid-rows: ~\"1fr\";\n margin-left: -20px;\n }\n .ad:nth-child(1) {\n .position(1,1,1,1);\n }\n .ad:nth-child(2) {\n .position(2,1,1,1);\n }\n .ad:nth-child(3) {\n .position(3,1,1,1);\n }\n}\n\nView example four in Internet Explorer 10.\n\n\n\nThis is a very simple example to show how we can use CSS grid layout without needing to add a lot of classes to our document. It also demonstrates how we can mainpulate the content depending on the context in which the user is viewing it.\n\nLayout, source order and the idea of content priority\n\nCSS3 grid layout isn\u2019t the only module that starts to move us away from the issue of visual layout being linked to source order. However, with good support in Internet Explorer 10, it is a nice way to start looking at how this might work. If you look at the grid layout module as something to be used in conjunction with the flexible box layout module and the very interesting CSS regions and exclusions specifications, we have, tantalizingly on the horizon, a powerful set of tools for layout.\n\nI am particularly keen on the potential separation of source order from layout as it dovetails rather neatly into something I spend a lot of time thinking about. As a CMS developer, working on larger scale projects as well as our CMS product Perch, I am interested in how we better enable content editors to create content for the web. In particular, I search for better ways to help them create adaptive content; content that will work in a variety of contexts rather than being tied to one representation of that content.\n\nIf the concept of adaptive content is new to you, then Karen McGrane\u2019s presentation Adapting Ourselves to Adaptive Content is the place to start. Karen talks about needing to think of content as chunks, that might be used in many different places, displayed differently depending on context.\n\nI absolutely agree with Karen\u2019s approach to content. We have always attempted to move content editors away from thinking about creating a page and previewing it on the desktop. However at some point content does need to be published as a page, or a collection of content if you prefer, and bits of that content have priority. Particularly in a small screen context, content gets linearized, we can only show so much at a time, and we need to make sure important content rises to the top. In the case of my example, I wanted to ensure that the address information was clearly visible without scrolling around too much. Dropping it with the entire sidebar to the bottom of the page would not have been so helpful, though neither would moving the whole sidebar to the top of the screen so a visitor had to scroll past advertising to get to the article.\n\nIf our layout is linked to our source order, then enabling the content editor to make decisions about priority is really hard. Only a system that can do some regeneration of the source order on the server-side \u2013 perhaps by way of multiple templates \u2013 can allow those kinds of decisions to be made. For larger systems this might be a possibility; for smaller ones, or when using an off-the-shelf CMS, it is less likely to be. Fortunately, any system that allows some form of custom field type can be used to pop a class on to an element, and with CSS grid layout that is all that is needed to be able to target that element and drop it into the right place when the content is viewed, be that on a desktop or a mobile device.\n\nThis approach can move us away from forcing editors to think visually. At the moment, I might have to explain to an editor that if a certain piece of content needs to come first when viewed on a mobile device, it needs to be placed in the sidebar area, tying it to a particular layout and design. I have to do this because we have to enforce fairly strict rules around source order to make the mechanics of the responsive design work. If I can instead advise an editor to flag important content as high priority in the CMS, then I can make decisions elsewhere as to how that is displayed, and we can maintain the visual hierarchy across all the different ways content might be rendered.\n\nWhy frustrate ourselves with specifications we can\u2019t yet use in production?\n\nThe CSS3 grid layout specification is listed under the Exploring section of the list of current work of the CSS Working Group. While discussing a module at this stage might seem a bit pointless if we can\u2019t use it in production work, there is a very real reason for doing so. If those of us who will ultimately be developing sites with these tools find out about them early enough, then we can start to give our feedback to the people responsible for the specification. There is information on the same page about how to get involved with the disussions.\n\nSo, if you have a bit of time this holiday season, why not have a play with the CSS3 grid layout module? I have outlined here some of my thoughts on how grid layout and other modules that separate layout from source order can be used in the work that I do. Likewise, wherever in the stack you work, playing with and thinking about new specifications means you can think about how you would use them to enhance your work. Spot a problem? Think that a change to the specification would improve things for a specific use case? Then you have something you could post to www-style to add to the discussion around this module.\n\nAll the examples are on CodePen so feel free to play around and fork them.", "year": "2012", "author": "Rachel Andrew", "author_slug": "rachelandrew", "published": "2012-12-18T00:00:00+00:00", "url": "https://24ways.org/2012/css3-grid-layout/", "topic": "code"} {"rowid": 98, "title": "Absolute Columns", "contents": "CSS layouts have come quite a long way since the dark ages of web publishing, with all sorts of creative applications of floats, negative margins, and even background images employed in order to give us that most basic building block, the column. As the title implies, we are indeed going to be discussing columns today\u2014more to the point, a handy little application of absolute positioning that may be exactly what you\u2019ve been looking for\u2026\n\nCare for a nightcap?\n\nIf you\u2019ve been developing for the web for long enough, you may be familiar with this little children\u2019s fable, passed down from wizened Shaolin monks sitting atop the great Mt. Geocities: \u201cOnce upon a time, multiple columns of the same height could be easily created using TABLES.\u201d Now, though we\u2019re all comfortably seated on the standards train (and let\u2019s be honest: even if you like to think you\u2019ve fallen off, if you\u2019ve given up using tables for layout, rest assured your sleeper car is still reserved), this particular\u2014and as page layout goes, quite basic\u2014trick is still a thorn in our CSSides compared to the ease of achieving the same effect using said Tables of Evil\u2122.\n\nSee, the orange juice masks the flavor\u2026\n\nCreative solutions such as Dan Cederholm\u2019s Faux Columns do a good job of making it appear as though adjacent columns maintain equal height as content expands, using a background image to fill the space that the columns cannot.\n\nNow, the Holy Grail of CSS columns behaving exactly how they would as table cells\u2014or more to the point, as columns\u2014still eludes us (cough CSS3 Multi-column layout module cough), but sometimes you just need, for example, a secondary column (say, a sidebar) to match the height of a primary column, without involving the creation of images. This is where a little absolute positioning can save you time, while possibly giving your layout a little more flexibility.\n\nShaken, not stirred\n\nYou\u2019re probably familiar by now with the concept of Making the Absolute, Relative as set forth long ago by Doug Bowman, but let\u2019s quickly review just in case: an element set to position:absolute will position itself relative to its nearest ancestor set to position:relative, rather than the browser window (see Figure 1).\n\n Figure 1.\n\nHowever, what you may not know is that we can anchor more than two sides of an absolutely positioned element. Yes, that\u2019s right, all four sides (top, right, bottom, left) can be set, though in this example we\u2019re only going to require the services of three sides (see Figure 2 for the end result).\n\n Figure 2.\n\nTrust me, this will make you feel better\n\nOur requirements are essentially the same as the standard \u201cabsolute-relative\u201d trick\u2014a container <div> set to position:relative, and our sidebar <div> set to position:absolute \u2014 plus another <div> that will serve as our main content column. We\u2019ll also add a few other common layout elements (wrapper, header, and footer) so our example markup looks more like a real layout and less like a test case:\n\n<div id=\"wrapper\">\n\t<div id=\"header\">\n\t\t<h2>#header</h2>\n\t</div>\n\t<div id=\"container\">\n\t\t<div id=\"column-left\">\n\t\t\t<h2>#left</h2>\n\t\t\t<p>Lorem ipsum dolor sit amet\u2026</p>\n\t\t</div>\n\t\t<div id=\"column-right\">\n\t\t\t<h2>#right</h2>\n\t\t</div>\n\t</div>\n\t<div id=\"footer\">\n\t\t<h2>#footer</h2>\n\t</div>\n</div>\n\nIn this example, our main column (#column-left) is only being given a width to fit within the context of the layout, and is otherwise untouched (though we\u2019re using pixels here, this trick will of course work with fluid layouts as well), and our right keeping our styles nice and minimal:\n\n#container {\n\tposition: relative;\n}\n#column-left {\n\twidth: 480px;\n}\n#column-right {\n\tposition: absolute;\n\ttop: 10px;\n\tright: 10px;\n\tbottom: 10px;\n\twidth: 250px;\n}\n\nThe trick is a simple one: the #container <div> will expand vertically to fit the content within #column-left. By telling our sidebar <div> (#column-right) to attach itself not only to the top and right edges of #container, but also to the bottom, it too will expand and contract to match the height of the left column (duplicate the \u201clorem ipsum\u201d paragraph a few times to see it in action).\n\n Figure 3.\n\nOn the rocks\n\n\u201cBut wait!\u201d I hear you exclaim, \u201cwhen the right column has more content than the left column, it doesn\u2019t expand! My text runneth over!\u201d Sure enough, that\u2019s exactly what happens, and what\u2019s more, it\u2019s supposed to: Absolutely positioned elements do exactly what you tell them to do, and unfortunately aren\u2019t very good at thinking outside the box (get it? sigh\u2026). \n\nHowever, this needn\u2019t get your spirits down, because there\u2019s an easy way to address the issue: by adding overflow:auto to #column-right, a scrollbar will automatically appear if and when needed:\n\n#column-right {\n\tposition: absolute;\n\ttop: 10px;\n\tright: 10px;\n\tbottom: 10px;\n\twidth: 250px;\n\toverflow: auto;\n}\n\nWhile this may limit the trick\u2019s usefulness to situations where the primary column will almost always have more content than the secondary column\u2014or where the secondary column\u2019s content can scroll with wild abandon\u2014a little prior planning will make it easy to incorporate into your designs.\n\nDriving us to drink\n\nIt just wouldn\u2019t be right to have a friendly, festive holiday tutorial without inviting IE6, though in this particular instance there will be no shaming that old browser into admitting it has a problem, nor an intervention and subsequent 12-step program. That\u2019s right my friends, this tutorial has abstained from IE6-abuse now for 30 days, thanks to the wizard Dean Edwards and his amazingly talented IE7 Javascript library.\n\nSimply drop the Conditional Comment and <script> element into the <head> of your document, along with one tiny CSS hack that only IE6 (and below) will ever see, and that browser will be back on the straight and narrow:\n\n<!--[if lt IE 7]>\n<script src=\"http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE7.js\" type=\"text/javascript\"></script>\n<style type=\"text/css\" media=\"screen\">\n\t#container {\n\t\tzoom:1; /* helps fix IE6 by initiating hasLayout */\n\t}\n</style>\n<![endif]-->\n\nEggnog is supposed to be spiked, right?\n\nOf course, this is one simple example of what can be a much more powerful technique, depending on your needs and creativity. Just don\u2019t go coding up your wildest fantasies until you\u2019ve had a chance to sleep off the Christmas turkey and whatever tasty liquids you happen to imbibe along the way\u2026", "year": "2008", "author": "Dan Rubin", "author_slug": "danrubin", "published": "2008-12-22T00:00:00+00:00", "url": "https://24ways.org/2008/absolute-columns/", "topic": "code"} {"rowid": 99, "title": "A Christmas hCard From Me To You", "contents": "So apparently Christmas is coming. And what is Christmas all about? Well, cleaning out your address book, of course! What better time to go through your contacts, making sure everyone\u2019s details are up date and that you\u2019ve deleted all those nasty clients who never paid on time?\n\nIt\u2019s also a good time to make sure your current clients and colleagues have your most up-to-date details, so instead of filling up their inboxes with e-cards, why not send them something useful? Something like a\u2026 vCard! (See what I did there?)\n\nJust in case you\u2019ve been working in a magical toy factory in the upper reaches of Scandinavia for the last few years, I\u2019m going to tell you that now would also be the perfect time to get into microformats. Using the hCard format, we\u2019ll build a very simple web page and markup our contact details in such a way that they\u2019ll be understood by microformats plugins, like Operator or Tails for Firefox, or the cross-browser Microformats Bookmarklet.\n\nOh, and because Christmas is all about dressing up and being silly, we\u2019ll make the whole thing look nice and have a bit of fun with some CSS3 progressive enhancement. \n\nIf you can\u2019t wait to see what we end up with, you can preview it here.\n\n\n\nStep 1: Contact Details\n\nFirst, let\u2019s decide what details we want to put on the page. I\u2019d put my full name, my email address, my phone number, and my postal address, but I\u2019d rather not get surprise visits from strangers when I\u2019m fannying about with my baubles, so I\u2019m going to use Father Christmas instead (that\u2019s Santa to you Yanks).\n\nFather Christmas\nfatherchristmas@elliotjaystocks.com\n25 Laughingallthe Way\nSnow Falls\nLapland\nFinland\n010 60 58 000\n\nStep 2: hCard Creator\n\nNow I\u2019m not sure about you, but I rather like getting the magical robot pixies to do the work for me, so head on over to the hCard Creator and put those pixies to work! Pop in your details and they\u2019ll give you some nice microformatted HTML in turn.\n\n\n\n<div id=\"hcard-Father-Christmas\" class=\"vcard\">\n\t<a class=\"url fn\" href=\"http://elliotjaystocks.com/fatherchristmas\">Father Christmas</a>\n\t<a class=\"email\" href=\"mailto:fatherchristmas@elliotjaystocks.com\"> fatherchristmas@elliotjaystocks.com</a>\n\t<div class=\"adr\">\n\t<div class=\"street-address\">25 Laughingallthe Way</div>\n\t<span class=\"locality\">Snow Falls</span>\n\t, \n\t<span class=\"region\">Lapland</span>\n\t, \n\t<span class=\"postal-code\">FI-00101</span>\n\t<span class=\"country-name\">Finland</span>\n</div>\n<div class=\"tel\">010 60 58 000</div>\n\t<p style=\"font-size:smaller;\">This <a href=\"http://microformats.org/wiki/hcard\">hCard</a> created with the <a href=\"http://microformats.org/code/hcard/creator\">hCard creator</a>.</p>\n</div>\n\nStep 3: Editing The Code\n\nOne of the great things about microformats is that you can use pretty much whichever HTML tags you want, so just because the hCard Creator Fairies say something should be wrapped in a <span> doesn\u2019t mean you can\u2019t change it to a <blink>. Actually, no, don\u2019t do that. That\u2019s not even excusable at Christmas.\n\nI personally have a penchant for marking up each line of an address inside a <li> tag, where the parent url retains the class of adr. As long as you keep the class names the same, you\u2019ll be fine.\n\n<div id=\"hcard-Father-Christmas\" class=\"vcard\">\n\t<h1><a class=\"url fn\" href=\"http://elliotjaystocks.com/fatherchristmas\">Father Christmas </a></h1>\n\t<a class=\"email\" href=\"mailto:fatherchristmas@elliotjaystocks.com?subject=Here, have some Christmas cheer!\">fatherchristmas@elliotjaystocks.com</a>\n\t<ul class=\"adr\">\n\t\t<li class=\"street-address\">25 Laughingallthe Way</li>\n\t\t<li class=\"locality\">Snow Falls</li>\n\t\t<li class=\"region\">Lapland</li>\n\t\t<li class=\"postal-code\">FI-00101</li>\n\t\t<li class=\"country-name\">Finland</li>\n\t</ul>\n\t<span class=\"tel\">010 60 58 000</span>\n</div>\n\nStep 4: Testing The Microformats\n\nWith our microformats in place, now would be a good time to test that they\u2019re working before we start making things look pretty. If you\u2019re on Firefox, you can install the Operator or Tails extensions, but if you\u2019re on another browser, just add the Microformats Bookmarklet. Regardless of your choice, the results is the same: if you\u2019ve code microformatted content on a web page, one of these bad boys should pick it up for you and allow you to export the contact info. Give it a try and you should see father Christmas appearing in your address book of choice. Now you\u2019ll never forget where to send those Christmas lists!\n\n\n\nStep 5: Some Extra Markup\n\nOne of the first things we\u2019re going to do is put a photo of Father Christmas on the hCard. We\u2019ll be using CSS to apply a background image to a div, so we\u2019ll be needing an extra div with a class name of \u201cphoto\u201d. In turn, we\u2019ll wrap the text-based elements of our hCard inside a div cunningly called \u201ctext\u201d. Unfortunately, because of the float technique we\u2019ll be using, we\u2019ll have to use one of those nasty float-clearing techniques. I shall call this \u201cchristmas-cheer\u201d, since that is what its presence will inevitably bring, of course.\n\nOh, and let\u2019s add a bit of text to give the page context, too:\n\n<p>Send your Christmas lists my way...</p>\n<div id=\"hcard-Father-Christmas\" class=\"vcard\">\n\t<div class=\"text\">\n\t\t<h1><a class=\"url fn\" href=\"http://elliotjaystocks.com/fatherchristmas\">Father Christmas </a></h1>\n\t\t<a class=\"email\" href=\"mailto:fatherchristmas@elliotjaystocks.com?subject=Here, have some Christmas cheer!\">fatherchristmas@elliotjaystocks.com</a>\n\t\t<ul class=\"adr\">\n\t\t\t<li class=\"street-address\">25 Laughingallthe Way</li>\n\t\t\t<li class=\"locality\">Snow Falls</li>\n\t\t\t<li class=\"region\">Lapland</li>\n\t\t\t<li class=\"postal-code\">FI-00101</li>\n\t\t\t<li class=\"country-name\">Finland</li>\n\t\t</ul>\n\t\t<span class=\"tel\">010 60 58 000</span>\n\t</div>\n\t<div class=\"photo\"></div>\n\t<br class=\"christmas-cheer\" />\n</div>\n<div class=\"credits\">\n\t<p>A tutorial by <a href=\"http://elliotjaystocks.com\">Elliot Jay Stocks</a> for <a href=\"http://24ways.org/\">24 Ways</a></p>\n\t<p>Background: <a href=\"http://sxc.hu/photo/1108741\">stock.xchng</a> | Father Christmas: <a href=\"http://istockphoto.com/file_closeup/people/4575943-active-santa.php?id=4575943\">iStockPhoto</a></p>\n</div>\n\nStep 6: Some Christmas Sparkle\n\nSo far, our hCard-housing web page is slightly less than inspiring, isn\u2019t it? It\u2019s time to add a bit of CSS. There\u2019s nothing particularly radical going on here; just a simple layout, some basic typographic treatment, and the placement of the Father Christmas photo. I\u2019d usually use a more thorough CSS reset like the one found in the YUI or Eric Meyer\u2019s, but for this basic page, the simple * solution will do.\n\nCheck out the step 6 demo to see our basic styles in place.\n\nFrom this\u2026\n\n\n\n\u2026 to this:\n\n\n\nStep 7: Fun With imagery\n\nNow it\u2019s time to introduce a repeating background image to the <body> element. This will seamlessly repeat for as wide as the browser window becomes.\n\nBut that\u2019s fairly straightforward. How about having some fun with the Father Christmas image? If you look at the image file itself, you\u2019ll see that it\u2019s twice as wide as the area we can see and contains a \u2018hidden\u2019 photo of our rather camp St. Nick.\n\n\n\nAs a light-hearted visual\u2026 er\u2026 \u2018treat\u2019 for users who move their mouse over the image, we move the position of the background image on the \u201cphoto\u201d div. Check out the step 7 demo to see it working.\n\nStep 8: Progressive Enhancement\n\nFinally, this fun little project is a great opportunity for us to mess around with some advanced CSS features (some from the CSS3 spec) that we rarely get to use on client projects. (Don\u2019t forget: no Christmas pressies for clients who want you to support IE6!)\n\nHere are the rules we\u2019re using to give some browsers a superior viewing experience:\n\n\n\t@font-face allows us to use Jos Buivenga\u2019s free font \u2018Fertigo Pro\u2019 on all text;\n\ttext-shadow adds a little emphasis on the opening paragraph;\n\tbody > p:first-child causes only the first paragraph to receive this treatment;\n\tborder-radius created rounded corners on our main div and the links within it;\n\tand webkit-transition allows us to gently fade in between the default and hover states of those links.\n\n\nAnd with that, we\u2019re done! You can see the results here. It\u2019s time to customise the page to your liking, upload it to your site, and send out the URL. And do it quickly, because I\u2019m sure you\u2019ve got some last-minute Christmas shopping to finish off!", "year": "2008", "author": "Elliot Jay Stocks", "author_slug": "elliotjaystocks", "published": "2008-12-10T00:00:00+00:00", "url": "https://24ways.org/2008/a-christmas-hcard-from-me-to-you/", "topic": "code"} {"rowid": 100, "title": "Moo'y Christmas", "contents": "A note from the editors: Moo has changed their API since this article was written.\n \n \n \n As the web matures, it is less and less just about the virtual world. It is becoming entangled with our world and it is harder to tell what is virtual and what is real. There are several companies who are blurring this line and make the virtual just an extension of the physical. Moo is one such company. \n\nMoo offers simple print on demand services. You can print business cards, moo mini cards, stickers, postcards and more. They give you the ability to upload your images, customize them, then have them sent to your door. Many companies allow this sort of digital to physical interaction, but Moo has taken it one step further and has built an API. \n\nPrintable stocking stuffers \n\nThe Moo API consists of a simple XML file that is sent to their servers. It describes all the information needed to dynamically assemble and print your object. This is very helpful, not just for when you want to print your own stickers, but when you want to offer them to your customers, friends, organization or community with no hassle. Moo handles the check-out and shipping, all you need to do is what you do best, create! \n\nNow using an API sounds complicated, but it is actually very easy. I am going to walk you through the options so you can easily be printing in no time. \n\nBefore you can begin sending data to the Moo API, you need to register and get an API key. This is important, because it allows Moo to track usage and to credit you. To register, visit http://www.moo.com/api/ and click \u201cRequest an API key\u201d. \n\nIn the following examples, I will use {YOUR API KEY HERE} as a place holder, replace that with your API key and everything will work fine. \n\nFirst thing you need to do is to create an XML file to describe the check-out basket. Open any text-editor and start with some XML basics. Don\u2019t worry, this is pretty simple and Moo gives you a few tools to check your XML for errors before you order. \n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n<moo xsi:noNamespaceSchemaLocation=\"http://www.moo.com/xsd/api_0.7.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> \n\t <request>\n\t\t <version>0.7</version>\n\t\t <api_key>{YOUR API KEY HERE}</api_key>\n\t\t <call>build</call>\n\t\t <return_to>http://www.example.com/return.html</return_to>\n\t\t <fail_to>http://www.example.com/fail.html</fail_to>\n\t </request>\n\t <payload>\n\t ...\n\t </payload>\n</moo>\n\nMuch like HTML\u2019s <head> and <body>, Moo has created <request> and <payload> elements all wrapped in a <moo> element. \n\nThe <request> element contains a few pieces of information that is the same across all the API calls. The <version> element describes which version of the API is being used. This is more important for Moo than for you, so just stick with \u201c0.7\u201d for now. \n\nThe <api_key> allows Moo to track sales, referrers and credit your account. \n\nThe <call> element can only take \u201cbuild\u201d so that is pretty straight forward. The <return_to> and <fail_to> elements are URLs. These are optional and are the URLs the customer is redirected to if there is an error, or when the check out process is complete. This allows for some basic branding and a custom \u201cthank you\u201d page which is under your control. That\u2019s it for the <request> element, pretty easy so far! \n\nNext up is the <payload> element. What goes inside here describes what is to be printed. There are two possible elements, we can put <chooser> or we can put <products> directly inside <payload>. They work in a similar ways, but they drop the customer into different parts of the Moo checkout process. \n\nIf you specify <products> then you send the customer straight to the Moo payment process. If you specify <chooser> then you send the customer one-step earlier where they are allowed to pick and choose some images, remove the ones they don\u2019t like, adjust the crop, etc. The example here will use <chooser> but with a little bit of homework you can easily adjust to <products> if you desire. \n\n... \n<chooser> \n\t <product_type>sticker</product_type> \n\t <images> \n\t\t <url>http://example.com/images/christmas1.jpg</url> \n\t </images> \n</chooser> \n...\n\nInside the <chooser> element, we can see there are two basic piece of information. The type of product we want to print, and the images that are to be printed. The <product_type> element can take one of five options and is required! The possibilities are: minicard, notecard, sticker, postcard or greetingcard. We\u2019ll now look at two of these more closely. \n\nMoo Stickers \n\nIn the Moo sticker books you get 90 small squarish stickers in a small little booklet. \n\n\n\nThe simplest XML you could send would be something like the following payload:\n\n...\n<payload>\n\t<chooser>\n\t\t<product_type>sticker</product_type>\n\t\t<images>\n\t\t\t<url>http://example.com/image1.jpg</url>\n\t\t</images>\n\t\t<images>\n\t\t\t<url>http://example.com/image2.jpg</url>\n\t\t</images>\n\t\t<images>\n\t\t\t<url>http://example.com/image3.jpg</url>\n\t\t</images>\n\t</chooser>\n</payload>\n...\n\nThis creates a sticker book with only 3 unique images, but 30 copies of each image. The Sticker books always print 90 stickers in multiples of the images you uploaded. That example only has 3 <images> elements, but you can easily duplicate the XML and send up to 90. The <url> should be the full path to your image and the image needs to be a minimum of 300 pixels by 300 pixels.\n\nYou can add more XML to describe cropping, but the simplest option is to either, let your customers choose or to pre-crop all your images square so there are no issues.\n\nThe full XML you would post to the Moo API to print sticker books would look like this:\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n<moo xsi:noNamespaceSchemaLocation=\"http://www.moo.com/xsd/api_0.7.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> \n\t<request>\n\t\t<version>0.7</version>\n\t\t<api_key>{YOUR API KEY HERE}</api_key>\n\t\t<call>build</call>\n\t\t<return_to>http://www.example.com/return.html</return_to>\n\t\t<fail_to>http://www.example.com/fail.html</fail_to>\n\t</request>\n\t<payload>\n\t\t<chooser>\n\t\t\t<product_type>sticker</product_type>\n\t\t\t<images>\n\t\t\t\t<url>http://example.com/image1.jpg</url>\n\t\t\t</images>\n\t\t\t<images>\n\t\t\t\t<url>http://example.com/image2.jpg</url>\n\t\t\t</images>\n\t\t\t<images>\n\t\t\t\t<url>http://example.com/image3.jpg</url>\n\t\t\t</images>\n\t\t</chooser>\n\t</payload> \n</moo>\n\nMini-cards \n\nThe mini-cards are the small cute business cards in 14\u00d735 dimensions and come in packs of 100. \n\n\n\nSince the mini-cards are print on demand, this allows you to have 100 unique images on the back of the cards.\n\nJust like the stickers example, we need the same XML setup. The <moo> element and <request> elements will be the same as before. The part you will focus on is the <payload> section. \n\nSince you are sending along specific information, we can\u2019t use the <chooser> option any more. Switch this to <products> which has a child of <product>, which in turn has a <product_type> and <designs>. This might seem like a lot of work, but once you have it set up you won\u2019t need to change it.\n\n...\n<payload>\n\t<products>\n\t\t<product>\n\t\t\t<product_type>minicard</product_type>\n\t\t\t<designs>\n\t\t\t\t...\n\t\t\t</designs>\n\t\t</product>\n\t</products>\n</payload>\n...\n\nSo now that we have the basic framework, we can talk about the information specific to minicards. Inside the <designs> element, you will have one <design> for each card. Much like before, this contains a way to describe the image. Note that this time the element is called <image>, not images plural. \n\nInside the <image> element you have a <url> which points to where the image lives and a <type>. The <type> should just be set to \u2018variable\u2019. You can pass crop information here instead, but we\u2019re going to keep it simple for this tutorial. If you are interested in how that works, you should refer to the official API documentation.\n\n...\n<design>\n\t<image>\n\t\t<url>http://example.com/image1.jpg</url>\n\t\t<type>variable</type>\n\t</image>\n</design>\n...\n\nSo far, we have managed to build a pack of 100 Moo mini-cards with the same image on the front. If you wanted 100 different images, you just need to replicate this snippit, 99 more times.\n\nThat describes the front design, but the flip-side of your mini-cards can contain 6 lines of text, which is customizable in a variety of colors, fonts and styles.\n\nThe API allows you to create different text on the back of each mini-card, something the web interface doesn\u2019t implement. To describe the text on the mini-card we need to add a <text_collection> element inside the <design> element. If you skip this element, the back of your mini-card will just be blank, but that\u2019s not very festive!\n\nInside the <text_collection> element, we need to describe the type of text we want to format, so we add a <minicard> element, which in turn contains all the lines of text. Each of Moo\u2019s printed products take different numbers of lines of text, so if you are not planning on making mini-cards, be sure to consult the documentation.\n\nFor mini-cards, we can have 6 distinct lines, each with their own style and layout. Each line is represented by an element <text_line> which has several optional children. The <id> tells which line of the 6 to print the text one. The <string> is the text you want to print and it must be shorter than 38 characters. The <bold> element is false by default, but if you want your text bolded, then add this and set it to true. \n\nThe <align> element is also optional. By default it is set to align left. You can also set this to right or center if you desirer. The <font> element takes one of 3 types, modern, traditional or typewriter. The default is modern. Finally, you can set the <colour>, yes that\u2019s color with a \u2018u\u2019, Moo is a British company, so they get to make the rules. When you start a print on demand company, you can spell it however you want. The <colour> element takes a 6 character hex value with a leading #.\n\n<design>\n\t...\n\t<text_collection>\n\t\t<minicard>\n\t\t\t<text_line>\n\t\t\t\t<id>(1-6)</id>\n\t\t\t\t<string>String, I must be less than 38 chars!</string>\n\t\t\t\t<bold>true</bold>\n\t\t\t\t<align>left</align>\n\t\t\t\t<font>modern</font>\n\t\t\t\t<colour>#ff0000</colour> \n\t\t\t</text_line>\n\t\t</minicard>\n\t</text_collection>\n</design>\n\nIf you combine all of this into a mini-card request you\u2019d get this example:\n\n<?xml version=\"1.0\" encoding=\"UTF-8\"?> \n<moo xsi:noNamespaceSchemaLocation=\"http://www.moo.com/xsd/api_0.7.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> \n\t<request>\n\t\t<version>0.7</version>\n\t\t<api_key>{YOUR API KEY HERE}</api_key>\n\t\t<call>build</call>\n\t\t<return_to>http://www.example.com/return.html</return_to>\n\t\t<fail_to>http://www.example.com/fail.html</fail_to>\n\t</request>\n\t<payload>\n\t\t<products>\n\t\t\t<product>\n\t\t\t\t<product_type>minicard</product_type>\n\t\t\t\t<designs>\n\t\t\t\t\t<design>\n\t\t\t\t\t\t<image>\n\t\t\t\t\t\t\t<url>http://example.com/image1.jpg</url>\n\t\t\t\t\t\t\t<type>variable</type>\n\t\t\t\t\t\t</image>\n\t\t\t\t\t\t<text_collection>\n\t\t\t\t\t\t\t<minicard>\n\t\t\t\t\t\t\t\t<text_line>\n\t\t\t\t\t\t\t\t<id>1</id>\n\t\t\t\t\t\t\t\t<string>String, I must be less than 38 chars!</string>\n\t\t\t\t\t\t\t\t<bold>true</bold>\n\t\t\t\t\t\t\t\t<align>left</align>\n\t\t\t\t\t\t\t\t<font>modern</font>\n\t\t\t\t\t\t\t\t<colour>#ff0000</colour> \n\t\t\t\t\t\t\t\t</text_line>\n\t\t\t\t\t\t\t</minicard>\n\t\t\t\t\t\t</text_collection>\n\t\t\t\t\t</design>\n\t\t\t\t</designs>\n\t\t\t</product>\n\t\t</products>\n\t</payload> \n</moo>\n\nNow you know how to construct the XML that describes what to print. Next, you need to know how to send it to Moo to make it happen!\n\nPosting to the API\n\nSo your XML is file ready to go. First thing we need to do is check it to make sure it\u2019s valid. Moo has created a simple validator where you paste in your XML, and it alerts you to problems.\n\nWhen you have a fully valid XML file, you\u2019ll want to send that to the Moo API. There are a few ways to do this, but the simplest is with an HTML form. \n\nThis is the sample code for an HTML form with a big \u201cBuy My Stickers\u201d button. Once you know that it is working, you can use all your existing HTML knowledge to style it up any way you like.\n\n<form method=\"POST\" action=\"http://www.moo.com/api/api.php\">\n\t<input type=\"hidden\" name=\"xml\" value=\"<?xml version=\"1.0\" encoding=\"UTF-8\"?> <moo xsi:noNamespaceSchemaLocation=\"http://www.moo.com/xsd/api_0.7.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <request>....</request> <payload>...</payload> </moo> \"> \n\t<input type=\"submit\" name=\"submit\" value=\"Buy My Stickers\"/>\n</form>\n\nThis is just a basic <form> element that submits to the Moo API, http://www.moo.com/api/api.php, when someone clicks the button. There is a hidden input called \u201cxml\u201d which contains the value the XML file we created previously.\n\nFor those of you who need to \u201cview source\u201d to fully understand what\u2019s happening can see a working version and peek under the hood.\n\nUsing the API has advantages over uploading the images directly yourself. The images and text that you send via the API can be dynamic. Some companies, like Dopplr, have taken user profiles and dynamic data that changes every minute to generate customer stickers of places that you\u2019ve travelled to or mini-cards with a world map of all the cities you have visited. Every single customer has different travel plans and therefore different sets of stickers and mini-card maps. The API allows for the utmost current information to be printed, on demand, in real-time.\n\nGo forth and Moo\u2019ltiply\n\nSee, making an API call wasn\u2019t that hard was it? You are now 90% of the way to creating anything with the Moo API. With a bit of reading, you can learn that extra 10% and print any Moo product. Be on the lookout in 2009 for the official release of the 1.0 API with improvements and some extras that were not available when this article was written.\n\nThis article is released under the creative-commons attribution share-a-like license. That means you are free to re-distribute it, mash it up, translate it and otherwise re-using it ways the author never considered, in return he only asks you mention his name.\n\n\nThis work by Brian Suda is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.", "year": "2008", "author": "Brian Suda", "author_slug": "briansuda", "published": "2008-12-19T00:00:00+00:00", "url": "https://24ways.org/2008/mooy-christmas/", "topic": "code"} {"rowid": 104, "title": "Sitewide Search On A Shoe String", "contents": "One of the questions I got a lot when I was building web sites for smaller businesses was if I could create a search engine for their site. Visitors should be able to search only this site and find things without the maintainer having to put \u201crelated articles\u201d or \u201cfeatured content\u201d links on every page by hand. \n\nBack when this was all fields this wasn\u2019t easy as you either had to write your own scraping tool, use ht://dig or a paid service from providers like Yahoo, Altavista or later on Google. In the former case you had to swallow the bitter pill of computing and indexing all your content and storing it in a database for quick access and in the latter it hurt your wallet.\n\nTimes have moved on and nowadays you can have the same functionality for free using Yahoo\u2019s \u201cBuild your own search service\u201d \u2013 BOSS. The cool thing about BOSS is that it allows for a massive amount of hits a day and you can mash up the returned data in any format you want. Another good feature of it is that it comes with JSON-P as an output format which makes it possible to use it without any server-side component!\n\nStarting with a working HTML form\n\nIn order to add a search to your site, you start with a simple HTML form which you can use without JavaScript. Most search engines will allow you to filter results by domain. In this case we will search \u201cbbc.co.uk\u201d. If you use Yahoo as your standard search, this could be: \n\n<form id=\"customsearch\" action=\"http://search.yahoo.com/search\">\n\t<div>\n\t\t<label for=\"p\">Search this site:</label>\n\t\t<input type=\"text\" name=\"p\" id=\"term\">\n\t\t<input type=\"hidden\" name=\"vs\" id=\"site\" value=\"bbc.co.uk\">\n\t\t<input type=\"submit\" value=\"go\">\n\t</div>\n</form>\n\nThe Google equivalent is:\n\n<form id=\"customsearch\" action=\"http://www.google.co.uk/search\">\n\t<div>\n\t\t<label for=\"p\">Search this site:</label>\n\t\t<input type=\"text\" name=\"as_q\" id=\"term\">\n\t\t<input type=\"hidden\" name=\"as_sitesearch\" id=\"site\" value=\"bbc.co.uk\">\n\t\t<input type=\"submit\" value=\"go\">\n\t</div>\n</form>\n\nIn any case make sure to use the ID term for the search term and site for the site, as this is what we are going to use for the script. To make things easier, also have an ID called customsearch on the form.\n\nTo use BOSS, you should get your own developer API for BOSS and replace the one in the demo code. There is click tracking on the search results to see how successful your app is, so you should make it your own.\n\nAdding the BOSS magic\n\nBOSS is a REST API, meaning you can use it in any HTTP request or in a browser by simply adding the right parameters to a URL. Say for example you want to search \u201cbbc.co.uk\u201d for \u201cchristmas\u201d all you need to do is open the following URL:\n\nhttp://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&format=xml&appid=YOUR-APPLICATION-ID\n\nTry it out and click it to see the results in XML. We don\u2019t want XML though, which is why we get rid of the format=xml parameter which gives us the same information in JSON:\n\nhttp://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&appid=YOUR-APPLICATION-ID\n\nJSON makes most sense when you can send the output to a function and immediately use it. For this to happen all you need is to add a callback parameter and the JSON will be wrapped in a function call. Say for example we want to call SITESEARCH.found() when the data was retrieved we can do it this way:\n\nhttp://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&callback=SITESEARCH.found&appid=YOUR-APPLICATION-ID\n\nYou can use this immediately in a script node if you want to. The following code would display the total amount of search results for the term christmas on bbc.co.uk as an alert:\n\n<script type=\"text/javascript\">\n\tvar SITESEARCH = {};\n\tSITESEARCH.found = function(o){\n\t\talert(o.ysearchresponse.totalhits);\n\t}\n</script>\n<script type=\"text/javascript\" src=\"http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&callback=SITESEARCH.found&appid=Kzv_lcHV34HIybw0GjVkQNnw4AEXeyJ9Rb1gCZSGxSRNrcif_HdMT9qTE1y9LdI-\">\n</script>\n\nHowever, for our example, we need to be a bit more clever with this.\n\nEnhancing the search form\n\n\n\n\nHere\u2019s the script that enhances a search form to show results below it.\n\nSITESEARCH = function(){\n\tvar config = {\n\t\tIDs:{\n\t\t\tsearchForm:'customsearch',\n\t\t\tterm:'term',\n\t\t\tsite:'site'\n\t\t},\n\t\tloading:'Loading results...',\n\t\tnoresults:'No results found.',\n\t\tappID:'YOUR-APP-ID',\n\t\tresults:20\n\t};\n\tvar form;\n\tvar out;\n\tfunction init(){\n\t\tif(config.appID === 'YOUR-APP-ID'){\n\t\t\talert('Please get a real application ID!');\n\t\t} else {\n\t\t\tform = document.getElementById(config.IDs.searchForm);\n\t\t\tif(form){\n\t\t\t\tform.onsubmit = function(){\n\t\t\t\t\tvar site = document.getElementById(config.IDs.site).value;\n\t\t\t\t\tvar term = document.getElementById(config.IDs.term).value;\n\t\t\t\t\tif(typeof site === 'string' && typeof term === 'string'){\n\t\t\t\t\t\tif(typeof out !== 'undefined'){\n\t\t\t\t\t\t\tout.parentNode.removeChild(out);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tout = document.createElement('p');\n\t\t\t\t\t\tout.appendChild(document.createTextNode(config.loading));\n\t\t\t\t\t\tform.appendChild(out);\n\t\t\t\t\t\tvar APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' + \n\t\t\t\t\t\t\t\t\t\t\t\t\tterm + '?callback=SITESEARCH.found&sites=' + \n\t\t\t\t\t\t\t\t\t\t\t\t\tsite + '&count=' + config.results + \n\t\t\t\t\t\t\t\t\t\t\t\t\t'&appid=' + config.appID;\n\t\t\t\t\t\tvar s = document.createElement('script');\n\t\t\t\t\t\ts.setAttribute('src',APIurl);\n\t\t\t\t\t\ts.setAttribute('type','text/javascript');\n\t\t\t\t\t\tdocument.getElementsByTagName('head')[0].appendChild(s);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n\tfunction found(o){\n\t\tvar list = document.createElement('ul');\n\t\tvar results = o.ysearchresponse.resultset_web;\n\t\tif(results){\n\t\t\tvar item,link,description;\n\t\t\tfor(var i=0,j=results.length;i<j;i++){\n\t\t\t\titem = document.createElement('li');\n\t\t\t\tlink = document.createElement('a');\n\t\t\t\tlink.setAttribute('href',results[i].clickurl);\n\t\t\t\tlink.innerHTML = results[i].title;\n\t\t\t\titem.appendChild(link);\n\t\t\t\tdescription = document.createElement('p');\n\t\t\t\tdescription.innerHTML = results[i]['abstract'];\n\t\t\t\titem.appendChild(description);\n\t\t\t\tlist.appendChild(item);\n\t\t\t}\n\t\t} else {\n\t\t\tlist = document.createElement('p');\n\t\t\tlist.appendChild(document.createTextNode(config.noresults));\n\t\t}\n\t\tform.replaceChild(list,out);\n\t\tout = list;\n\t};\n\treturn{\n\t\tconfig:config,\n\t\tinit:init,\n\t\tfound:found\n\t};\n}();\n\nOooohhhh scary code! Let\u2019s go through this one bit at a time:\n\nWe start by creating a module called SITESEARCH and give it an configuration object: \n\nSITESEARCH = function(){\n\tvar config = {\n\t\tIDs:{\n\t\t\tsearchForm:'customsearch',\n\t\t\tterm:'term',\n\t\t\tsite:'site'\n\t\t},\n\t\tloading:'Loading results...',\n\t\tappID:'YOUR-APP-ID',\n\t\tresults:20\n\t}\n\nConfiguration objects are a great idea to make your code easy to change and also to override. In this case you can define different IDs than the one agreed upon earlier, define a message to show when the results are loading, when there aren\u2019t any results, the application ID and the number of results that should be displayed.\n\nNote: you need to replace \u201cYOUR-APP-ID\u201d with the real ID you retrieved from BOSS, otherwise the script will complain! \n\nvar form;\nvar out;\nfunction init(){\n\tif(config.appID === 'YOUR-APP-ID'){\n\t\talert('Please get a real application ID!');\n\t} else {\n\nWe define form and out as variables to make sure that all the methods in the module have access to them. We then check if there was a real application ID defined. If there wasn\u2019t, the script complains and that\u2019s that. \n\nform = document.getElementById(config.IDs.searchForm);\nif(form){\n\tform.onsubmit = function(){\n\t\tvar site = document.getElementById(config.IDs.site).value;\n\t\tvar term = document.getElementById(config.IDs.term).value;\n\t\tif(typeof site === 'string' && typeof term === 'string'){ \n\nIf the application ID was a winner, we check if the form with the provided ID exists and apply an onsubmit event handler. The first thing we get is the values of the site we want to search in and the term that was entered and check that those are strings.\n\nif(typeof out !== 'undefined'){\n\tout.parentNode.removeChild(out);\n}\nout = document.createElement('p');\nout.appendChild(document.createTextNode(config.loading));\nform.appendChild(out); \n\nIf both are strings we check of out is undefined. We will create a loading message and subsequently the list of search results later on and store them in this variable. So if out is defined, it\u2019ll be an old version of a search (as users will re-submit the form over and over again) and we need to remove that old version.\n\nWe then create a paragraph with the loading message and append it to the form.\n\nvar APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' + \n\t\t\t\t\t\t\t\t\t\t\t\tterm + '?callback=SITESEARCH.found&sites=' + \n\t\t\t\t\t\t\t\t\t\t\t\tsite + '&count=' + config.results + \n\t\t\t\t\t\t\t\t\t\t\t\t'&appid=' + config.appID;\n\t\t\t\t\tvar s = document.createElement('script');\n\t\t\t\t\ts.setAttribute('src',APIurl);\n\t\t\t\t\ts.setAttribute('type','text/javascript');\n\t\t\t\t\tdocument.getElementsByTagName('head')[0].appendChild(s);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n};\n\nNow it is time to call the BOSS API by assembling a correct REST URL, create a script node and apply it to the head of the document. We return false to ensure the form does not get submitted as we want to stay on the page.\n\nNotice that we are using SITESEARCH.found as the callback method, which means that we need to define this one to deal with the data returned by the API.\n\nfunction found(o){\n\tvar list = document.createElement('ul');\n\tvar results = o.ysearchresponse.resultset_web;\n\tif(results){\n\t\tvar item,link,description;\n\nWe create a new list and then get the resultset_web array from the data returned from the API. If there aren\u2019t any results returned, this array will not exist which is why we need to check for it. Once we done that we can define three variables to repeatedly store the item title we want to display, the link to point to and the description of the link.\n\nfor(var i=0,j=results.length;i<j;i++){\n\titem = document.createElement('li');\n\tlink = document.createElement('a');\n\tlink.setAttribute('href',results[i].clickurl);\n\tlink.innerHTML = results[i].title;\n\titem.appendChild(link);\n\tdescription = document.createElement('p');\n\tdescription.innerHTML = results[i]['abstract'];\n\titem.appendChild(description);\n\tlist.appendChild(item);\n}\n\nWe then loop over the results array and assemble a list of results with the titles in links and paragraphs with the abstract of the site. Notice the bracket notation for abstract as abstract is a reserved word in JavaScript2 :).\n\n} else {\n\t\tlist = document.createElement('p');\n\t\tlist.appendChild(document.createTextNode(config.noresults));\n\t}\n\tform.replaceChild(list,out);\n\tout = list;\n}; \n\nIf there aren\u2019t any results, we define a paragraph with the no results message as list. In any case we replace the old out (the loading message) with the list and re-define out as the list. \n\nreturn{\n\t\tconfig:config,\n\t\tinit:init,\n\t\tfound:found\n\t};\n}();\n\nAll that is left to do is return the properties and methods we want to make public. In this case found needs to be public as it is accessed by the API return. We return init to make it accessible and config to allow implementers to override any of the properties.\n\nUsing the script\n\n\nIn order to use this script, all you need to do is to add it after the form in the document, override the API key with your own and call init():\n\n<form id=\"customsearch\" action=\"http://search.yahoo.com/search\">\n\t<div>\n\t\t<label for=\"p\">Search this site:</label>\n\t\t<input type=\"text\" name=\"p\" id=\"term\">\n\t\t<input type=\"hidden\" name=\"vs\" id=\"site\" value=\"bbc.co.uk\">\n\t\t<input type=\"submit\" value=\"go\">\n\t</div>\n</form>\n<script type=\"text/javascript\" src=\"boss-site-search.js\"></script>\n<script type=\"text/javascript\">\n\tSITESEARCH.config.appID = 'copy-the-id-you-know-to-get-where';\n\tSITESEARCH.init();\n</script>\n\nWhere to go from here\n\nThis is just a very simple example of what you can do with BOSS. You can define languages and regions, retrieve and display images and news and mix the results with other data sources before displaying them. One very cool feature is that by adding a view=keyterms parameter to the URL you can get the keywords of each of the results to drill deeper into the search. An example for this written in PHP is available on the YDN blog. For JavaScript solutions there is a handy wrapper called yboss available to help you go nuts.", "year": "2008", "author": "Christian Heilmann", "author_slug": "chrisheilmann", "published": "2008-12-04T00:00:00+00:00", "url": "https://24ways.org/2008/sitewide-search-on-a-shoestring/", "topic": "code"} {"rowid": 109, "title": "Geotag Everywhere with Fire Eagle", "contents": "A note from the editors: Since this article was written Yahoo! has retired the Fire Eagle service.\n \n \n \n Location, they say, is everywhere. Everyone has one, all of the time. But on the web, it\u2019s taken until this year to see the emergence of location in the applications we use and build.\n\nThe possibilities are broad. Increasingly, mobile phones provide SDKs to approximate your location wherever you are, browser extensions such as Loki and Mozilla\u2019s Geode provide browser-level APIs to establish your location from the proximity of wireless networks to your laptop. Yahoo\u2019s Brickhouse group launched Fire Eagle, an ambitious location broker enabling people to take their location from any of these devices or sources, and provide it to a plethora of web services. It enables you to take the location information that only your iPhone knows about and use it anywhere on the web.\n\nThat said, this is still a time of location as an emerging technology. Fire Eagle stores your location on the web (protected by application-specific access controls), but to try and give an idea of how useful and powerful your location can be \u2014 regardless of the services you use now \u2014 today\u2019s 24ways is going to build a bookmarklet to call up your location on demand, in any web application.\n\nLocation Support on the Web\n\nOver the past year, the number of applications implementing location features has increased dramatically. Plazes and Brightkite are both full featured social networks based around where you are, whilst Pownce rolled in Fire Eagle support to allow geotagging of all the content you post to their microblogging service. Dipity\u2019s beautiful timeline shows for you moving from place to place and Six Apart\u2019s activity stream for Movable Type started exposing your movements.\n\nThe number of services that hook into Fire Eagle will increase as location awareness spreads through the developer community, but you can use your location on other sites indirectly too.\n\nConsider Flickr. Now world renowned for their incredible mapping and places features, geotagging on Flickr started out as a grassroots extension of regular tagging. That same technique can be used to start rolling geotagging in any publishing platform you come across, for any kind of content. Machine-tags (geo:lat= and geo:lon=) and the adr and geo microformats can be used to enhance anything you write with location information.\n\nA crash course in avian inflammability\n\nFire Eagle is a location store. A broker between services and devices which provide location and those which consume it. It\u2019s a switchboard that controls which pieces of your location different applications can see and use, and keeps hidden anything you want kept private. A blog widget that displays your current location in public can be restricted to display just your current city, whilst a service that provides you with a list of the nearest ATMs will operate better with a precise street address. \n\nEven if your iPhone tells Fire Eagle exactly where you are, consuming applications only see what you want them to see. That\u2019s important for users to realise that they\u2019re in control, but also important for application developers to remember that you cannot rely on having super-accurate information available all the time. You need to build location aware applications which degrade gracefully, because users will provide fuzzier information \u2014 either through choice, or through less accurate sources.\n\nApplication specific permissions are controlled through an OAuth API. Each application has a unique key, used to request a second, user-specific key that permits access to that user\u2019s information. You store that user key and it remains valid until such a time as the user revokes your application\u2019s access. Unlike with passwords, these keys are unique per application, so revoking the access rights of one application doesn\u2019t break all the others.\n\nBuilding your first Fire Eagle app; Geomarklet\n\nFire Eagle\u2019s developer documentation can take you through examples of writing simple applications using server side technologies (PHP, Python). Here, we\u2019re going to write a client-side bookmarklet to make your location available in every site you use. It\u2019s designed to fast-track the experience of having location available everywhere on web, and show you how that can be really handy. Hopefully, this will set you thinking about how location can enhance the new applications you build in 2009.\n\nAn oddity of bookmarklets\n\nBookmarklets (or \u2018favlets\u2019, for those of an MSIE persuasion) are a strange environment to program in. Critically, you have no persistent storage available. As such, using token-auth APIs in a static environment requires you to build you application in a slightly strange way; authing yourself in advance and then hardcoding the keys into your script.\n\nGet started\n\nBefore you do anything else, go to http://fireeagle.com and log in, get set up if you need to and by all means take a look around. Take a look at the mobile updaters section of the application gallery and perhaps pick out an app that will update Fire Eagle from your phone or laptop.\n\nOnce that\u2019s done, you need to register for an application key in the developer section. Head straight to /developer/create and complete the form. Since you\u2019re building a standalone application, choose \u2018Auth for desktop applications\u2019 (rather than web applications), and select that you\u2019ll be \u2018accessing location\u2019, not updating.\n\nAt the end of this process, you\u2019ll have two application keys, a \u2018Consumer Key\u2019 and a \u2018Consumer Secret\u2019, which look like these:\n\n \n Consumer Key\n luKrM9U1pMnu\n Consumer Secret\n ZZl9YXXoJX5KLiKyVrMZffNEaBnxnd6M\n \n\nThese keys combined allow your application to make requests to Fire Eagle.\n\nNext up, you need to auth yourself; granting your new application permission to use your location. Because bookmarklets don\u2019t have local storage, you can\u2019t integrate the auth process into the bookmarklet itself \u2014 it would have no way of storing the returned key. Instead, I\u2019ve put together a simple web frontend through which you can auth with your application.\n\nHead to Auth me, Amadeus!, enter the application keys you just generated and hit \u2018Authorize with Fire Eagle\u2019. You\u2019ll be taken to the Fire Eagle website, just as in regular Fire Eagle applications, and after granting access to your app, be redirected back to Amadeus which will provide you your user tokens. These tokens are used in subsequent requests to read your location.\n\nAnd, skip to the end\u2026\n\nThe process of building the bookmarklet, making requests to Fire Eagle, rendering it to the page and so forth follows, but if you\u2019re the impatient type, you might like to try this out right now. Take your four API keys from above, and drag the following link to your Bookmarks Toolbar; it contains all the code described below. Before you can use it, you need to edit in your own API keys. Open your browser\u2019s bookmark editor and where you find text like \u2018YOUR_CONSUMER_KEY_HERE\u2019, swap in the corresponding key you just generated.\n\nGet Location\n\nBookmarklet Basics\n\nTo start on the bookmarklet code, set out a basic JavaScript module-pattern structure:\n\nvar Geomarklet = function() {\n\treturn ({\n\t\tcallback: function(json) {},\n\t\trun: function() {}\n\t});\n};\nGeomarklet.run();\n\nNext we\u2019ll add the keys obtained in the setup step, and also some basic Fire Eagle support objects:\n\nvar Geomarklet = function() {\n\tvar Keys = {\n\t\t\tconsumer_key: 'IuKrJUHU1pMnu',\n\t\t\tconsumer_secret: 'ZZl9YXXoJX5KLiKyVEERTfNEaBnxnd6M',\n\t\t\tuser_token: 'xxxxxxxxxxxx',\n\t\t\tuser_secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'\n\t};\n\tvar LocationDetail = {\n\t\t\tEXACT: 0,\n\t\t\tPOSTAL: 1,\n\t\t\tNEIGHBORHOOD: 2,\n\t\t\tCITY: 3,\n\t\t\tREGION: 4,\n\t\t\tSTATE: 5,\n\t\t\tCOUNTRY: 6\n\t};\n\tvar index_offset;\n\treturn ({\n\t\tcallback: function(json) {},\n\t\trun: function() {}\n\t});\n};\nGeomarklet.run();\n\nThe Location Hierarchy\n\nA successful Fire Eagle query returns an object called the \u2018location hierarchy\u2019. Depending on the level of detail shared, the index of a particular piece of information in the array will vary. The LocationDetail object maps the array indices of each level in the hierarchy to something comprehensible, whilst the index_offset variable is an adjustment based on the detail of the result returned.\n\nThe location hierarchy object looks like this, providing a granular breakdown of a location, in human consumable and machine-friendly forms.\n\n\"user\": {\n\t\t\"location_hierarchy\": [{\n\t\t\t\"level\": 0,\n\t\t\t\"level_name\": \"exact\",\n\t\t\t\"name\": \"707 19th St, San Francisco, CA\",\n\t\t\t\"normal_name\": \"94123\",\n\t\t\t\"geometry\": {\n\t\t\t\t\t\"type\": \"Point\",\n\t\t\t\t\t\"coordinates\": [ - 0.2347530752, 67.232323]\n\t\t\t},\n\t\t\t\"label\": null,\n\t\t\t\"best_guess\": true,\n\t\t\t\"id\": ,\n\t\t\t\"located_at\": \"2008-12-18T00:49:58-08:00\",\n\t\t\t\"query\": \"q=707%2019th%20Street,%20Sf\"\n\t\t},\n\t\t{\n\t\t\t\t\"level\": 1,\n\t\t\t\t\"level_name\": \"postal\",\n\t\t\t\t\"name\": \"San Francisco, CA 94114\",\n\t\t\t\t\"normal_name\": \"12345\",\n\t\t\t\t\"woeid\": ,\n\t\t\t\t\"place_id\": \"\",\n\t\t\t\t\"geometry\": {\n\t\t\t\t\t\t\"type\": \"Polygon\",\n\t\t\t\t\t\t\"coordinates\": [],\n\t\t\t\t\t\t\"bbox\": []\n\t\t\t\t},\n\t\t\t\t\"label\": null,\n\t\t\t\t\"best_guess\": false,\n\t\t\t\t\"id\": 59358791,\n\t\t\t\t\"located_at\": \"2008-12-18T00:49:58-08:00\"\n\t\t},\n\t\t{\n\t\t\t\t\"level\": 2,\n\t\t\t\t\"level_name\": \"neighborhood\",\n\t\t\t\t\"name\": \"The Mission, San Francisco, CA\",\n\t\t\t\t\"normal_name\": \"The Mission\",\n\t\t\t\t\"woeid\": 23512048,\n\t\t\t\t\"place_id\": \"Y12JWsKbApmnSQpbQg\",\n\t\t\t\t\"geometry\": {\n\t\t\t\t\t\t\"type\": \"Polygon\",\n\t\t\t\t\t\t\"coordinates\": [],\n\t\t\t\t\t\t\"bbox\": []\n\t\t\t\t},\n\t\t\t\t\"label\": null,\n\t\t\t\t\"best_guess\": false,\n\t\t\t\t\"id\": 59358801,\n\t\t\t\t\"located_at\": \"2008-12-18T00:49:58-08:00\"\n\t\t\t},\n\t\t}\n\nIn this case the first object has a level of 0, so the index_offset is also 0.\n\nPrerequisites\n\nTo query Fire Eagle we call in some existing libraries to handle the OAuth layer and the Fire Eagle API call. Your bookmarklet will need to add the following scripts into the page:\n\n\n\tThe SHA1 encryption algorithm\n\tThe OAuth wrapper\n\tAn extension for the OAuth wrapper\n\tThe Fire Eagle wrapper itself\n\n\nWhen the bookmarklet is first run, we\u2019ll insert these scripts into the document. We\u2019re also inserting a stylesheet to dress up the UI that will be generated.\n\nIf you want to follow along any of the more mundane parts of the bookmarklet, you can download the full source code.\n\nRendering\n\nThis bookmarklet can be extended to support any formatting of your location you like, but for sake of example I\u2019m going to build three common formatters that you\u2019ll find useful for common location scenarios: Sites which already ask for your location; and in publishing systems that accept tags or HTML mark-up.\n\nAll the rendering functions are items in a renderers object, so they can be iterated through easily, making it trivial to add new formatting functions as your find new use cases (just add another function to the object).\n\nvar renderers = {\ngeotag: function(user) {\n\tif(LocationDetail.EXACT !== index_offset) {\n\t\t\treturn false;\n\t}\n\telse {\n\t\tvar coords =\n\t\t\tuser.location_hierarchy[LocationDetail.EXACT].geometry.coordinates;\n\t\treturn \"geo:lat=\" + coords[0] + \", geo:lon=\" + coords[1];\n\t}\n},\ncity: function(user) {\n\tif(LocationDetail.CITY < index_offset) {\n\t\treturn false;\n\t}\n\telse {\n\t\treturn user.location_hierarchy[LocationDetail.CITY - index_offset].name; \n\t}\t\t\t\t\t\t \n}\n\nYou should always fail gracefully, and in line with catering to users who choose not to share their location precisely, always check that the location has been returned at the level you require. Geotags are expected to be precise, so if an exact location is unavailable, returning false will tell the rendering aspect of the bookmarklet to ignore the function altogether.\n\nThese first two are quite simple, geotag returns geo:lat=-0.2347530752, geo:lon=67.232323 and city returns San Francisco, CA.\n\nThis final renderer creates a chunk of HTML using the adr and geo microformats, using all available aspects of the location hierarchy, and can be used to geotag any content you write on your blog or in comments:\n\nhtml: function(user) {\n\tvar geostring = '';\n\tvar adrstring = '';\n\tvar adr = [];\t\t \n\tadr.push('<p class=\"adr\">');\n\t// city\n\tif(LocationDetail.CITY >= index_offset) {\n\t\tadr.push(\n\t\t\t'\\n\t\t <span class=\"locality\">'\n\t\t+ user.location_hierarchy[LocationDetail.CITY-index_offset].normal_name\n\t\t+ '</span>,'\n\t\t);\n\t}\n\t// county\n\tif(LocationDetail.REGION >= index_offset) {\n\t\tadr.push(\n\t\t\t'\\n\t\t <span class=\"region\">' \n\t\t+ user.location_hierarchy[LocationDetail.REGION-index_offset].normal_name\n\t\t+ '</span>,'\n\t\t\t);\n\t}\n\t// locality\n\tif(LocationDetail.STATE >= index_offset) {\n\t\tadr.push(\n\t\t\t'\\n\t\t <span class=\"region\">'\n\t\t+ user.location_hierarchy[LocationDetail.STATE-index_offset].normal_name\n\t\t+ '</span>,'\n\t\t);\n\t}\n\t// country\n\tif(LocationDetail.COUNTRY >= index_offset) {\n\t\tadr.push(\n\t\t\t'\\n\t\t <span class=\"country-name\">'\n\t\t+ user.location_hierarchy[LocationDetail.COUNTRY-index_offset].normal_name\n\t\t+ '</span>'\n\t\t);\n\t}\n\t// postal\n\tif(LocationDetail.POSTAL >= index_offset) {\n\t\tadr.push(\n\t\t\t'\\n\t\t <span class=\"postal-code\">'\n\t\t+ user.location_hierarchy[LocationDetail.POSTAL-index_offset].normal_name\n\t\t+ '</span>,'\n\t\t);\n\t}\n\tadr.push('\\n</p>\\n');\n\tadrstring = adr.join('');\n\tif(LocationDetail.EXACT === index_offset) {\n\t\tvar coords = \n\t\t\tuser.location_hierarchy[LocationDetail.EXACT].geometry.coordinates;\n\t\tgeostring = '<p class=\"geo\">'\n\t\t\t+'\\n\t\t<span class=\"latitude\">'\n\t\t\t+ coords[0]\n\t\t\t+ '</span>;'\n\t\t\t+ '\\n\t\t <span class=\"longitude\">'\n\t\t\t+ coords[1]\n\t\t\t+ '</span>\\n</p>\\n';\n\t}\n\treturn (adrstring + geostring);\n}\n\nHere we check the availability of every level of location and build it into the adr and geo patterns as appropriate. Just as for the geotag function, if there\u2019s no exact location the geo markup won\u2019t be returned.\n\nFinally, there\u2019s a rendering method which creates a container for all this data, renders all the applicable location formats and then displays them in the page for a user to copy and paste. You can throw this together with DOM methods and some simple styling, or roll in some components from YUI or JQuery to handle drawing full featured overlays.\n\nYou can see this simple implementation for rendering in the full source code.\n\nMake the call\n\nWith a framework in place to render Fire Eagle\u2019s location hierarchy, the only thing that remains is to actually request your location. Having already authed through Amadeus earlier, that\u2019s as simple as instantiating the Fire Eagle JavaScript wrapper and making a single function call. It\u2019s a big deal that whilst a lot of new technologies like OAuth add some complexity and require new knowledge to work with, APIs like Fire Eagle are really very simple indeed.\n\nreturn {\n\trun: function() {\n\t\tinsert_prerequisites();\n\t\tsetTimeout(\n\t\t\tfunction() {\n\t\t\t\tvar fe = new FireEagle(\n\t\t\t\t\tKeys.consumer_key,\n\t\t\t\t\tKeys.consumer_secret,\n\t\t\t\t\tKeys.user_token,\n\t\t\t\t\tKeys.user_secret\n\t\t\t\t);\n\t\t\t\tvar script = document.createElement('script');\n\t\t\t\tscript.type = 'text/javascript';\n\t\t\t\tscript.src = fe.getUserUrl(\n\t\t\t\t\tFireEagle.RESPONSE_FORMAT.json,\n\t\t\t\t\t'Geomarklet.callback'\n\t\t\t\t);\n\t\t\t\tdocument.body.appendChild(script);\n\t\t\t},\n\t\t\t2000\n\t\t);\n\t},\n\tcallback: function(json) {\n\t\tif(json.rsp && 'fail' == json.rsp.stat) {\n\t\t\talert('Error ' + json.rsp.code + \": \" + json.rsp.message);\n\t\t}\n\t\telse {\n\t\t\tindex_offset = json.user.location_hierarchy[0].level;\t\t\t\t\t\t \n\t\t\tdraw_selector(json);\n\t\t}\n\t}\n};\n\nWe first insert the prerequisite scripts required for the Fire Eagle request to function, and to prevent trying to instantiate the FireEagle object before it\u2019s been loaded over the wire, the remaining instantiation and request is wrapped inside a setTimeout delay.\n\nWe then create the request URL, referencing the Geomarklet.callback callback function and then append the script to the document body \u2014 allowing a cross-domain request.\n\nThe callback itself is quite simple. Check for the presence and value of rsp.status to test for errors, and display them as required. If the request is successful set the index_offset \u2014 to adjust for the granularity of the location hierarchy \u2014 and then pass the object to the renderer.\n\nThe result? When Geomarklet.run() is called, your location from Fire Eagle is read, and each renderer displayed on the page in an easily copy and pasteable form, ready to be used however you need.\n\nDeploy\n\nThe final step is to convert this code into a long string for use as a bookmarklet. Easiest for Mac users is the JavaScript bundle in TextMate \u2014 choose Bundles: JavaScript: Copy as Bookmarklet to Clipboard. Then create a new \u2018Get Location\u2019 bookmark in your browser of choice and paste in.\n\nThose without TextMate can shrink their code down into a single line by first running their code through the JSLint tool (to ensure the code is free from errors and has all the required semi-colons) and then use a find-and-replace tool to remove line breaks from your code (or even run your code through JSMin to shrink it down).\n\nWith the bookmarklet created and added to your bookmarks bar, you can now call up your location on any page at all. Get a feel for a web where your location is just another reliable part of the browsing experience.\n\nWhere next?\n\nSo, the Geomarklet you\u2019ve been guided through is a pretty simple premise and pretty simple output. But from this base you can start to extend: Add code that will insert each of the location renderings directly into form fields, perhaps, or how about site-specific handlers to add your location tags into the correct form field in Wordpress or Tumblr? Paste in your current location to Google Maps? Or Flickr?\n\nGeomarklet gives you a base to start experimenting with location on your own pages and the sites you browse daily.\n\nThe introduction of consumer accessible geo to the web is an adventure of discovery; not so much discovering new locations, but discovering location itself.", "year": "2008", "author": "Ben Ward", "author_slug": "benward", "published": "2008-12-21T00:00:00+00:00", "url": "https://24ways.org/2008/geotag-everywhere-with-fire-eagle/", "topic": "code"} {"rowid": 110, "title": "Shiny Happy Buttons", "contents": "Since Mac OS X burst onto our screens, glossy, glassy, shiny buttons have been almost de rigeur, and have essentially, along with reflections and rounded corners, become a clich\u00e9 of Web 2.0 \u201cdesign\u201d. But if you can\u2019t beat \u2018em you\u2019d better join \u2018em. So, in this little contribution to our advent calendar, we\u2019re going to take a plain old boring HTML button, and 2.0 it up the wazoo. \n\nBut, here\u2019s the catch. We\u2019ll use no images, either in our HTML or our CSS. No sliding doors, no image replacement techniques. Just straight up, CSS, CSS3 and a bit of experimental CSS. And, it will be compatible with pretty much any browser (though with some progressive enhancement for those who keep up with the latest browsers).\n\nThe HTML\n\nWe\u2019ll start with our HTML.\n\n<button type=\"submit\">This is a shiny button</button>\n\nOK, so it\u2019s not shiny yet \u2013 but boy will it ever be.\n\nBefore styling, that\u2019s going to look like this.\n\nIronically, depending on the operating system and browser you are using, it may well be a shiny button already, but that\u2019s not the point. We want to make it shiny 2.0. Our mission is to make it look something like this\n\n\n\nIf you want to follow along at home keep in mind that depending on which browser you are using you may see fewer of the CSS effects we\u2019ve added to create the button. As of writing, only in Safari are all the effects we\u2019ll apply supported.\n\nTaking a look at our finished product, here\u2019s what we\u2019ve done to it:\n\n\n\tWe\u2019ve given the button some padding and a width.\n\tWe\u2019ve changed the text color, and given the text a drop shadow.\n\tWe\u2019ve given the button a border.\n\tWe\u2019ve given the button some rounded corners.\n\tWe\u2019ve given the button a drop shadow.\n\tWe\u2019ve given the button a gradient background.\n\n\nand remember, all without using any images.\n\nStyling the button\n\nSo, let\u2019s get to work.\n\nFirst, we\u2019ll add given the element some padding and a width:\n\nbutton {\n\tpadding: .5em;\n\twidth: 15em;\n}\n\nNext, we\u2019ll add the text color, and the drop shadow:\n\ncolor: #ffffff;\ntext-shadow: 1px 1px 1px #000;\n\nA note on text-shadow\n\nIf you\u2019ve not seen text-shadows before well, here\u2019s the quick back-story. Text shadow was introduced in CSS2, but only supported in Safari (version 1!) some years later. It was removed from CSS2.1, but returned in CSS3 (in the text module). It\u2019s now supported in Safari, Opera and Firefox (3.1). Internet Explorer has a shadow filter, but the syntax is completely different.\n\nSo, how do text-shadows work? The three length values specify respectively a horizontal offset, a vertical offset and a blur (the greater the number the more blurred the shadow will be), and finally a color value for the shadow.\n\nRounding the corners\n\nNow we\u2019ll add a border, and round the corners of the element:\n\nborder: solid thin #882d13;\n-webkit-border-radius: .7em;\n-moz-border-radius: .7em;\nborder-radius: .7em;\n\nHere, we\u2019ve used the same property in three slightly different forms. We add the browser specific prefix for Webkit and Mozilla browsers, because right now, both of these browsers only support border radius as an experimental property. We also add the standard property name, for browsers that do support the property fully in the future. \n\nThe benefit of the browser specific prefix is that if a browser only partly supports a given property, we can easily avoid using the property with that browser simply by not adding the browser specific prefix. At present, as you might guess, border-radius is supported in Safari and Firefox, but in each the relevant prefix is required.\n\nborder-radius takes a length value, such as pixels. (It can also take two length values, but that\u2019s for another Christmas.) In this case, as with padding, I\u2019ve used ems, which means that as the user scales the size of text up and down, the radius will scale as well. You can test the difference by making the radius have a value of say 5px, and then zooming up and down the text size. \n\nWe\u2019re well and truly on the way now. All we need to do is add a shadow to the button, and then a gradient background.\n\nIn CSS3 there\u2019s the box-shadow property, currently only supported in Safari 3. It\u2019s very similar to text-shadow \u2013 you specify a horizontal and vertical offset, a blur value and a color.\n\n-webkit-box-shadow: 2px 2px 3px #999; \nbox-shadow: 2px 2px 2px #bbb;\n\nOnce more, we require the \u201cexperimental\u201d -webkit- prefix, as Safari\u2019s support for this property is still considered by its developers to be less than perfect.\n\nGradient Background\n\nSo, all we have left now is to add our shiny gradient effect. Now of course, people have been doing this kind of thing with images for a long time. But if we can avoid them all the better. Smaller pages, faster downloads, and more scalable designs that adapt better to the user\u2019s font size preference. But how can we add a gradient background without an image?\n\nHere we\u2019ll look at the only property that is not as yet part of the CSS standard \u2013 Apple\u2019s gradient function for use anywhere you can use images with CSS (in this case backgrounds). In essence, this takes SVG gradients, and makes them available via CSS syntax.\n\nHere\u2019s what the property and its value looks like:\n\nbackground-image: -webkit-gradient(linear, left top, left bottom, from(#e9ede8), to(#ce401c),color-stop(0.4, #8c1b0b));\n\nZooming in on the gradient function, it has this basic form:\n\n-webkit-gradient(type, point, point, from(color), to(color),color-stop(where, color));\n\nWhich might look complicated, but is less so than at first glance.\n\nThe name of the function is gradient (and in this case, because it is an experimental property, we use the -webkit- prefix).\n\nYou might not have seen CSS functions before, but there are others, including the attr() function, used with generated content. A function returns a value that can be used as a property value \u2013 here we are using it as a background image.\n\nNext we specify the type of the gradient. Here we have a linear gradient, and there are also radial gradients. \n\nAfter that, we specify the start and end points of the gradient \u2013 in our case the top and bottom of the element, in a vertical line. \n\nWe then specify the start and end colors \u2013 and finally one stop color, located at 40% of the way down the element. Together, this creates a gradient that smoothly transitions from the start color in the top, vertically to the stop color, then smoothly transitions to the end color.\n\nThere\u2019s one last thing. What color will the background of our button be if the browser doesn\u2019t support gradients? It will be white (or possibly some default color for buttons). Which may make the text difficult or impossible to read. So, we\u2019ll add a background color as well (see why the validator is always warning you when a color but not a background color is specified for an element?).\n\nIf we put it all together, here\u2019s what we have:\n\nbutton {\n\twidth: 15em;\n\tpadding: .5em;\n\tcolor: #ffffff;\n\ttext-shadow: 1px 1px 1px #000;\n\tborder: solid thin #882d13;\n\t-webkit-border-radius: .7em;\n\t-moz-border-radius: .7em;\n\tborder-radius: .7em;\n\t-webkit-box-shadow: 2px 2px 3px #999; \n\tbox-shadow: 2px 2px 2px #bbb;\n\tbackground-color: #ce401c;\n\tbackground-image: -webkit-gradient(linear, left top, left bottom, from(#e9ede8), to(#ce401c),color-stop(0.4, #8c1b0b));\n}\n\nWhich looks like this in various browsers:\n\nIn Safari (3)\n\n\n\nIn Firefox 3.1 (3.0 supports border-radius but not text-shadow)\n\n\n\nIn Opera 10\n\n\n\nand of course in Internet Explorer (version 8 shown here)\n\n\n\nBut it looks different in different browsers\n\nYes, it does look different in different browsers, but we all know the answer to the question \u201cdo web sites need to look the same in every browser?\u201c.\n\nEven if you really think sites should look the same in every browser, hopefully this little tutorial has whet your appetite for what CSS3 and experimental CSS that\u2019s already supported in widely used browsers (and we haven\u2019t even touched on animations and similar effects!).\n\nI hope you\u2019ve enjoyed out little CSSMas present, and look forward to seeing your shiny buttons everywhere on the web.\n\nOh, and there\u2019s just a bit of homework \u2013 your job is to use the :hover selector, and make a gradient in the hover state.", "year": "2008", "author": "John Allsopp", "author_slug": "johnallsopp", "published": "2008-12-18T00:00:00+00:00", "url": "https://24ways.org/2008/shiny-happy-buttons/", "topic": "code"} {"rowid": 116, "title": "The IE6 Equation", "contents": "It is the destiny of one browser to serve as the nemesis of web developers everywhere. At the birth of the Web Standards movement, that role was played by Netscape Navigator 4; an outdated browser that refused to die. Its tenacious existence hampered the adoption of modern standards. Today that role is played by Internet Explorer 6.\n\nThere\u2019s a sensation that I\u2019m sure you\u2019re familiar with. It\u2019s a horrible mixture of dread and nervousness. It\u2019s the feeling you get when\u2014after working on a design for a while in a standards-compliant browser like Firefox, Safari or Opera\u2014you decide that you can no longer put off the inevitable moment when you must check the site in IE6. Fingers are crossed, prayers are muttered, but alas, to no avail. The nemesis browser invariably screws something up.\n\nWhat do you do next? If the differences in IE6 are minor, you could just leave it be. After all, websites don\u2019t need to look exactly the same in all browsers. But if there are major layout issues and a significant portion of your audience is still using IE6, you\u2019ll probably need to roll up your sleeves and start fixing the problems.\n\nA common approach is to quarantine IE6-specific CSS in a separate stylesheet. This stylesheet can then be referenced from the HTML document using conditional comments like this:\n\n<!--[if lt IE 7]>\n<link rel=\"stylesheet\" href=\"ie6.css\" type=\"text/css\" media=\"screen\" />\n<![endif]-->\n\nThat stylesheet will only be served up to Internet Explorer where the version number is less than 7.\n\nYou can put anything inside a conditional comment. You could put a script element in there. So as well as serving up browser-specific CSS, it\u2019s possible to serve up browser-specific JavaScript.\n\nA few years back, before Microsoft released Internet Explorer 7, JavaScript genius Dean Edwards wrote a script called IE7. This amazing piece of code uses JavaScript to make Internet Explorer 5 and 6 behave like a standards-compliant browser. Dean used JavaScript to bootstrap IE\u2019s CSS support.\n\nBecause the script is specifically targeted at Internet Explorer, there\u2019s no point in serving it up to other browsers. Conditional comments to the rescue:\n\n<!--[if lt IE 7]>\n<script src=\"http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE7.js\" type=\"text/javascript\"></script>\n<![endif]-->\n\nStandards-compliant browsers won\u2019t fetch the script. Users of IE6, on the hand, will pay a kind of bad browser tax by having to download the JavaScript file.\n\nSo when should you develop an IE6-specific stylesheet and when should you just use Dean\u2019s JavaScript code? This is the question that myself and my co-worker Natalie Downe set out to answer one morning at Clearleft. We realised that in order to answer that question you need to first answer two other questions, how much time does it take to develop for IE6? and how much of your audience is using IE6?\n\nLet\u2019s say that t represents the total development time. Let t6 represent the portion of that time you spend developing for IE6. If your total audience is a, then a6 is the portion of your audience using IE6. With some algebraic help from our mathematically minded co-worker Cennydd Bowles, Natalie and I came up with the following equation to calculate the percentage likelihood that you should be using Dean\u2019s IE7 script:\n\n\n\np = 50 [ log ( at6 / ta6 ) + 1 ]\n\nTry plugging in your own numbers. If you spend a lot of time developing for IE6 and only a small portion of your audience is using that browser, you\u2019ll get a very high number out of the equation; you should probably use the IE7 script. But if you only spend a little time developing for IE6 and a significant portion of you audience are still using that browser, you\u2019ll get a very small value for p; you might as well write an IE6-specific stylesheet.\n\nOf course this equation is somewhat disingenuous. While it\u2019s entirely possible to research the percentage of your audience still using IE6, it\u2019s not so easy to figure out how much of your development time will be spent developing for that one browser. You can\u2019t really know until you\u2019ve already done the development, by which time the equation is irrelevant.\n\nInstead of using the equation, you could try imposing a limit on how long you will spend developing for IE6. Get your site working in standards-compliant browsers first, then give yourself a time limit to get it working in IE6. If you can\u2019t solve all the issues in that time limit, switch over to using Dean\u2019s script. You could even make the time limit directly proportional to the percentage of your audience using IE6. If 20% of your audience is still using IE6 and you\u2019ve just spent five days getting the site working in standards-compliant browsers, give yourself one day to get it working in IE6. But if 50% of your audience is still using IE6, be prepared to spend 2.5 days wrestling with your nemesis.\n\nAll of these different methods for dealing with IE6 demonstrate that there\u2019s no one single answer that works for everyone. They also highlight a problem with the current debate around dealing with IE6. There\u2019s no shortage of blog posts, articles and even entire websites discussing when to drop support for IE6. But very few of them take the time to define what they mean by \u201csupport.\u201d This isn\u2019t a binary issue. There is no Boolean answer. Instead, there\u2019s a sliding scale of support:\n\n\n\tBlock IE6 users from your site.\n\tDevelop with web standards and don\u2019t spend any development time testing in IE6.\n\tUse the Dean Edwards IE7 script to bootstrap CSS support in IE6.\n\tWrite an IE6 stylesheet to address layout issues.\n\tMake your site look exactly the same in IE6 as in any other browser.\n\n\nEach end of that scale is extreme. I don\u2019t think that anybody should be actively blocking any browser but neither do I think that users of an outdated browser should get exactly the same experience as users of a more modern browser. The real meanings of \u201csupporting\u201d or \u201cnot supporting\u201d IE6 lie somewhere in-between those extremes.\n\nJust as I think that semantics are important in markup, they are equally important in our discussion of web development. So let\u2019s try to come up with some better terms than using the catch-all verb \u201csupport.\u201d If you say in your client contract that you \u201csupport\u201d IE6, define exactly what that means. If you find yourself in a discussion about \u201cdropping support\u201d for IE6, take the time to explain what you think that entails.\n\nThe web developers at Yahoo! are on the right track with their concept of graded browser support. I\u2019m interested in hearing more ideas of how to frame this discussion. If we can all agree to use clear and precise language, we stand a better chance of defeating our nemesis.", "year": "2008", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2008-12-08T00:00:00+00:00", "url": "https://24ways.org/2008/the-ie6-equation/", "topic": "code"} {"rowid": 117, "title": "The First Tool You Reach For", "contents": "Microsoft recently announced that Internet Explorer 8 will be released in the first half of 2009. Compared to the standards support of other major browsers, IE8 will not be especially great, but it will finally catch up with the state of the art in one specific area: support for CSS tables. This milestone has the potential to trigger an important change in the way you approach web design.\n\nTo show you just how big a difference CSS tables can make, think about how you might code a fluid, three-column layout from scratch. Just to make your life more difficult, give it one fixed-width column, with a background colour that differs from the rest of the page. Ready? Go!\n\nOkay, since you\u2019re the sort of discerning web designer who reads 24ways, I\u2019m going to assume you at least considered doing this without using HTML tables for the layout. If you\u2019re especially hardcore, I imagine you began thinking of CSS floats, negative margins, and faux columns. If you did, colour me impressed!\n\nNow admit it: you probably also gave an inward sigh about the time it would take to figure out the math on the negative margin overlaps, check for dropped floats in Internet Explorer and generally wrestle each of the major browsers into giving you what you want. If after all that you simply gave up and used HTML tables, I can\u2019t say I blame you.\n\nThere are plenty of professional web designers out there who still choose to use HTML tables as their main layout tool. Sure, they may know that users with screen readers get confused by inappropriate use of tables, but they have a job to do, and they want tools that will make that job easy, not difficult.\n\nNow let me show you how to do it with CSS tables. First, we have a div element for each of our columns, and we wrap them all in another two divs:\n\n<div class=\"container\">\n\t<div>\n\t\t<div id=\"menu\">\n\t\t\u22ee\n\t\t</div>\n\t\t<div id=\"content\">\n\t\t\u22ee\n\t\t</div>\n\t\t<div id=\"sidebar\">\n\t\t\u22ee\n\t\t</div>\n\t</div>\n</div>\n\nDon\u2019t sweat the \u201cdiv clutter\u201d in this code. Unlike tables, divs have no semantic meaning, and can therefore be used liberally (within reason) to provide hooks for the styles you want to apply to your page.\n\nUsing CSS, we can set the outer div to display as a table with collapsed borders (i.e. adjacent cells share a border) and a fixed layout (i.e. cell widths unaffected by their contents):\n\n.container {\n\tdisplay: table;\n\tborder-collapse: collapse;\n\ttable-layout: fixed;\n}\n\nWith another two rules, we set the middle div to display as a table row, and each of the inner divs to display as table cells:\n\n.container > div {\n\tdisplay: table-row;\n}\n.container > div > div {\n\tdisplay: table-cell;\n}\n\nFinally, we can set the widths of the cells (and of the table itself) directly:\n\n.container {\n\twidth: 100%;\n}\n#menu {\n\twidth: 200px;\n}\n#content {\n\twidth: auto;\n}\n#sidebar {\n\twidth: 25%;\n}\n\nAnd, just like that, we have a rock solid three-column layout, ready to be styled to your own taste, like in this example:\n\n\n\nThis example will render perfectly in reasonably up-to-date versions of Firefox, Safari and Opera, as well as the current beta release of Internet Explorer 8.\n\nCSS tables aren\u2019t only useful for multi-column page layout; they can come in handy in most any situation that calls for elements to be displayed side-by-side on the page. Consider this simple login form layout:\n\n\n\nThe incantation required to achieve this layout using CSS floats may be old hat to you by now, but try to teach it to a beginner, and watch his eyes widen in horror at the hoops you have to jump through (not to mention the assumptions you have to build into your design about the length of the form labels).\n\nHere\u2019s how to do it with CSS tables:\n\n<form action=\"/login\" method=\"post\">\n\t<div>\n\t\t<div>\n\t\t\t<label for=\"username\">Username:</label>\n\t\t\t<span class=\"input\"><input type=\"text\" name=\"username\" id=\"username\"/></span>\n\t\t</div>\n\t\t<div>\n\t\t\t<label for=\"userpass\">Password:</label>\n\t\t\t<span class=\"input\"><input type=\"password\" name=\"userpass\" id=\"userpass\"/></span>\n\t\t</div>\n\t\t<div class=\"submit\">\n\t\t\t<label for=\"login\"></label>\n\t\t\t<span class=\"input\"><input type=\"submit\" name=\"login\" id=\"login\" value=\"Login\"/></span>\n\t\t</div>\n\t</div>\n</form>\n\nThis time, we\u2019re using a mixture of divs and spans as semantically transparent styling hooks. Let\u2019s look at the CSS code.\n\nFirst, we set up the outer div to display as a table, the inner divs to display as table rows, and the labels and spans as table cells (with right-aligned text):\n\nform > div {\n\tdisplay: table;\n}\nform > div > div {\n\tdisplay: table-row;\n}\nform label,\nform span {\n\tdisplay: table-cell;\n\ttext-align: right;\n}\n\nWe want the first column of the table to be wide enough to accommodate our labels, but no wider. With CSS float techniques, we had to guess at what that width was likely to be, and adjust it whenever we changed our form labels. With CSS tables, we can simply set the width of the first column to something very small (1em), and then use the white-space property to force the column to the required width:\n\nform label {\n\twhite-space: nowrap;\n\twidth: 1em;\n}\n\nTo polish off the layout, we\u2019ll make our text and password fields occupy the full width of the table cells that contain them:\n\ninput[type=text],\ninput[type=password] {\n\twidth: 100%;\n}\n\nThe rest is margins, padding and borders to get the desired look. Check out the finished example.\n\nAs the first tool you reach for when approaching any layout task, CSS tables make a lot more sense to your average designer than the cryptic incantations called for by CSS floats. When IE8 is released and all major browsers support CSS tables, we can begin to gradually deploy CSS table-based layouts on sites that are more and more mainstream.\n\nIn our new book, Everything You Know About CSS Is Wrong!, Rachel Andrew and I explore in much greater detail how CSS tables work as a page layout tool in the real world. CSS tables have their quirks just like floats do, but they don\u2019t tend to affect common layout tasks, and the workarounds tend to be less fiddly too. Check it out, and get ready for the next big step forward in web design with CSS.", "year": "2008", "author": "Kevin Yank", "author_slug": "kevinyank", "published": "2008-12-13T00:00:00+00:00", "url": "https://24ways.org/2008/the-first-tool-you-reach-for/", "topic": "code"} {"rowid": 121, "title": "Hide And Seek in The Head", "contents": "If you want your JavaScript-enhanced pages to remain accessible and understandable to scripted and noscript users alike, you have to think before you code. Which functionalities are required (ie. should work without JavaScript)? Which ones are merely nice-to-have (ie. can be scripted)? You should only start creating the site when you\u2019ve taken these decisions.\n\nSpecial HTML elements\n\nOnce you have a clear idea of what will work with and without JavaScript, you\u2019ll likely find that you need a few HTML elements for the noscript version only.\n\nTake this example: A form has a nifty bit of Ajax that automatically and silently sends a request once the user enters something in a form field. However, in order to preserve accessibility, the user should also be able to submit the form normally. So the form should have a submit button in noscript browsers, but not when the browser supports sufficient JavaScript.\n\nSince the button is meant for noscript browsers, it must be hard-coded in the HTML:\n\n<input type=\"submit\" value=\"Submit form\" id=\"noScriptButton\" />\n\nWhen JavaScript is supported, it should be removed:\n\nvar checkJS = [check JavaScript support];\nwindow.onload = function () {\n\tif (!checkJS) return;\n\tdocument.getElementById('noScriptButton').style.display = 'none';\n}\n\nProblem: the load event\n\nAlthough this will likely work fine in your testing environment, it\u2019s not completely correct. What if a user with a modern, JavaScript-capable browser visits your page, but has to wait for a huge graphic to load? The load event fires only after all assets, including images, have been loaded. So this user will first see a submit button, but then all of a sudden it\u2019s removed. That\u2019s potentially confusing.\n\nFortunately there\u2019s a simple solution: play a bit of hide and seek in the <head>:\n\nvar checkJS = [check JavaScript support];\nif (checkJS) {\n\tdocument.write('<style>#noScriptButton{display: none}</style>');\n}\n\nFirst, check if the browser supports enough JavaScript. If it does, document.write an extra <style> element that hides the button.\n\nThe difference with the previous technique is that the document.write command is outside any function, and is therefore executed while the JavaScript is being parsed. Thus, the #noScriptButton{display: none} rule is written into the document before the actual HTML is received.\n\nThat\u2019s exactly what we want. If the rule is already present at the moment the HTML for the submit button is received and parsed, the button is hidden immediately. Even if the user (and the load event) have to wait for a huge image, the button is already hidden, and both scripted and noscript users see the interface they need, without any potentially confusing flashes of useless content.\n\nIn general, if you want to hide content that\u2019s not relevant to scripted users, give the hide command in CSS, and make sure it\u2019s given before the HTML element is loaded and parsed.\n\nAlternative\n\nSome people won\u2019t like to use document.write. They could also add an empty <link /> element to the <head> and give it an href attribute once the browser\u2019s JavaScript capabilities have been evaluated. The <link /> element is made to refer to a style sheet that contains the crucial #noScriptButton{display: none}, and everything works fine.\n\nImportant note: The script needs access to the <link />, and the only way to ensure that access is to include the empty <link /> element before your <script> tag.", "year": "2006", "author": "Peter-Paul Koch", "author_slug": "ppk", "published": "2006-12-06T00:00:00+00:00", "url": "https://24ways.org/2006/hide-and-seek-in-the-head/", "topic": "code"} {"rowid": 124, "title": "Writing Responsible JavaScript", "contents": "Without a doubt, JavaScript has been making something of a comeback in the last year. If you\u2019re involved in client-side development in any way at all, chances are that you\u2019re finding yourself writing more JavaScript now than you have in a long time.\n\nIf you learned most of your JavaScript back when DHTML was all the rage and before DOM Scripting was in vogue, there have been some big shifts in the way scripts are written. Most of these are in the way event handlers are assigned and functions declared. Both of these changes are driven by the desire to write scripts that are responsible page citizens, both in not tying behaviour to content and in taking care not to conflict with other scripts. I thought it may be useful to look at some of these more responsible approaches to learn how to best write scripts that are independent of the page content and are safely portable between different applications.\n\nEvent Handling\n\nBack in the heady days of Web 1.0, if you wanted to have an object on the page react to something like a click, you would simply go ahead and attach an onclick attribute. This was easy and understandable, but much like the font tag or the style attribute, it has the downside of mixing behaviour or presentation in with our content. As we\u2019re learned with CSS, there are big benefits in keeping those layers separate. Hey, if it works for CSS, it should work for JavaScript too.\n\nJust like with CSS, instead of adding an attribute to our element within the document, the more responsible way to do that is to look for the item from your script (like CSS does with a selector) and then assign the behaviour to it. To give an example, take this oldskool onclick use case:\n\n<a id=\"anim-link\" href=\"#\" onclick=\"playAnimation()\">Play the animation</a>\n\nThis could be rewritten by removing the onclick attribute, and instead doing the following from within your JavaScript.\n\ndocument.getElementById('anim-link').onclick = playAnimation;\n\nIt\u2019s all in the timing\n\nOf course, it\u2019s never quite that easy. To be able to attach that onclick, the element you\u2019re targeting has to exist in the page, and the page has to have finished loading for the DOM to be available. This is where the onload event is handy, as it fires once everything has finished loading. Common practise is to have a function called something like init() (short for initialise) that sets up all these event handlers as soon as the page is ready.\n\nBack in the day we would have used the onload attibute on the <body> element to do this, but of course what we really want is:\n\nwindow.onload = init;\n\nAs an interesting side note, we\u2019re using init here rather than init() so that the function is assigned to the event. If we used the parentheses, the init function would have been run at that moment, and the result of running the function (rather than the function itself) would be assigned to the event. Subtle, but important.\n\nAs is becoming apparent, nothing is ever simple, and we can\u2019t just go around assigning our initialisation function to window.onload. What if we\u2019re using other scripts in the page that might also want to listen out for that event? Whichever script got there last would overwrite everything that came before it. To manage this, we need a script that checks for any existing event handlers, and adds the new handler to it. Most of the JavaScript libraries have their own systems for doing this. If you\u2019re not using a library, Simon Willison has a good stand-alone example\n\nfunction addLoadEvent(func) {\n\tvar oldonload = window.onload;\n\tif (typeof window.onload != 'function') {\n\t\twindow.onload = func;\n\t} else {\n\t\twindow.onload = function() {\n\t\t\tif (oldonload) {\n\t\t\t\toldonload();\n\t\t\t}\n\t\t\tfunc();\n\t\t}\n\t}\n}\n\nObviously this is just a toe in the events model\u2019s complex waters. Some good further reading is PPK\u2019s Introduction to Events.\n\nCarving out your own space\n\nAnother problem that rears its ugly head when combining multiple scripts on a single page is that of making sure that the scripts don\u2019t conflict. One big part of that is ensuring that no two scripts are trying to create functions or variables with the same names. Reusing a name in JavaScript just over-writes whatever was there before it.\n\nWhen you create a function in JavaScript, you\u2019ll be familiar with doing something like this.\n\nfunction foo() {\n\t... goodness ...\n}\n\nThis is actually just creating a variable called foo and assigning a function to it. It\u2019s essentially the same as the following.\n\nvar foo = function() {\n\t... goodness ...\n}\n\nThis name foo is by default created in what\u2019s known as the \u2018global namespace\u2019 \u2013 the general pool of variables within the page. You can quickly see that if two scripts use foo as a name, they will conflict because they\u2019re both creating those variables in the global namespace.\n\nA good solution to this problem is to add just one name into the global namespace, make that one item either a function or an object, and then add everything else you need inside that. This takes advantage of JavaScript\u2019s variable scoping to contain you mess and stop it interfering with anyone else.\n\nCreating An Object\n\nSay I was wanting to write a bunch of functions specifically for using on a site called \u2018Foo Online\u2019. I\u2019d want to create my own object with a name I think is likely to be unique to me.\n\nvar FOOONLINE = {};\n\nWe can then start assigning functions are variables to it like so:\n\nFOOONLINE.message = 'Merry Christmas!';\nFOOONLINE.showMessage = function() {\n\talert(this.message);\n};\n\nCalling FOOONLINE.showMessage() in this example would alert out our seasonal greeting. The exact same thing could also be expressed in the following way, using the object literal syntax.\n\nvar FOOONLINE = {\n\tmessage: 'Merry Christmas!',\n\tshowMessage: function() {\n\t\talert(this.message);\n\t}\n};\n\nCreating A Function to Create An Object\n\nWe can extend this idea bit further by using a function that we run in place to return an object. The end result is the same, but this time we can use closures to give us something like private methods and properties of our object.\n\nvar FOOONLINE = function(){\n\tvar message = 'Merry Christmas!';\n\treturn {\n\t\tshowMessage: function(){\n\t\t\talert(message);\n\t\t}\n\t}\n}();\n\nThere are two important things to note here. The first is the parentheses at the end of line 10. Just as we saw earlier, this runs the function in place and causes its result to be assigned. In this case the result of our function is the object that is returned at line 4.\n\nThe second important thing to note is the use of the var keyword on line 2. This ensures that the message variable is created inside the scope of the function and not in the global namespace. Because of the way closure works (which if you\u2019re not familiar with, just suspend your disbelief for a moment) that message variable is visible to everything inside the function but not outside. Trying to read FOOONLINE.message from the page would return undefined.\n\nThis is useful for simulating the concept of private class methods and properties that exist in other programming languages. I like to take the approach of making everything private unless I know it\u2019s going to be needed from outside, as it makes the interface into your code a lot clearer for someone else to read. \n\nAll Change, Please\n\nSo that was just a whistle-stop tour of a couple of the bigger changes that can help to make your scripts better page citizens. I hope it makes useful Sunday reading, but obviously this is only the tip of the iceberg when it comes to designing modular, reusable code.\n\nFor some, this is all familiar ground already. If that\u2019s the case, I encourage you to perhaps submit a comment with any useful resources you\u2019ve found that might help others get up to speed. Ultimately it\u2019s in all of our interests to make sure that all our JavaScript interoperates well \u2013 share your tips.", "year": "2006", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2006-12-10T00:00:00+00:00", "url": "https://24ways.org/2006/writing-responsible-javascript/", "topic": "code"} {"rowid": 126, "title": "Intricate Fluid Layouts in Three Easy Steps", "contents": "The Year of the Script may have drawn attention away from CSS but building fluid, multi-column, cross-browser CSS layouts can still be as unpleasant as a lump of coal. Read on for a worry-free approach in three quick steps.\n\nThe layout system I developed, YUI Grids CSS, has three components. They can be used together as we\u2019ll see, or independently.\n\nThe Three Easy Steps\n\n\n\tChoose fluid or fixed layout, and choose the width (in percents or pixels) of the page.\n\tChoose the size, orientation, and source-order of the main and secondary blocks of content.\n\tChoose the number of columns and how they distribute (for example 50%-50% or 25%-75%), using stackable and nestable grid structures.\n\n\nThe Setup\n\nThere are two prerequisites: We need to normalize the size of an em and opt into the browser rendering engine\u2019s Strict Mode.\n\nEms are a superior unit of measure for our case because they represent the current font size and grow as the user increases their font size setting. This flexibility\u2014the container growing with the user\u2019s wishes\u2014means larger text doesn\u2019t get crammed into an unresponsive container. We\u2019ll use YUI Fonts CSS to set the base size because it provides consistent-yet-adaptive font-sizes while preserving user control.\n\nThe second prerequisite is to opt into Strict Mode (more info on rendering modes) by declaring a Doctype complete with URI. You can choose XHTML or HTML, and Transitional or Strict. I prefer HTML 4.01 Strict, which looks like this:\n\n<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n\nIncluding the CSS\n\nA single small CSS file powers a nearly-infinite number of layouts thanks to a recursive system and the interplay between the three distinct components. You could prune to a particular layout\u2019s specific needs, but why bother when the complete file weighs scarcely 1.8kb uncompressed? Compressed, YUI Fonts and YUI Grids combine for a miniscule 0.9kb over the wire.\n\nYou could save an HTTP request by concatenating the two CSS files, or by adding their contents to your own CSS, but I\u2019ll keep them separate for now:\n\n<link href=\"fonts.css\" rel=\"stylesheet\" type=\"text/css\">\n<link href=\"grids.css\" rel=\"stylesheet\" type=\"text/css\">\n\nExample: The Setup\n\nNow we\u2019re ready to build some layouts.\n\nStep 1: Choose Fluid or Fixed Layout\n\nChoose between preset widths of 750px, 950px, and 100% by giving a document-wrapping div an ID of doc, doc2, or doc3. These options cover most use cases, but it\u2019s easy to define a custom fixed width.\n\nThe fluid 100% grid (doc3) is what I\u2019ve been using almost exclusively since it was introduced in the last YUI released.\n\n<body>\n\t<div id=\"doc3\"></div>\n</body>\n\nAll pages are centered within the viewport, and grow with font size. The 100% width page (doc3) preserves 10px of breathing room via left and right margins. If you prefer your content flush to the viewport, just add doc3 {margin:auto} to your CSS.\n\nRegardless of what you choose in the other two steps, you can always toggle between these widths and behaviors by simply swapping the ID value. It\u2019s really that simple.\n\nExample: 100% fluid layout\n\nStep 2: Choose a Template Preset\n\nThis is perhaps the most frequently omitted step (they\u2019re all optional), but I use it nearly every time. In a source-order-independent way (good for accessibility and SEO), \u201cTemplate Presets\u201d provide commonly used template widths compatible with ad-unit dimension standards defined by the Interactive Advertising Bureau, an industry association.\n\nChoose between the six Template Presets (.yui-t1 through .yui-t6) by setting the class value on the document-wrapping div established in Step 1. Most frequently I use yui-t3, which puts the narrow secondary block on the left and makes it 300px wide. \n\n<body>\n\t<div id=\"doc3\" class=\"yui-t3\"></div>\n</body>\n\nThe Template Presets control two \u201cblocks\u201d of content, which are defined by two divs, each with yui-b (\u201cb\u201d for \u201cblock\u201d) class values. Template Presets describe the width and orientation of the secondary block; the main block will take up the rest of the space.\n\n<body>\n\t<div id=\"doc3\" class=\"yui-t3\">\n\t <div class=\"yui-b\"></div>\n\t <div class=\"yui-b\"></div>\n\t</div>\n</body>\n\nUse a wrapping div with an ID of yui-main to structurally indicate which block is the main block. This wrapper\u2014not the source order\u2014identifies the main block.\n\n<body>\n\t<div id=\"doc3\" class=\"yui-t3\">\n\t <div id=\"yui-main\">\n\t <div class=\"yui-b\"></div>\n\t </div>\n\t <div class=\"yui-b\"></div>\n\t</div>\n</body>\n\nExample: Main and secondary blocks sized and oriented with .yui-t3 Template Preset\n\nAgain, regardless of what values you choose in the other steps, you can always toggle between these Template Presets by toggling the class value of your document-wrapping div. It\u2019s really that simple.\n\nStep 3: Nest and Stack Grid Structures.\n\nThe bulk of the power of the system is in this third step. The key is that columns are built by parents telling children how to behave. By default, two children each consume half of their parent\u2019s area. Put two units inside a grid structure, and they will sit side-by-side, and they will each take up half the space. Nest this structure and two columns become four. Stack them for rows of columns.\n\nAn Even Number of Columns\n\nThe default behavior creates two evenly-distributed columns. It\u2019s easy. Define one parent grid with .yui-g (\u201cg\u201d for grid) and two child units with .yui-u (\u201cu\u201d for unit). The code looks like this:\n\n<div class=\"yui-g\">\n\t<div class=\"yui-u first\"></div>\n\t<div class=\"yui-u\"></div>\n</div>\n\nBe sure to indicate the \u201cfirst\u201c unit because the :first-child pseudo-class selector isn\u2019t supported across all A-grade browsers. It\u2019s unfortunate we need to add this, but luckily it\u2019s not out of place in the markup layer since it is structural information.\n\nExample: Two evenly-distributed columns in the main content block\n\nAn Odd Number of Columns\n\nThe default system does not work for an odd number of columns without using the included \u201cSpecial Grids\u201d classes. To create three evenly distributed columns, use the \u201cyui-gb\u201c Special Grid:\n\n<div class=\"yui-gb\">\n\t<div class=\"yui-u first\"></div>\n\t<div class=\"yui-u\"></div>\n\t<div class=\"yui-u\"></div>\n</div>\n\nExample: Three evenly distributed columns in the main content block\n\nUneven Column Distribution\n\nSpecial Grids are also used for unevenly distributed column widths. For example, .yui-ge tells the first unit (column) to take up 75% of the parent\u2019s space and the other unit to take just 25%.\n\n<div class=\"yui-ge\">\n\t<div class=\"yui-u first\"></div>\n\t<div class=\"yui-u\"></div>\n</div>\n\nExample: Two columns in the main content block split 75%-25%\n\nPutting It All Together\n\nStart with a full-width fluid page (div#doc3). Make the secondary block 180px wide on the right (div.yui-t4). Create three rows of columns: Three evenly distributed columns in the first row (div.yui-gb), two uneven columns (66%-33%) in the second row (div.yui-gc), and two evenly distributed columns in the thrid row.\n\n<body>\n\t<!-- choose fluid page and Template Preset -->\n\t<div id=\"doc3\" class=\"yui-t4\">\n\t\t<!-- main content block -->\n\t\t<div id=\"yui-main\">\n\t\t\t<div class=\"yui-b\">\n\t\t\t\t<!-- stacked grid structure, Special Grid \"b\" -->\n\t\t\t\t<div class=\"yui-gb\">\n\t\t\t\t\t<div class=\"yui-u first\"></div>\n\t\t\t\t\t<div class=\"yui-u\"></div>\n\t\t\t\t\t<div class=\"yui-u\"></div>\n\t\t\t\t</div>\n\t\t\t\t<!-- stacked grid structure, Special Grid \"c\" -->\n\t\t\t\t<div class=\"yui-gc\">\n\t\t\t\t\t<div class=\"yui-u first\"></div>\n\t\t\t\t\t<div class=\"yui-u\"></div>\n\t\t\t\t</div>\n\t\t\t\t<!-- stacked grid structure -->\n\t\t\t\t<div class=\"yui-g\">\n\t\t\t\t\t<div class=\"yui-u first\"></div>\n\t\t\t\t\t<div class=\"yui-u\"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<!-- secondary content block -->\n\t\t<div class=\"yui-b\"></div>\n\t</div>\n</body>\n\nExample: A complex layout.\n\nWasn\u2019t that easy? Now that you know the three \u201clevers\u201d of YUI Grids CSS, you\u2019ll be creating headache-free fluid layouts faster than you can say \u201cPeace on Earth\u201d.", "year": "2006", "author": "Nate Koechley", "author_slug": "natekoechley", "published": "2006-12-20T00:00:00+00:00", "url": "https://24ways.org/2006/intricate-fluid-layouts/", "topic": "code"} {"rowid": 128, "title": "Boost Your Hyperlink Power", "contents": "There are HTML elements and attributes that we use every day. Headings, paragraphs, lists and images are the mainstay of every Web developer\u2019s toolbox. Perhaps the most common tool of all is the anchor. The humble a element is what joins documents together to create the gloriously chaotic collection we call the World Wide Web.\n\nAnatomy of an Anchor\n\nThe power of the anchor element lies in the href attribute, short for hypertext reference. This creates a one-way link to another resource, usually another page on the Web:\n\n<a href=\"http://allinthehead.com/\">\n\nThe href attribute sits in the opening a tag and some descriptive text sits between the opening and closing tags:\n\n<a href=\"http://allinthehead.com/\">Drew McLellan</a>\n\n\u201cWhoop-dee-freakin\u2019-doo,\u201d I hear you say, \u201cthis is pretty basic stuff\u201d \u2013 and you\u2019re quite right. But there\u2019s more to the anchor element than just the href attribute.\n\nThe Theory of relativity\n\nYou might be familiar with the rel attribute from the link element. I bet you\u2019ve got something like this in the head of your documents:\n\n<link rel=\"stylesheet\" type=\"text/css\" media=\"screen\" href=\"styles.css\" />\n\nThe rel attribute describes the relationship between the linked document and the current document. In this case, the value of rel is \u201cstylesheet\u201d. This means that the linked document is the stylesheet for the current document: that\u2019s its relationship.\n\nHere\u2019s another common use of rel:\n\n<link rel=\"alternate\" type=\"application/rss+xml\" title=\"my RSS feed\" href=\"index.xml\" />\n\nThis describes the relationship of the linked file \u2013 an RSS feed \u2013 as \u201calternate\u201d: an alternate view of the current document.\n\nBoth of those examples use the link element but you are free to use the rel attribute in regular hyperlinks. Suppose you\u2019re linking to your RSS feed in the body of your page:\n\nSubscribe to <a href=\"index.xml\">my RSS feed</a>.\n\nYou can add extra information to this anchor using the rel attribute:\n\nSubscribe to <a href=\"index.xml\" rel=\"alternate\" type=\"application/rss+xml\">my RSS feed</a>.\n\nThere\u2019s no prescribed list of values for the rel attribute so you can use whatever you decide is semantically meaningful. Let\u2019s say you\u2019ve got a complex e-commerce application that includes a link to a help file. You can explicitly declare the relationship of the linked file as being \u201chelp\u201d:\n\n<a href=\"help.html\" rel=\"help\">need help?</a>\n\nElemental Microformats\n\nAlthough it\u2019s completely up to you what values you use for the rel attribute, some consensus is emerging in the form of microformats. Some of the simplest microformats make good use of rel. For example, if you are linking to a license that covers the current document, use the rel-license microformat:\n\nLicensed under a <a href=\"http://creativecommons.org/licenses/by/2.0/\" rel=\"license\">Creative Commons attribution license</a>\n\nThat describes the relationship of the linked document as \u201clicense.\u201d\n\nThe rel-tag microformat goes a little further. It uses rel to describe the final part of the URL of the linked file as a \u201ctag\u201d for the current document:\n\nLearn more about <a href=\"http://en.wikipedia.org/wiki/Microformats\" rel=\"tag\">semantic markup</a>\n\nThis states that the current document is being tagged with the value \u201cMicroformats.\u201d\n\nXFN, which stands for XHTML Friends Network, is a way of describing relationships between people:\n\n<a href=\"http://allinthehead.com/\" rel=\"friend\">Drew McLellan</a>\n\nThis microformat makes use of a very powerful property of the rel attribute. Like the class attribute, rel can take multiple values, separated by spaces:\n\n<a href=\"http://allinthehead.com/\" rel=\"friend met colleague\">Drew McLellan</a>\n\nHere I\u2019m describing Drew as being a friend, someone I\u2019ve met, and a colleague (because we\u2019re both Web monkies).\n\nYou Say You Want a revolution\n\nWhile rel describes the relationship of the linked resource to the current document, the rev attribute describes the reverse relationship: it describes the relationship of the current document to the linked resource. Here\u2019s an example of a link that might appear on help.html:\n\n<a href=\"shoppingcart.html\" rev=\"help\">continue shopping</a>\n\nThe rev attribute declares that the current document is \u201chelp\u201d for the linked file.\n\nThe vote-links microformat makes use of the rev attribute to allow you to qualify your links. By using the value \u201cvote-for\u201d you can describe your document as being an endorsement of the linked resource:\n\nI agree with <a href=\"http://richarddawkins.net/home\" rev=\"vote-for\">Richard Dawkins</a>.\n\nThere\u2019s a corresponding vote-against value. This means that you can link to a document but explicitly state that you don\u2019t agree with it.\n\nI agree with <a href=\"http://richarddawkins.net/home\" rev=\"vote-for\">Richard Dawkins</a>\nabout those <a href=\"http://www.icr.org/\" rev=\"vote-against\">creationists</a>. \n\nOf course there\u2019s nothing to stop you using both rel and rev on the same hyperlink:\n\n<a href=\"http://richarddawkins.net/home\" rev=\"vote-for\" rel=\"muse\">Richard Dawkins</a>\n\nThe Wisdom of Crowds\n\nThe simplicity of rel and rev belies their power. They allow you to easily add extra semantic richness to your hyperlinks. This creates a bounty that can be harvested by search engines, aggregators and browsers. Make it your New Year\u2019s resolution to make friends with these attributes and extend the power of hypertext.", "year": "2006", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2006-12-18T00:00:00+00:00", "url": "https://24ways.org/2006/boost-your-hyperlink-power/", "topic": "code"} {"rowid": 129, "title": "Knockout Type - Thin Is Always In", "contents": "OS X has gorgeous native anti-aliasing (although I will admit to missing 10px aliased Geneva \u2014 *sigh*). This is especially true for dark text on a light background. However, things can go awry when you start using light text on a dark background. Strokes thicken. Counters constrict. Letterforms fill out like seasonal snackers.\n\n \n\nSo how do we combat the fat? In Safari and other Webkit-based browsers we can use the CSS \u2018text-shadow\u2019 property. While trying to add a touch more contrast to the navigation on haveamint.com I noticed an interesting side-effect on the weight of the type. \n\n\n\nThe second line in the example image above has the following style applied to it:\n\n \n\nThis creates an invisible drop-shadow. (Why is it invisible? The shadow is positioned directly behind the type (the first two zeros) and has no spread (the third zero). So the color, black, is completely eclipsed by the type it is supposed to be shadowing.)\n\n \n\nWhy applying an invisible drop-shadow effectively lightens the weight of the type is unclear. What is clear is that our light-on-dark text is now of a comparable weight to its dark-on-light counterpart.\n\n \n\nYou can see this trick in effect all over ShaunInman.com and in the navigation on haveamint.com and Subtraction.com. The HTML and CSS source code used to create the example images used in this article can be found here.", "year": "2006", "author": "Shaun Inman", "author_slug": "shauninman", "published": "2006-12-17T00:00:00+00:00", "url": "https://24ways.org/2006/knockout-type/", "topic": "code"} {"rowid": 132, "title": "Tasty Text Trimmer", "contents": "In most cases, when designing a user interface it\u2019s best to make a decision about how data is best displayed and stick with it. Failing to make a decision ultimately leads to too many user options, which in turn can be taxing on the poor old user. \n\nUnder some circumstances, however, it\u2019s good to give the user freedom in customising their workspace. One good example of this is the \u2018Article Length\u2019 tool in Apple\u2019s Safari RSS reader. Sliding a slider left of right dynamically changes the length of each article shown. It\u2019s that kind of awesomey magic stuff that\u2019s enough to keep you from sleeping. Let\u2019s build one.\n\nThe Setup\n\nLet\u2019s take a page that has lots of long text items, a bit like a news page or like Safari\u2019s RSS items view. If we were to attach a class name to each element we wanted to resize, that would give us something to hook onto from the JavaScript. \n\nExample 1: The basic page.\n\nAs you can see, I\u2019ve wrapped my items in a DIV and added a class name of chunk to them. It\u2019s these chunks that we\u2019ll be finding with the JavaScript. Speaking of which \u2026\n\nOur Core Functions\n\nThere are two main tasks that need performing in our script. The first is to find the chunks we\u2019re going to be resizing and store their original contents away somewhere safe. We\u2019ll need this so that if we trim the text down we\u2019ll know what it was if the user decides they want it back again. We\u2019ll call this loadChunks. \n\nvar loadChunks = function(){\n\tvar everything = document.getElementsByTagName('*');\n\tvar i, l;\n\tchunks\t= [];\n\tfor (i=0, l=everything.length; i<l; i++){\n\t\tif (everything[i].className.indexOf(chunkClass) > -1){\n\t\t\tchunks.push({\n\t\t\t\tref: everything[i],\n\t\t\t\toriginal: everything[i].innerHTML\n\t\t\t});\n\t\t}\n\t}\n};\n\nThe variable chunks is stored outside of this function so that we can access it from our next core function, which is doTrim.\n\nvar doTrim = function(interval) {\n\tif (!chunks) loadChunks();\n\tvar i, l;\n\tfor (i=0, l=chunks.length; i<l; i++){\n\t\tvar a = chunks[i].original.split(' ');\n\t\ta = a.slice(0, interval);\n\t\tchunks[i].ref.innerHTML\t= a.join(' ');\n\t}\n};\n\nThe first thing that needs to be done is to call loadChunks if the chunks variable isn\u2019t set. This should only happen the first time doTrim is called, as from that point the chunks will be loaded.\n\nThen all we do is loop through the chunks and trim them. The trimming itself (lines 6-8) is very simple. We split the text into an array of words (line 6), then select only a portion from the beginning of the array up until the number we want (line 7). Finally the words are glued back together (line 8).\n\nIn essense, that\u2019s it, but it leaves us needing to know how to get the number into this function in the first place, and how that number is generated by the user. Let\u2019s look at the latter case first.\n\nThe YUI Slider Widget\n\nThere are lots of JavaScript libraries available at the moment. A fair few of those are really good. I use the Yahoo! User Interface Library professionally, but have only recently played with their pre-build slider widget. Turns out, it\u2019s pretty good and perfect for this task. \n\nOnce you have the library files linked in (check the docs linked above) it\u2019s fairly straightforward to create yourself a slider.\n\nslider = YAHOO.widget.Slider.getHorizSlider(\"sliderbg\", \"sliderthumb\", 0, 100, 5); \nslider.setValue(50);\nslider.subscribe(\"change\", doTrim);\n\nAll that\u2019s needed then is some CSS to make the slider look like a slider, and of course a few bits of HTML. We\u2019ll see those later.\n\nSee It Working!\n\nRather than spell out all the nuts and bolts of implementing this fairly simple script, let\u2019s just look at in it action and then pick on some interesting bits I\u2019ve added.\n\nExample 2: Try the Tasty Text Trimmer.\n\nAt the top of the JavaScript file I\u2019ve added a small number of settings.\n\nvar chunkClass\t= 'chunk';\nvar minValue\t= 10;\nvar maxValue\t= 100;\nvar multiplier\t= 5;\n\nObvious candidates for configuration are the class name used to find the chunks, and also the some minimum and maximum values. The minValue is the fewest number of words we wish to display when the slider is all the way down. The maxValue is the length of the slider, in this case 100.\n\nMoving the slider makes a call to our doTrim function with the current value of the slider. For a slider 100 pixels long, this is going to be in the range of 0-100. That might be okay for some things, but for longer items of text you\u2019ll want to allow for displaying more than 100 words. I\u2019ve accounted for this by adding in a multiplier \u2013 in my code I\u2019m multiplying the value by 5, so a slider value of 50 shows 250 words. You\u2019ll probably want to tailor the multiplier to the type of content you\u2019re using.\n\nKeeping it Accessible \n\nThis effect isn\u2019t something we can really achieve without JavaScript, but even so we must make sure that this functionality has no adverse impact on the page when JavaScript isn\u2019t available. This is achieved by adding the slider markup to the page from within the insertSliderHTML function.\n\nvar insertSliderHTML = function(){\n\tvar s = '<a id=\"slider-less\" href=\"#less\"><img src=\"icon_min.gif\" width=\"10\" height=\"10\" alt=\"Less text\" class=\"first\" /></a>';\n\ts +=' <div id=\"sliderbg\"><div id=\"sliderthumb\"><img src=\"sliderthumbimg.gif\" /></div></div>';\n\ts +=' <a id=\"slider-more\" href=\"#more\"><img src=\"icon_max.gif\" width=\"10\" height=\"10\" alt=\"More text\" /></a>';\n\tdocument.getElementById('slider').innerHTML = s;\n}\n\nThe other important factor to consider is that a slider can be tricky to use unless you have good eyesight and pretty well controlled motor skills. Therefore we should provide a method of changing the value by the keyboard.\n\nI\u2019ve done this by making the icons at either end of the slider links so they can be tabbed to. Clicking on either icon fires the appropriate JavaScript function to show more or less of the text.\n\nIn Conclusion\n\nThe upshot of all this is that without JavaScript the page just shows all the text as it normally would. With JavaScript we have a slider for trimming the text excepts that can be controlled with the mouse or with a keyboard.\n\nIf you\u2019re like me and have just scrolled to the bottom to find the working demo, here it is again:\n\nTry the Tasty Text Trimmer\n\nTrimmer for Christmas? Don\u2019t say I never give you anything!", "year": "2006", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2006-12-01T00:00:00+00:00", "url": "https://24ways.org/2006/tasty-text-trimmer/", "topic": "code"} {"rowid": 135, "title": "A Scripting Carol", "contents": "We all know the stories of the Ghost of Scripting Past \u2013 a time when the web was young and littered with nefarious scripting, designed to bestow ultimate control upon the developer, to pollute markup with event handler after event handler, and to entrench advertising in the minds of all that gazed upon her.\n\nAnd so it came to be that JavaScript became a dirty word, thrown out of solutions by many a Scrooge without regard to the enhancements that JavaScript could bring to any web page. JavaScript, as it was, was dead as a door-nail.\n\nWith the arrival of our core philosophy that all standardistas hold to be true: \u201cseparate your concerns \u2013 content, presentation and behaviour,\u201d we are in a new era of responsible development the Web Standards Way\u2122. Or are we? Have we learned from the Ghosts of Scripting Past? Or are we now faced with new problems that come with new ways of implementing our solutions?\n\nThe Ghost of Scripting Past\n\nIf the Ghost of Scripting Past were with us it would probably say: \n\n\n\tYou must remember your roots and where you came from, and realize the misguided nature of your early attempts for control. That person you see down there, is real and they are the reason you exist in the first place\u2026 without them, you are nothing.\n\n\nIn many ways we\u2019ve moved beyond the era of control and we do take into account the user, or at least much more so than we used to. Sadly \u2013 there is one advantage that old school inline event handlers had where we assigned and reassigned CSS style property values on the fly \u2013 we knew that if JavaScript wasn\u2019t supported, the styles wouldn\u2019t be added because we ended up doing them at the same time.\n\nIf anything, we need to have learned from the past that just because it works for us doesn\u2019t mean it is going to work for anyone else \u2013 we need to test more scenarios than ever to observe the multitude of browsing arrangements we\u2019ll observe: CSS on with JavaScript off, CSS off/overridden with JavaScript on, both on, both off/not supported. It is a situation that is ripe for conflict.\n\nThis may shock some of you, but there was a time when testing was actually easier: back in the day when Netscape 4 was king. Yes, that\u2019s right. I actually kind of enjoyed Netscape 4 (hear me out, please). With NS4\u2019s CSS implementation known as JavaScript Style Sheets, you knew that if JavaScript was off the styles were off too.\n\nThe Ghost of Scripting Present\n\nWith current best practice \u2013 we keep our CSS and JavaScript separate from each other. So what happens when some of our fancy, unobtrusive DOM Scripting doesn\u2019t play nicely with our wonderfully defined style rules?\n\nLets look at one example of a collapsing and expanding menu to illustrate where we are now:\n\nSimple Collapsing/Expanding Menu Example\n\nWe\u2019re using some simple JavaScript (I\u2019m using jquery in this case) to toggle between a CSS state for expanded and not expanded:\n\nJavaScript\n\n$(document).ready(function(){\n\tTWOFOURWAYS.enableTree();\n});\nvar TWOFOURWAYS = new Object();\nTWOFOURWAYS.enableTree = function ()\n{\n\t$(\"ul li a\").toggle(function(){\n\t\t$(this.parentNode).addClass(\"expanded\");\n\t}, function() {\n\t\t$(this.parentNode).removeClass(\"expanded\");\n\t});\n\treturn false;\t\n}\n\nCSS\n\nul li ul {\n\tdisplay: none;\n}\nul li.expanded ul {\n\tdisplay: block;\n}\n\nAt this point we\u2019ve separated our presentation from our content and behaviour, and all is well, right?\n\nNot quite.\n\nHere\u2019s where I typically see failures in the assessment work that I do on web sites and applications (Yes, call me Scrooge \u2013 I don\u2019t care!). We know our page needs to work with or without scripting, and we know it needs to work with or without CSS. All too often the testing scenarios don\u2019t take into account combinations.\n\nTesting it out\n\nSo what happens when we test this? Make sure you test with:\n\n\n\tCSS off\n\tJavaScript off\n\n\nUse the simple example again.\n\nWith CSS off, we revert to a simple nested list of links and all functionality is maintained. With JavaScript off, however, we run into a problem \u2013 we have now removed the ability to expand the menu using the JavaScript triggered CSS change.\n\nHopefully you see the problem \u2013 we have a JavaScript and CSS dependency that is critical to the functionality of the page. Unobtrusive scripting and binary on/off tests aren\u2019t enough. We need more.\n\nThis Ghost of Scripting Present sighting is seen all too often.\n\nLets examine the JavaScript off scenario a bit further \u2013 if we require JavaScript to expand/show the branch of the tree we should use JavaScript to hide them in the first place. That way we guarantee functionality in all scenarios, and have achieved our baseline level of interoperability. \n\nTo revise this then, we\u2019ll start with the sub items expanded, use JavaScript to collapse them, and then use the same JavaScript to expand them.\n\nHTML\n\n<ul>\n\t<li><a href=\"#\">Main Item</a>\n\t\t<ul class=\"collapseme\">\n\t\t\t<li><a href=\"#\">Sub item 1</a></li>\n\t\t\t<li><a href=\"#\">Sub item 2</a></li>\n\t\t\t<li><a href=\"#\">Sub item 3</a></li>\n\t\t</ul>\n\t</li>\n</ul>\n\nCSS\n\n/* initial style is expanded */\nul li ul.collapseme {\n\tdisplay: block;\n}\n\nJavaScript\n\n// remove the class collapseme after the page loads\n$(\"ul ul.collapseme\").removeClass(\"collapseme\");\n\nAnd there you have it \u2013 a revised example with better interoperability.\n\nThis isn\u2019t rocket surgery by any means. It is a simple solution to a ghostly problem that is too easily overlooked (and often is).\n\nThe Ghost of Scripting Future\n\nWell, I\u2019m not so sure about this one, but I\u2019m guessing that in a few years\u2019 time, we\u2019ll all have seen a few more apparitions and have a few more tales to tell. And hopefully we\u2019ll be able to share them on 24 ways.\n\nThanks to Drew for the invitation to contribute and thanks to everyone else out there for making this a great (and haunting) year on the web!", "year": "2006", "author": "Derek Featherstone", "author_slug": "derekfeatherstone", "published": "2006-12-21T00:00:00+00:00", "url": "https://24ways.org/2006/a-scripting-carol/", "topic": "code"} {"rowid": 136, "title": "Making XML Beautiful Again: Introducing Client-Side XSL", "contents": "Remember that first time you saw XML and got it? When you really understood what was possible and the deep meaning each element could carry? Now when you see XML, it looks ugly, especially when you navigate to a page of XML in a browser. Well, with every modern browser now supporting XSL 1.0, I\u2019m going to show you how you can turn something as simple as an ATOM feed into a customised page using a browser, Notepad and some XSL.\n\nWhat on earth is this XSL?\n\nXSL is a family of recommendations for defining XML document transformation and presentation. It consists of three parts:\n\n\n\tXSLT 1.0 \u2013 Extensible Stylesheet Language Transformation, a language for transforming XML\n\tXPath 1.0 \u2013 XML Path Language, an expression language used by XSLT to access or refer to parts of an XML document. (XPath is also used by the XML Linking specification)\n\tXSL-FO 1.0 \u2013 Extensible Stylesheet Language Formatting Objects, an XML vocabulary for specifying formatting semantics\n\n\nXSL transformations are usually a one-to-one transformation, but with newer versions (XSL 1.1 and XSL 2.0) its possible to create many-to-many transformations too. So now you have an overview of XSL, on with the show\u2026\n\nSo what do I need?\n\nSo to get going you need a browser an supports client-side XSL transformations such as Firefox, Safari, Opera or Internet Explorer. Second, you need a source XML file \u2013 for this we\u2019re going to use an ATOM feed from Flickr.com. And lastly, you need an editor of some kind. I find Notepad++ quick for short XSLs, while I tend to use XMLSpy or Oxygen for complex XSL work. \n\nBecause we\u2019re doing a client-side transformation, we need to modify the XML file to tell it where to find our yet-to-be-written XSL file. Take a look at the source XML file, which originates from my Flickr photos tagged sky, in ATOM format.\n\nThe top of the ATOM file now has an additional <?xml-stylesheet /> instruction, as can been seen on Line 2 below. This instructs the browser to use the XSL file to transform the document.\n\n<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\n<?xml-stylesheet type=\"text/xsl\" href=\"flickr_transform.xsl\"?>\n<feed xmlns=\"http://www.w3.org/2005/Atom\"\n\txmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n\nYour first transformation\n\nYour first XSL will look something like this:\n\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsl:stylesheet version=\"1.0\"\n\txmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n\txmlns:atom=\"http://www.w3.org/2005/Atom\"\n\txmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n\t<xsl:output method=\"html\" encoding=\"utf-8\"/>\n</xsl:stylesheet>\n\nThis is pretty much the starting point for most XSL files. You will notice the standard XML processing instruction at the top of the file (line 1). We then switch into XSL mode using the XSL namespace on all XSL elements (line 2). In this case, we have added namespaces for ATOM (line 4) and Dublin Core (line 5). This means the XSL can now read and understand those elements from the source XML. \n\nAfter we define all the namespaces, we then move onto the xsl:output element (line 6). This enables you to define the final method of output. Here we\u2019re specifying html, but you could equally use XML or Text, for example. The encoding attributes on each element do what they say on the tin. As with all XML, of course, we close every element including the root.\n\nThe next stage is to add a template, in this case an <xsl:template /> as can be seen below:\n\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsl:stylesheet version=\"1.0\"\n\txmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n\txmlns:atom=\"http://www.w3.org/2005/Atom\"\n\txmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n\t<xsl:output method=\"html\" encoding=\"utf-8\"/>\n\t<xsl:template match=\"/\">\n\t\t<html>\n\t\t\t<head>\n\t\t\t\t<title>Making XML beautiful again : Transforming ATOM</title>\n\t\t\t</head>\n\t\t\t<body>\n\t\t\t\t<xsl:apply-templates select=\"/atom:feed\"/>\n\t\t\t</body>\n\t\t</html>\n\t</xsl:template>\n</xsl:stylesheet>\n\nThe beautiful thing about XSL is its English syntax, if you say it out loud it tends to make sense. \n\nThe / value for the match attribute on line 8 is our first example of XPath syntax. The expression / matches any element \u2013 so this <xsl:template/> will match against any element in the document. As the first element in any XML document is the root element, this will be the one matched and processed first.\n\nOnce we get past our standard start of a HTML document, the only instruction remaining in this <xsl:template/> is to look for and match all <atom:feed/> elements using the <xsl:apply-templates/> in line 14, above.\n\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xsl:stylesheet version=\"1.0\"\n\txmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n\txmlns:atom=\"http://www.w3.org/2005/Atom\"\n\txmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n\t<xsl:output method=\"html\" encoding=\"utf-8\"/>\n\t<xsl:template match=\"/\">\n\t\t<xsl:apply-templates select=\"/atom:feed\"/>\n\t</xsl:template>\n\t<xsl:template match=\"/atom:feed\">\n\t\t<div id=\"content\">\n\t\t\t<h1>\n\t\t\t\t<xsl:value-of select=\"atom:title\"/>\n\t\t\t</h1>\n\t\t\t<p>\n\t\t\t\t<xsl:value-of select=\"atom:subtitle\"/>\n\t\t\t</p>\n\t\t\t<ul id=\"entries\">\n\t\t\t\t<xsl:apply-templates select=\"atom:entry\"/>\n\t\t\t</ul>\n\t\t</div>\n\t</xsl:template>\n</xsl:stylesheet>\n\nThis new template (line 12, above) matches <feed/> and starts to write the new HTML elements out to the output stream. The <xsl:value-of/> does exactly what you\u2019d expect \u2013 it finds the value of the item specifed in its select attribute. With XPath you can select any element or attribute from the source XML. \n\nThe last part is a repeat of the now familiar <xsl:apply-templates/> from before, but this time we\u2019re using it inside of a called template. Yep, XSL is full of recursion\u2026\n\n<xsl:template match=\"atom:entry\">\n\t<li class=\"entry\">\n\t\t<h2>\n\t\t\t<a href=\"{atom:link/@href}\">\n\t\t\t\t<xsl:value-of select=\"atom:title\"/>\n\t\t\t</a>\n\t\t</h2>\n\t\t<p class=\"date\">\n\t\t\t(<xsl:value-of select=\"substring-before(atom:updated,'T')\"/>)\n\t\t</p>\n\t\t<p class=\"content\">\n\t\t\t<xsl:value-of select=\"atom:content\" disable-output-escaping=\"yes\"/>\n\t\t</p>\n\t\t<xsl:apply-templates select=\"atom:category\"/>\n\t</li>\n</xsl:template>\n\nThe <xsl:template/> which matches atom:entry (line 1) occurs every time there is a <entry/> element in the source XML file. So in total that is 20 times, this is naturally why XSLT is full of recursion. This <xsl:template/> has been matched and therefore called higher up in the document, so we can start writing list elements directly to the output stream. The first part is simply a <h2/> with a link wrapped within it (lines 3-7). We can select attributes using XPath using @. \n\nThe second part of this template selects the date, but performs a XPath string function on it. This means that we only get the date and not the time from the string (line 9). This is achieved by getting only the part of the string that exists before the T. \n\nRegular Expressions are not part of the XPath 1.0 string functions, although XPath 2.0 does include them. Because of this, in XSL we tend to rely heavily on the available XML output. \n\nThe third part of the template (line 12) is a <xsl:value-of/> again, but this time we use an attribute of <xsl:value-of/> called disable output escaping to turn escaped characters back into XML. \n\nThe very last section is another <xsl:apply-template/> call, taking us three templates deep. Do not worry, it is not uncommon to write XSL which go 20 or more templates deep!\n\n<xsl:template match=\"atom:category\">\n\t<xsl:for-each select=\".\">\n\t\t<xsl:element name=\"a\">\n\t\t\t<xsl:attribute name=\"rel\">\n\t\t\t\t<xsl:text>tag</xsl:text>\n\t\t\t</xsl:attribute>\n\t\t\t<xsl:attribute name=\"href\">\n\t\t\t\t<xsl:value-of select=\"concat(@scheme, @term)\"/>\n\t\t\t</xsl:attribute>\n\t\t\t<xsl:value-of select=\"@term\"/>\n\t\t</xsl:element>\n\t\t<xsl:text> </xsl:text>\n\t</xsl:for-each>\n</xsl:template>\n\nIn our final <xsl:template/>, we see a combination of what we have done before with a couple of twists. Once we match atom:category we then count how many elements there are at that same level (line 2). The XPath . means \u2018self\u2019, so we count how many category elements are within the <entry/> element. \n\nFollowing that, we start to output a link with a rel attribute of the predefined text, tag (lines 4-6). In XSL you can just type text, but results can end up with strange whitespace if you do (although there are ways to simply remove all whitespace). \n\nThe only new XPath function in this example is concat(), which simply combines what XPaths or text there might be in the brackets. We end the output for this tag with an actual tag name (line 10) and we add a space afterwards (line 12) so it won\u2019t touch the next tag. (There are better ways to do this in XSL using the last() XPath function). \n\nAfter that, we go back to the <xsl:for-each/> element again if there is another category element, otherwise we end the <xsl:for-each/> loop and end this <xsl:template/>.\n\nA touch of style\n\nBecause we\u2019re using recursion through our templates, you will find this is the end of the templates and the rest of the XML will be ignored by the parser. Finally, we can add our CSS to finish up. (I have created one for Flickr and another for News feeds)\n\n<style type=\"text/css\" media=\"screen\">@import \"flickr_overview.css?v=001\";</style>\n\nSo we end up with a nice simple to understand but also quick to write XSL which can be used on ATOM Flickr feeds and ATOM News feeds. With a little playing around with XSL, you can make XML beautiful again.\n\nAll the files can be found in the zip file (14k)", "year": "2006", "author": "Ian Forrester", "author_slug": "ianforrester", "published": "2006-12-07T00:00:00+00:00", "url": "https://24ways.org/2006/beautiful-xml-with-xsl/", "topic": "code"} {"rowid": 138, "title": "Rounded Corner Boxes the CSS3 Way", "contents": "If you\u2019ve been doing CSS for a while you\u2019ll know that there are approximately 3,762 ways to create a rounded corner box. The simplest techniques rely on the addition of extra mark-up directly to your page, while the more complicated ones add the mark-up though DOM manipulation. While these techniques are all very interesting, they do seem somewhat of a kludge. The goal of CSS is to separate structure from presentation, yet here we are adding superfluous mark-up to our code in order to create a visual effect. The reason we are doing this is simple. CSS2.1 only allows a single background image per element.\n\nThankfully this looks set to change with the addition of multiple background images into the CSS3 specification. With CSS3 you\u2019ll be able to add not one, not four, but eight background images to a single element. This means you\u2019ll be able to create all kinds of interesting effects without the need of those additional elements.\n\nWhile the CSS working group still seem to be arguing over the exact syntax, Dave Hyatt went ahead and implemented the currently suggested mechanism into Safari. The technique is fiendishly simple, and I think we\u2019ll all be a lot better off once the W3C stop arguing over the details and allow browser vendors to get on and provide the tools we need to build better websites.\n\nTo create a CSS3 rounded corner box, simply start with your box element and apply your 4 corner images, separated by commas.\n\n.box {\n\tbackground-image: url(top-left.gif), url(top-right.gif), url(bottom-left.gif), url(bottom-right.gif);\n}\n\nWe don\u2019t want these background images to repeat, which is the normal behaviour, so lets set all their background-repeat properties to no-repeat.\n\n.box {\n\tbackground-image: url(top-left.gif), url(top-right.gif), url(bottom-left.gif), url(bottom-right.gif);\n\tbackground-repeat: no-repeat, no-repeat, no-repeat, no-repeat;\n}\n\nLastly, we need to define the positioning of each corner image.\n\n.box {\n\tbackground-image: url(top-left.gif), url(top-right.gif), url(bottom-left.gif), url(bottom-right.gif);\n\tbackground-repeat: no-repeat, no-repeat, no-repeat, no-repeat;\n\tbackground-position: top left, top right, bottom left, bottom right;\n}\n\nAnd there we have it, a simple rounded corner box with no additional mark-up.\n\nAs well as using multiple background images, CSS3 also has the ability to create rounded corners without the need of any images at all. You can do this by setting the border-radius property to your desired value as seen in the next example.\n\n.box {\n\tborder-radius: 1.6em;\n}\n\nThis technique currently works in Firefox/Camino and creates a nice, if somewhat jagged rounded corner. If you want to create a box that works in both Mozilla and WebKit based browsers, why not combine both techniques and see what happens.", "year": "2006", "author": "Andy Budd", "author_slug": "andybudd", "published": "2006-12-04T00:00:00+00:00", "url": "https://24ways.org/2006/rounded-corner-boxes-the-css3-way/", "topic": "code"} {"rowid": 139, "title": "Flickr Photos On Demand with getFlickr", "contents": "In case you don\u2019t know it yet, Flickr is great. It is a lot of fun to upload, tag and caption photos and it is really handy to get a vast network of contacts through it. \n\nUsing Flickr photos outside of it is a bit of a problem though. There is a Flickr API, and you can get almost every page as an RSS feed, but in general it is a bit tricky to use Flickr photos inside your blog posts or web sites. You might not want to get into the whole API game or use a server side proxy script as you cannot retrieve RSS with Ajax because of the cross-domain security settings.\n\nHowever, Flickr also provides an undocumented JSON output, that can be used to hack your own solutions in JavaScript without having to use a server side script.\n\n\n\tIf you enter the URL http://flickr.com/photos/tags/panda you get to the flickr page with photos tagged \u201cpanda\u201d.\n\tIf you enter the URL http://api.flickr.com/services/feeds/photos_public.gne?tags=panda&format=rss_200 you get the same page as an RSS feed.\n\tIf you enter the URL http://api.flickr.com/services/feeds/photos_public.gne?tags=panda&format=json you get a JavaScript function called jsonFlickrFeed with a parameter that contains the same data in JSON format\n\n\nYou can use this to easily hack together your own output by just providing a function with the same name. I wanted to make it easier for you, which is why I created the helper getFlickr for you to download and use.\n\ngetFlickr for Non-Scripters\n\nSimply include the javascript file getflickr.js and the style getflickr.css in the head of your document:\n\n<script type=\"text/javascript\" src=\"getflickr.js\"></script>\n<link rel=\"stylesheet\" href=\"getflickr.css\" type=\"text/css\">\n\nOnce this is done you can add links to Flickr pages anywhere in your document, and when you give them the CSS class getflickrphotos they get turned into gallery links. When a visitor clicks these links they turn into loading messages and show a \u201cpopup\u201d gallery with the connected photos once they were loaded. As the JSON returned is very small it won\u2019t take long. You can close the gallery, or click any of the thumbnails to view a photo. Clicking the photo makes it disappear and go back to the thumbnails.\n\nCheck out the example page and click the different gallery links to see the results.\n\nNotice that getFlickr works with Unobtrusive JavaScript as when scripting is disabled the links still get to the photos on Flickr.\n\ngetFlickr for JavaScript Hackers\n\nIf you want to use getFlickr with your own JavaScripts you can use its main method leech():\n\ngetFlickr.leech(sTag, sCallback);\n\n \n\tsTag\n\tthe tag you are looking for\n\tsCallback\n\tan optional function to call when the data was retrieved.\n \n\nAfter you called the leech() method you have two strings to use:\n\n \n\tgetFlickr.html[sTag]\n\tcontains an HTML list (without the outer UL element) of all the images linked to the correct pages at flickr. The images are the medium size, you can easily change that by replacing _m.jpg with _s.jpg for thumbnails.\n\tgetFlickr.tags[sTag]\n\tcontains a string of all the other tags flickr users added with the tag you searched for(space separated)\n \n\nYou can call getFlickr.leech() several times when the page has loaded to cache several result feeds before the page gets loaded. This\u2019ll make the photos quicker for the end user to show up. If you want to offer a form for people to search for flickr photos and display them immediately you can use the following HTML:\n\n<form onsubmit=\"getFlickr.leech(document.getElementById('tag').value, 'populate');return false\">\n <label for=\"tag\">Enter Tag</label>\n <input type=\"text\" id=\"tag\" name=\"tag\" />\n <input type=\"submit\" value=\"energize\" />\n <h3>Tags:</h3><div id=\"tags\"></div>\n <h3>Photos:</h3><ul id=\"photos\"></ul>\n</form>\n\nAll the JavaScript you\u2019ll need (for a basic display) is this:\n\nfunction populate(){\n var tag = document.getElementById('tag').value;\n document.getElementById('photos').innerHTML = getFlickr.html[tag].replace(/_m\\.jpg/g,'_s.jpg');\n document.getElementById('tags').innerHTML = getFlickr.tags[tag];\n return false;\n}\n\nEasy as pie, enjoy!\n\nCheck out the example page and try the form to see the results.", "year": "2006", "author": "Christian Heilmann", "author_slug": "chrisheilmann", "published": "2006-12-03T00:00:00+00:00", "url": "https://24ways.org/2006/flickr-photos-on-demand/", "topic": "code"} {"rowid": 143, "title": "Marking Up a Tag Cloud", "contents": "Everyone\u2019s doing it. \n\nThe problem is, everyone\u2019s doing it wrong. \n\nHarsh words, you might think. But the crimes against decent markup are legion in this area. You see, I\u2019m something of a markup and semantics junkie. So I\u2019m going to analyse some of the more well-known tag clouds on the internet, explain what\u2019s wrong, and then show you one way to do it better. \n\ndel.icio.us \n\nI think the first ever tag cloud I saw was on del.icio.us. Here\u2019s how they mark it up. \n\n<div class=\"alphacloud\">\n\t<a href=\"/tag/.net\" class=\"lb s2\">.net</a>\n\t<a href=\"/tag/advertising\" class=\" s3\">advertising</a>\n\t<a href=\"/tag/ajax\" class=\" s5\">ajax</a>\n\t...\n</div>\n\nUnfortunately, that is one of the worst examples of tag cloud markup I have ever seen. The page states that a tag cloud is a list of tags where size reflects popularity. However, despite describing it in this way to the human readers, the page\u2019s author hasn\u2019t described it that way in the markup. It isn\u2019t a list of tags, just a bunch of anchors in a <div>. This is also inaccessible because a screenreader will not pause between adjacent links, and in some configurations will not announce the individual links, but rather all of the tags will be read as just one link containing a whole bunch of words. Markup crime number one. \n\nFlickr \n\nAh, Flickr. The darling photo sharing site of the internet, and the biggest blind spot in every standardista\u2019s vision. Forgive it for having atrocious markup and sometimes confusing UI because it\u2019s just so much damn fun to use. Let\u2019s see what they do. \n\n<p id=\"TagCloud\">\n\t\u00a0<a href=\"/photos/tags/06/\" style=\"font-size: 14px;\">06</a>\u00a0\n\t\u00a0<a href=\"/photos/tags/africa/\" style=\"font-size: 12px;\">africa</a>\u00a0\n\t\u00a0<a href=\"/photos/tags/amsterdam/\" style=\"font-size: 14px;\">amsterdam</a>\u00a0\n\t...\n</p>\n\nAgain we have a simple collection of anchors like del.icio.us, only this time in a paragraph. But rather than using a class to represent the size of the tag they use an inline style. An inline style using a pixel-based font size. That\u2019s so far away from the goal of separating style from content, they might as well use a <font> tag. You could theoretically parse that to extract the information, but you have more work to guess what the pixel sizes represent. Markup crime number two (and extra jail time for using non-breaking spaces purely for visual spacing purposes.)\n\nTechnorati \n\nAh, now. Here, you\u2019d expect something decent. After all, the Overlord of microformats and King of Semantics Tantek \u00c7elik works there. Surely we\u2019ll see something decent here? \n\n<ol class=\"heatmap\">\n\t<li><em><em><em><em><a href=\"/tag/Britney+Spears\">Britney Spears</a></em></em></em></em></li>\n\t<li><em><em><em><em><em><em><em><em><em><a href=\"/tag/Bush\">Bush</a></em></em></em></em></em></em></em></em></em></li>\n\t<li><em><em><em><em><em><em><em><em><em><em><em><em><em><a href=\"/tag/Christmas\">Christmas</a></em></em></em></em></em></em></em></em></em></em></em></em></em></li>\n\t...\n\t<li><em><em><em><em><em><em><a href=\"/tag/SEO\">SEO</a></em></em></em></em></em></em></li>\n\t<li><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href=\"/tag/Shopping\">Shopping</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></li>\n\t...\n</ol>\n\nUnfortunately it turns out not to be that decent, and stop calling me Shirley. It\u2019s not exactly terrible code. It does recognise that a tag cloud is a list of links. And, since they\u2019re in alphabetical order, that it\u2019s an ordered list of links. That\u2019s nice. However \u2026 fifteen nested <em> tags? FIFTEEN? That\u2019s emphasis for you. Yes, it is parse-able, but it\u2019s also something of a strange way of looking at emphasis. The HTML spec states that <em> is emphasis, and <strong> is for stronger emphasis. Nesting <em> tags seems counter to the idea that different tags are used for different levels of emphasis. Plus, if you had a screen reader that stressed the voice for emphasis, what would it do? Shout at you? Markup crime number three. \n\nSo what should it be? \n\nAs del.icio.us tells us, a tag cloud is a list of tags where the size that they are rendered at contains extra information. However, by hiding the extra context purely within the CSS or the HTML tags used, you are denying that context to some users. The basic assumption being made is that all users will be able to see the difference between font sizes, and this is demonstrably false. \n\nA better way to code a tag cloud is to put the context of the cloud within the content, not the markup or CSS alone. As an example, I\u2019m going to take some of my favourite flickr tags and put them into a cloud which communicates the relative frequency of each tag. \n\nTo start with a tag cloud in its most basic form is just a list of links. I am going to present them in alphabetical order, so I\u2019ll use an ordered list. Into each list item I add the number of photos I have with that particular tag. The tag itself is linked to the page on flickr which contains those photos. So we end up with this first example. To display this as a traditional tag cloud, we need to alter it in a few ways: \n\n\n\tThe items need to be displayed next to each other, rather than one-per-line\n\tThe context information should be hidden from display (but not from screen readers)\n\tThe tag should link to the page of items with that tag\n\n\nDisplaying the items next to each other simply means setting the display of the list elements to inline. The context can be hidden by wrapping it in a <span> and then using the off-left method to hide it. And the link just means adding an anchor (with rel=\"tag\" for some extra microformats bonus points). So, now we have a simple collection of links in our second example. \n\nThe last stage is to add the sizes. Since we already have context in our content, the size is purely for visual rendering, so we can just use classes to define the different sizes. For my example, I\u2019ll use a range of class names from not-popular through ultra-popular, in order of smallest to largest, and then use CSS to define different font sizes. If you preferred, you could always use less verbose class names such as size1 through size6. Anyway, adding some classes and CSS gives us our final example, a semantic and more accessible tag cloud.", "year": "2006", "author": "Mark Norman Francis", "author_slug": "marknormanfrancis", "published": "2006-12-09T00:00:00+00:00", "url": "https://24ways.org/2006/marking-up-a-tag-cloud/", "topic": "code"} {"rowid": 145, "title": "The Neverending (Background Image) Story", "contents": "Everyone likes candy for Christmas, and there\u2019s none better than eye candy. Well, that, and just more of the stuff. Today we\u2019re going to combine both of those good points and look at how to create a beautiful background image that goes on and on\u2026 forever!\n\nOf course, each background image is different, so instead of agonising over each and every pixel, I\u2019m going to concentrate on five key steps that you can apply to any of your own repeating background images. In this example, we\u2019ll look at the Miami Beach background image used on the new FOWA site, which I\u2019m afraid is about as un-festive as you can get.\n\n1. Choose your image wisely\n\nI find there are three main criteria when judging photos you\u2019re considering for repetition manipulation (or \u2018repetulation\u2019, as I like to say)\u2026\n\n\n\tsimplicity (beware of complex patterns)\n\tangle and perspective (watch out for shadows and obvious vanishing points)\n\tconsistent elements (for easy cloning)\n\n\nYou might want to check out this annotated version of the image, where I\u2019ve highlighted elements of the photo that led me to choose it as the right one.\n\nThe original image purchased from iStockPhoto.\n\nThe Photoshopped version used on the FOWA site.\n\n2. The power of horizontal lines\n\nWith the image chosen and your cursor poised for some Photoshop magic, the most useful thing you can do is drag out the edge pixels from one side of the image to create a kind of rough colour \u2018template\u2019 on which to work over. It doesn\u2019t matter which side you choose, although you might find it beneficial to use the one with the simplest spread of colour and complex elements.\n\nClick and hold on the marquee tool in the toolbar and select the \u2018single column marquee tool\u2019, which will span the full height of your document but will only be one pixel wide. Make the selection right at the edge of your document, press ctrl-c / cmd-c to copy the selection you made, create a new layer, and hit ctrl-v / cmd-v to paste the selection onto your new layer. using free transform (ctrl-t / cmd-t), drag out your selection so that it becomes as wide as your entire canvas. \n\nA one-pixel-wide selection stretched out to the entire width of the canvas.\n\n3. Cloning\n\nIt goes without saying that the trusty clone tool is one of the most important in the process of creating a seamlessly repeating background image, but I think it\u2019s important to be fairly loose with it. Always clone on to a new layer so that you\u2019ve got the freedom to move it around, but above all else, use the eraser tool to tweak your cloned areas: let that handle the precision stuff and you won\u2019t have to worry about getting your clones right first time.\n\nIn the example below, you can see how I overcame the problem of the far-left tree shadow being chopped off by cloning the shadow from the tree on its right. \n\nThe edge of the shadow is cut off and needs to be \u2018made\u2019 from a pre-existing element.\n\nThe successful clone completes the missing shadow.\n\nThe two elements are obviously very similar but it doesn\u2019t look like a clone because the majority of the shape is \u2018genuine\u2019 and only a small part is a duplicate. Also, after cloning I transformed the duplicate, erased parts of it, used gradients, and \u2014 ooh, did someone mention gradients?\n\n4. Never underestimate a gradient\n\nFor this image, I used gradients in a similar way to a brush: covering large parts of the canvas with a colour that faded out to a desired point, before erasing certain parts for accuracy.\n\nSeveral of the gradients and brushes that make up the \u2018customised\u2019 part of the image, visible when the main photograph layer is hidden.\n\nThe full composite.\n\nGradients are also a bit of an easy fix: you can use a gradient on one side of the image, flip it horizontally, and then use it again on the opposite side to make a more seamless join.\n\nSpeaking of which\u2026\n\n5. Sewing the seams\n\nNo matter what kind of magic Photoshop dust you sprinkle over your image, there will still always be the area where the two edges meet: that scary \u2018loop\u2019 point. Fret ye not, however, for there\u2019s help at hand in the form of a nice little cheat. Even though the loop point might still be apparent, we can help hide it by doing something to throw viewers off the scent.\n\nThe seam is usually easy to spot because it\u2019s a blank area with not much detail or colour variation, so in order to disguise it, go against the rule: put something across it!\n\nThis isn\u2019t quite as challenging as it may sound, because if we intentionally make our own \u2018object\u2019 to span the join, we can accurately measure the exact halfway point where we need to split it across the two sides of the image. This is exactly what I did with the FOWA background image: I made some clouds!\n\nA sky with no clouds in an unhappy one.\n\nA simple soft white brush creates a cloud-like formation in the sky.\n\nAfter taking the cloud\u2019s opacity down to 20%, I used free transform to highlight the boundaries of the layer. I then moved it over to the right, so that the middle of the layer perfectly aligned with the right side of the canvas.\n\nFinally, I duplicated the layer and did the same in reverse: dragging the layer over to the left and making sure that the middle of the duplicate layer perfectly aligned with the left side of the canvas.\n\nAnd there you have it! Boom! Ta-da! Et Voila! To see the repeating background image in action, visit futureofwebapps.com on a large widescreen monitor or see a simulation of the effect.\n\nThanks for reading, folks. Have a great Christmas!", "year": "2007", "author": "Elliot Jay Stocks", "author_slug": "elliotjaystocks", "published": "2007-12-03T00:00:00+00:00", "url": "https://24ways.org/2007/the-neverending-background-image-story/", "topic": "code"} {"rowid": 147, "title": "Christmas Is In The AIR", "contents": "That\u2019s right, Christmas is coming up fast and there\u2019s plenty of things to do. Get the tree and lights up, get the turkey, buy presents and who know what else. And what about Santa? He\u2019s got a list. I\u2019m pretty sure he\u2019s checking it twice.\n\nSure, we could use an existing list making web site or even a desktop widget. But we\u2019re geeks! What\u2019s the fun in that? Let\u2019s build our own to-do list application and do it with Adobe AIR!\n\nWhat\u2019s Adobe AIR?\n\nAdobe AIR, formerly codenamed Apollo, is a runtime environment that runs on both Windows and OSX (with Linux support to follow). This runtime environment lets you build desktop applications using Adobe technologies like Flash and Flex. Oh, and HTML. That\u2019s right, you web standards lovin\u2019 maniac. You can build desktop applications that can run cross-platform using the trio of technologies, HTML, CSS and JavaScript.\n\nIf you\u2019ve tried developing with AIR before, you\u2019ll need to get re-familiarized with the latest beta release as many things have changed since the last one (such as the API and restrictions within the sandbox.)\n\nTo get started\n\nTo get started in building an AIR application, you\u2019ll need two basic things:\n\n\n\tThe AIR runtime. The runtime is needed to run any AIR-based application.\n\tThe SDK. The software development kit gives you all the pieces to test your application. Unzip the SDK into any folder you wish.\n\n\nYou\u2019ll also want to get your hands on the JavaScript API documentation which you\u2019ll no doubt find yourself getting into before too long. (You can download it, too.)\n\nAlso of interest, some development environments have support for AIR built right in. Aptana doesn\u2019t have support for beta 3 yet but I suspect it\u2019ll be available shortly.\n\nWithin the SDK, there are two main tools that we\u2019ll use: one to test the application (ADL) and another to build a distributable package of our application (ADT). I\u2019ll get into this some more when we get to that stage of development.\n\nBuilding our To-do list application\n\nThe first step to building an application within AIR is to create an XML file that defines our default application settings. I call mine application.xml, mostly because Aptana does that by default when creating a new AIR project. It makes sense though and I\u2019ve stuck with it. Included in the templates folder of the SDK is an example XML file that you can use.\n\nThe first key part to this after specifying things like the application ID, version, and filename, is to specify what the default content should be within the content tags. Enter in the name of the HTML file you wish to load. Within this HTML file will be our application.\n\n<content>ui.html</content>\n\nCreate a new HTML document and name it ui.html and place it in the same directory as the application.xml file. The first thing you\u2019ll want to do is copy over the AIRAliases.js file from the frameworks folder of the SDK and add a link to it within your HTML document.\n\n<script type=\"text/javascript\" src=\"AIRAliases.js\"></script>\n\nThe aliases create shorthand links to all of the Flash-based APIs.\n\nNow is probably a good time to explain how to debug your application.\n\nDebugging our application\n\nSo, with our XML file created and HTML file started, let\u2019s try testing our \u2018application\u2019. We\u2019ll need the ADL application located in BIN folder of the SDK and tell it to run the application.xml file.\n\n/path/to/adl /path/to/application.xml\n\nYou can also just drag the XML file onto ADL and it\u2019ll accomplish the same thing. If you just did that and noticed that your blank application didn\u2019t load, you\u2019d be correct. It\u2019s running but isn\u2019t visible. Which at this point means you\u2019ll have to shut down the ADL process. Sorry about that!\n\nChanging the visibility\n\nYou have two ways to make your application visible. You can do it automatically by setting the placing true in the visible tag within the application.xml file.\n\n<visible>true</visible>\n\nThe other way is to do it programmatically from within your application. You\u2019d want to do it this way if you had other startup tasks to perform before showing the interface. To turn the UI on programmatically, simple set the visible property of nativeWindow to true.\n\n<script type=\"text/javascript\">\n\tnativeWindow.visible = true;\n</script>\n\nSandbox Security\n\nNow that we have an application that we can see when we start it, it\u2019s time to build the to-do list application. In doing so, you\u2019d probably think that using a JavaScript library is a really good idea \u2014 and it can be but there are some limitations within AIR that have to be considered.\n\nAn HTML document, by default, runs within the application sandbox. You have full access to the AIR APIs but once the onload event of the window has fired, you\u2019ll have a limited ability to make use of eval and other dynamic script injection approaches. This limits the ability of external sources from gaining access to everything the AIR API offers, such as database and local file system access. You\u2019ll still be able to make use of eval for evaluating JSON responses, which is probably the most important if you wish to consume JSON-based services.\n\nIf you wish to create a greater wall of security between AIR and your HTML document loading in external resources, you can create a child sandbox. We won\u2019t need to worry about it for our application so I won\u2019t go any further into it but definitely keep this in mind.\n\nFinally, our application\n\nGetting tired of all this preamble? Let\u2019s actually build our to-do list application. I\u2019ll use jQuery because it\u2019s small and should suit our needs nicely. Let\u2019s begin with some structure:\n\n<body>\n\t<input type=\"text\" id=\"text\" value=\"\">\n\t<input type=\"button\" id=\"add\" value=\"Add\">\n\t<ul id=\"list\"></ul>\n</body>\n\nNow we need to wire up that button to actually add a new item to our to-do list.\n\n<script type=\"text/javascript\">\n$(document).ready(function(){\n\t// make sure the application is visible\n\tnativeWindow.visible = true;\n\t$('#add').click(function(){\n\t\tvar t = $('#text').val();\n\t\tif(t)\n\t\t{\n\t\t\t// use DOM methods to create the new list item\n\t\t\tvar li = document.createElement('li');\n\t\t\t// the extra space at the end creates a buffer between the text\n\t\t\t// and the delete link we're about to add\n\t\t\tli.appendChild(document.createTextNode(t + ' '));\n\t\t\t// create the delete link\n\t\t\tvar del = document.createElement('a');\n\t\t\t// this makes it a true link. I feel dirty doing this.\n\t\t\tdel.setAttribute('href', '#');\n\t\t\tdel.addEventListener('click', function(evt){\n\t\t\t\tthis.parentNode.parentNode.removeChild(this.parentNode);\n\t\t\t});\n\t\t\tdel.appendChild(document.createTextNode('[del]'));\n\t\t\tli.appendChild(del);\n\t\t\t// append everything to the list\n\t\t\t$('#list').append(li);\n\t\t\t//reset the text box\n\t\t\t$('#text').val('');\n\t\t}\n\t})\n});\n</script>\n\nAnd just like that, we\u2019ve got a to-do list! That\u2019s it! Just never close your application and you\u2019ll remember everything. Okay, that\u2019s not very practical. You need to have some way of storing your to-do items until the next time you open up the application.\n\nStoring Data\n\nYou\u2019ve essentially got 4 different ways that you can store data:\n\n\n\tUsing the local database. AIR comes with SQLLite built in. That means you can create tables and insert, update and select data from that database just like on a web server.\n\tUsing the file system. You can also create files on the local machine. You have access to a few folders on the local system such as the documents folder and the desktop.\n\tUsing EcryptedLocalStore. I like using the EcryptedLocalStore because it allows you to easily save key/value pairs and have that information encrypted. All this within just a couple lines of code.\n\tSending the data to a remote API. Our to-do list could sync up with Remember the Milk, for example.\n\n\nTo demonstrate some persistence, we\u2019ll use the file system to store our files. In addition, we\u2019ll let the user specify where the file should be saved. This way, we can create multiple to-do lists, keeping them separate and organized.\n\nThe application is now broken down into 4 basic tasks:\n\n\n\tLoad data from the file system.\n\tPerform any interface bindings.\n\tManage creating and deleting items from the list.\n\tSave any changes to the list back to the file system.\n\n\nLoading in data from the file system\n\nWhen the application starts up, we\u2019ll prompt the user to select a file or specify a new to-do list. Within AIR, there are 3 main file objects: File, FileMode, and FileStream. File handles file and path names, FileMode is used as a parameter for the FileStream to specify whether the file should be read-only or for write access. The FileStream object handles all the read/write activity.\n\nThe File object has a number of shortcuts to default paths like the documents folder, the desktop, or even the application store. In this case, we\u2019ll specify the documents folder as the default location and then use the browseForSave method to prompt the user to specify a new or existing file. If the user specifies an existing file, they\u2019ll be asked whether they want to overwrite it.\n\nvar store = air.File.documentsDirectory;\nvar fileStream = new air.FileStream();\nstore.browseForSave(\"Choose To-do List\");\n\nThen we add an event listener for when the user has selected a file. When the file is selected, we check to see if the file exists and if it does, read in the contents, splitting the file on new lines and creating our list items within the interface.\n\nstore.addEventListener(air.Event.SELECT, fileSelected);\nfunction fileSelected()\n{\n\tair.trace(store.nativePath);\n\t// load in any stored data\n\tvar byteData = new air.ByteArray();\n\tif(store.exists)\n\t{\n\t\tfileStream.open(store, air.FileMode.READ);\n\t\tfileStream.readBytes(byteData, 0, store.size);\n\t\tfileStream.close();\n\n\t\tif(byteData.length > 0)\n\t\t{\n\t\t\tvar s = byteData.readUTFBytes(byteData.length);\n\t\t\toldlist = s.split(\u201c\\r\\n\u201d);\n\n\t\t\t// create todolist items\n\t\t\tfor(var i=0; i < oldlist.length; i++)\n\t\t\t{\n\t\t\t\tcreateItem(oldlist[i], (new Date()).getTime() + i );\n\t\t\t}\n\t\t}\n\t}\n}\n\nPerform Interface Bindings\n\nThis is similar to before where we set the click event on the Add button but we\u2019ve moved the code to save the list into a separate function.\n\n$('#add').click(function(){\n\t\tvar t = $('#text').val();\n\t\tif(t){\n\t\t\t// create an ID using the time\n\t\t\tcreateItem(t, (new Date()).getTime() );\n\t\t}\n})\n\nManage creating and deleting items from the list\n\nThe list management is now in its own function, similar to before but with some extra information to identify list items and with calls to save our list after each change.\n\nfunction createItem(t, id)\n{\n\tif(t.length == 0) return;\n\t// add it to the todo list\n\ttodolist[id] = t;\n\t// use DOM methods to create the new list item\n\tvar li = document.createElement('li');\n\t// the extra space at the end creates a buffer between the text\n\t// and the delete link we're about to add\n\tli.appendChild(document.createTextNode(t + ' '));\n\t// create the delete link\n\tvar del = document.createElement('a');\n\t// this makes it a true link. I feel dirty doing this.\n\tdel.setAttribute('href', '#');\n\tdel.addEventListener('click', function(evt){\n\t\tvar id = this.id.substr(1);\n\t\tdelete todolist[id]; // remove the item from the list\n\t\tthis.parentNode.parentNode.removeChild(this.parentNode);\n\t\tsaveList();\n\t});\n\tdel.appendChild(document.createTextNode('[del]'));\n\tdel.id = 'd' + id;\n\tli.appendChild(del);\n\t// append everything to the list\n\t$('#list').append(li);\n\t//reset the text box\n\t$('#text').val('');\n\tsaveList();\n}\n\nSave changes to the file system\n\nAny time a change is made to the list, we update the file. The file will always reflect the current state of the list and we\u2019ll never have to click a save button. It just iterates through the list, adding a new line to each one.\n\nfunction saveList(){\n\tif(store.isDirectory) return;\n\tvar packet = '';\n\tfor(var i in todolist)\n\t{\n\t\tpacket += todolist[i] + '\\r\\n';\n\t}\n\tvar bytes = new air.ByteArray();\n\tbytes.writeUTFBytes(packet);\n\tfileStream.open(store, air.FileMode.WRITE);\n\tfileStream.writeBytes(bytes, 0, bytes.length);\n\tfileStream.close();\n}\n\nOne important thing to mention here is that we check if the store is a directory first. The reason we do this goes back to our browseForSave call. If the user cancels the dialog without selecting a file first, then the store points to the documentsDirectory that we set it to initially. Since we haven\u2019t specified a file, there\u2019s no place to save the list.\n\nHopefully by this point, you\u2019ve been thinking of some cool ways to pimp out your list. Now we need to package this up so that we can let other people use it, too.\n\nCreating a Package\n\nNow that we\u2019ve created our application, we need to package it up so that we can distribute it. This is a two step process. The first step is to create a code signing certificate (or you can pay for one from Thawte which will help authenticate you as an AIR application developer).\n\nTo create a self-signed certificate, run the following command. This will create a PFX file that you\u2019ll use to sign your application.\n\nadt -certificate -cn todo24ways 1024-RSA todo24ways.pfx mypassword\n\nAfter you\u2019ve done that, you\u2019ll need to create the package with the certificate\n\nadt -package -storetype pkcs12 -keystore todo24ways.pfx todo24ways.air application.xml .\n\nThe important part to mention here is the period at the end of the command. We\u2019re telling it to package up all files in the current directory.\n\nAfter that, just run the AIR file, which will install your application and run it.\n\nImportant things to remember about AIR\n\nWhen developing an HTML application, the rendering engine is Webkit. You\u2019ll thank your lucky stars that you aren\u2019t struggling with cross-browser issues. (My personal favourites are multiple backgrounds and border radius!)\n\nBe mindful of memory leaks. Things like Ajax calls and event binding can cause applications to slowly leak memory over time. Web pages are normally short lived but desktop applications are often open for hours, if not days, and you may find your little desktop application taking up more memory than anything else on your machine!\n\nThe WebKit runtime itself can also be a memory hog, usually taking about 15MB just for itself. If you create multiple HTML windows, it\u2019ll add another 15MB to your memory footprint. Our little to-do list application shouldn\u2019t be much of a concern, though.\n\nThe other important thing to remember is that you\u2019re still essentially running within a Flash environment. While you probably won\u2019t notice this working in small applications, the moment you need to move to multiple windows or need to accomplish stuff beyond what HTML and JavaScript can give you, the need to understand some of the Flash-based elements will become more important.\n\nLastly, the other thing to remember is that HTML links will load within the AIR application. If you want a link to open in the users web browser, you\u2019ll need to capture that event and handle it on your own. The following code takes the HREF from a clicked link and opens it in the default web browser.\n\nair.navigateToURL(new air.URLRequest(this.href));\n\nOnly the beginning\n\nOf course, this is only the beginning of what you can do with Adobe AIR. You don\u2019t have the same level of control as building a native desktop application, such as being able to launch other applications, but you do have more control than what you could have within a web application. Check out the Adobe AIR Developer Center for HTML and Ajax for tutorials and other resources.\n\nNow, go forth and create your desktop applications and hopefully you finish all your shopping before Christmas!\n\nDownload the example files.", "year": "2007", "author": "Jonathan Snook", "author_slug": "jonathansnook", "published": "2007-12-19T00:00:00+00:00", "url": "https://24ways.org/2007/christmas-is-in-the-air/", "topic": "code"} {"rowid": 153, "title": "JavaScript Internationalisation", "contents": "or: Why Rudolph Is More Than Just a Shiny Nose\n\nDunder sat, glumly staring at the computer screen.\n\n\u201cWhat\u2019s up, Dunder?\u201d asked Rudolph, entering the stable and shaking off the snow from his antlers.\n\n\u201cWell,\u201d Dunder replied, \u201cI\u2019ve just finished coding the new reindeer intranet Santa Claus asked me to do. You know how he likes to appear to be at the cutting edge, talking incessantly about Web 2.0, AJAX, rounded corners; he even spooked Comet recently by talking about him as if he were some pushy web server.\n\n\u201cI\u2019ve managed to keep him happy, whilst also keeping it usable, accessible, and gleaming \u2014 and I\u2019m still on the back row of the sleigh! But anyway, given the elves will be the ones using the site, and they come from all over the world, the site is in multiple languages. Which is great, except when it comes to the preview JavaScript I\u2019ve written for the reindeer order form. Here, have a look\u2026\u201d\n\nAs he said that, he brought up the textileRef:8234272265470b85d91702:linkStartMarker:\u201corder\n form in French\u201d:/examples/javascript-internationalisation/initial.fr.html on the screen. (Same in English).\n\n\u201cLooks good,\u201d said Rudolph.\n\n\u201cBut if I add some items,\u201d said Dunder, \u201cthe preview appears in English, as it\u2019s hard-coded in the JavaScript. I don\u2019t want separate code for each language, as that\u2019s just silly \u2014 I thought about just having if statements, but that doesn\u2019t scale at all\u2026\u201d\n\n\u201cAnd there\u2019s more, you aren\u2019t displaying large numbers in French properly, either,\u201d added Rudolph, who had been playing and looking at part of the source code:\n\nfunction update_text() {\n\tvar hay = getValue('hay');\n\tvar carrots = getValue('carrots');\n\tvar bells = getValue('bells');\n\tvar total = 50 * bells + 30 * hay + 10 * carrots;\n\tvar out = 'You are ordering '\n\t\t+ pretty_num(hay) + ' bushel' + pluralise(hay) + ' of hay, '\n\t\t+ pretty_num(carrots) + ' carrot' + pluralise(carrots)\n\t\t+ ', and ' + pretty_num(bells) + ' shiny bell' + pluralise(bells)\n\t\t+ ', at a total cost of <strong>' + pretty_num(total)\n\t\t+ '</strong> gold pieces. Thank you.';\n\tdocument.getElementById('preview').innerHTML = out;\n}\nfunction pretty_num(n) {\n\tn += '';\n\tvar o = '';\n\tfor (i=n.length; i>3; i-=3) {\n\t\to = ',' + n.slice(i-3, i) + o;\n\t}\n\to = n.slice(0, i) + o;\n\treturn o;\n}\nfunction pluralise(n) {\n\tif (n!=1) return 's';\n\treturn '';\n}\n\n\u201cOh, botheration!\u201d cried Dunder. \u201cThis is just so complicated.\u201d\n\n\u201cIt doesn\u2019t have to be,\u201d said Rudolph, \u201cyou just have to think about things in a slightly different way from what you\u2019re used to. As we\u2019re only a simple example, we won\u2019t be able to cover all possibilities, but for starters, we need some way of providing different information to the script dependent on the language. We\u2019ll create a global i18n object, say, and fill it with the correct language information. The first variable we\u2019ll need will be a thousands separator, and then we can change the pretty_num function to use that instead:\n\nfunction pretty_num(n) {\n\tn += '';\n\tvar o = '';\n\tfor (i=n.length; i>3; i-=3) {\n\t\to = i18n.thousands_sep + n.slice(i-3, i) + o;\n\t}\n\to = n.slice(0, i) + o;\n\treturn o;\n}\n\n\u201cThe i18n object will also contain our translations, which we will access through a function called _() \u2014 that\u2019s just an underscore. Other languages have a function of the same name doing the same thing. It\u2019s very simple:\n\nfunction _(s) {\n\tif (typeof(i18n)!='undefined' && i18n[s]) {\n\t\treturn i18n[s];\n\t}\n\treturn s;\n}\n\n\u201cSo if a translation is available and provided, we\u2019ll use that; otherwise we\u2019ll default to the string provided \u2014 which is helpful if the translation begins to lag behind the site\u2019s text at all, as at least something will be output.\u201d\n\n\u201cGot it,\u201d said Dunder. \u201c _('Hello Dunder') will print the translation of that string, if one exists, \u2018Hello Dunder\u2019 if not.\u201d\n\n\u201cExactly. Moving on, your plural function breaks even in English if we have a word where the plural doesn\u2019t add an s \u2014 like \u2018children\u2019.\u201d\n\n\u201cYou\u2019re right,\u201d said Dunder. \u201cHow did I miss that?\u201d\n\n\u201cNo harm done. Better to provide both singular and plural words to the function and let it decide which to use, performing any translation as well:\n\nfunction pluralise(s, p, n) {\n\tif (n != 1) return _(p);\n\treturn _(s);\n}\n\n\u201cWe\u2019d have to provide different functions for different languages as we employed more elves and got more complicated \u2014 for example, in Polish, the word \u2018file\u2019 pluralises like this: 1 plik, 2-4 pliki, 5-21 plik\u00f3w, 22-24 pliki, 25-31 plik\u00f3w, and so on.\u201d (More information on plural forms)\n\n\u201cGosh!\u201d\n\n\u201cNext, as different languages have different word orders, we must stop using concatenation to construct sentences, as it would be impossible for other languages to fit in; we have to keep coherent strings together. Let\u2019s rewrite your update function, and then go through it:\n\nfunction update_text() {\n\tvar hay = getValue('hay');\n\tvar carrots = getValue('carrots');\n\tvar bells = getValue('bells');\n\tvar total = 50 * bells + 30 * hay + 10 * carrots;\n\thay = sprintf(pluralise('%s bushel of hay', '%s bushels of hay', hay), pretty_num(hay));\n\tcarrots = sprintf(pluralise('%s carrot', '%s carrots', carrots), pretty_num(carrots));\n\tbells = sprintf(pluralise('%s shiny bell', '%s shiny bells', bells), pretty_num(bells));\n\tvar list = sprintf(_('%s, %s, and %s'), hay, carrots, bells);\n\tvar out = sprintf(_('You are ordering %s, at a total cost of <strong>%s</strong> gold pieces.'),\n\t\tlist, pretty_num(total));\n\tout += ' ';\n\tout += _('Thank you.');\n\tdocument.getElementById('preview').innerHTML = out;\n}\n\n\u201c sprintf is a function in many other languages that, given a format string and some variables, slots the variables into place within the string. JavaScript doesn\u2019t have such a function, so we\u2019ll write our own. Again, keep it simple for now, only integers and strings; I\u2019m sure more complete ones can be found on the internet.\n\nfunction sprintf(s) {\n\tvar bits = s.split('%');\n\tvar out = bits[0];\n\tvar re = /^([ds])(.*)$/;\n\tfor (var i=1; i<bits.length; i++) {\n\t\tp = re.exec(bits[i]);\n\t\tif (!p || arguments[i]==null) continue;\n\t\tif (p[1] == 'd') {\n\t\t\tout += parseInt(arguments[i], 10);\n\t\t} else if (p[1] == 's') {\n\t\t\tout += arguments[i];\n\t\t}\n\t\tout += p[2];\n\t}\n\treturn out;\n}\n\n\u201cLastly, we need to create one file for each language, containing our i18n object, and then include that from the relevant HTML. Here\u2019s what a blank translation file would look like for your order form:\n\nvar i18n = {\n\tthousands_sep: ',',\n\t\"%s bushel of hay\": '',\n\t\"%s bushels of hay\": '',\n\t\"%s carrot\": '',\n\t\"%s carrots\": '',\n\t\"%s shiny bell\": '',\n\t\"%s shiny bells\": '',\n\t\"%s, %s, and %s\": '',\n\t\"You are ordering %s, at a total cost of <strong>%s</strong> gold pieces.\": '',\n\t\"Thank you.\": ''\n};\n\n\u201cIf you implement this across the intranet, you\u2019ll want to investigate the xgettext program, which can automatically extract all strings that need translating from all sorts of code files into a standard .po file (I think Python mode works best for JavaScript). You can then use a different program to take the translated .po file and automatically create the language-specific JavaScript files for us.\u201d (e.g. German .po file for PledgeBank, mySociety\u2019s .po-.js script, example output)\n\nWith a flourish, Rudolph finished editing. \u201cAnd there we go, localised JavaScript in English, French, or German, all using the same main code.\u201d\n\n\u201cThanks so much, Rudolph!\u201d said Dunder.\n\n\u201cI\u2019m not just a pretty nose!\u201d Rudolph quipped. \u201cOh, and one last thing \u2014 please comment liberally explaining the context of strings you use. Your translator will thank you, probably at the same time as they point out the four hundred places you\u2019ve done something in code that only works in your language and no-one else\u2019s\u2026\u201d\n\nThanks to Tim Morley and Edmund Grimley Evans for the French and German translations respectively.", "year": "2007", "author": "Matthew Somerville", "author_slug": "matthewsomerville", "published": "2007-12-08T00:00:00+00:00", "url": "https://24ways.org/2007/javascript-internationalisation/", "topic": "code"} {"rowid": 157, "title": "Capturing Caps Lock", "contents": "One of the more annoying aspects of having to remember passwords (along with having to remember loads of them) is that if you\u2019ve got Caps Lock turned on accidentally when you type one in, it won\u2019t work, and you won\u2019t know why. Most desktop computers alert you in some way if you\u2019re trying to enter your password to log on and you\u2019ve enabled Caps Lock; there\u2019s no reason why the web can\u2019t do the same. What we want is a warning \u2013 maybe the user wants Caps Lock on, because maybe their password is in capitals \u2013 rather than something that interrupts what they\u2019re doing. Something subtle.\n\nBut that doesn\u2019t answer the question of how to do it. Sadly, there\u2019s no way of actually detecting whether Caps Lock is on directly. However, there\u2019s a simple work-around; if the user presses a key, and it\u2019s a capital letter, and they don\u2019t have the Shift key depressed, why then they must have Caps Lock on! Simple. \n\nDOM scripting allows your code to be notified when a key is pressed in an element; when the key is pressed, you get the ASCII code for that key. Capital letters, A to Z, have ASCII codes 65 to 90. So, the code would look something like:\n\non a key press\n\tif the ASCII code for the key is between 65 and 90 *and* if shift is pressed\n\t\twarn the user that they have Caps Lock on, but let them carry on\n\tend if\nend keypress\n\nThe actual JavaScript for this is more complicated, because both event handling and keypress information differ across browsers. Your event handling functions are passed an event object, except in Internet Explorer where you use the global event object; the event object has a which parameter containing the ASCII code for the key pressed, except in Internet Explorer where the event object has a keyCode parameter; some browsers store whether the shift key is pressed in a shiftKey parameter and some in a modifiers parameter. All this boils down to code that looks something like this:\n\nkeypress: function(e) {\n\tvar ev = e ? e : window.event;\n\tif (!ev) {\n\t\treturn;\n\t}\n\tvar targ = ev.target ? ev.target : ev.srcElement;\n\t// get key pressed\n\tvar which = -1;\n\tif (ev.which) {\n\t\twhich = ev.which;\n\t} else if (ev.keyCode) {\n\t\twhich = ev.keyCode;\n\t}\n\t// get shift status\n\tvar shift_status = false;\n\tif (ev.shiftKey) {\n\t\tshift_status = ev.shiftKey;\n\t} else if (ev.modifiers) {\n\t\tshift_status = !!(ev.modifiers & 4);\n\t}\n\n\t// At this point, you have the ASCII code in \u201cwhich\u201d, \n\t// and shift_status is true if the shift key is pressed\n}\n\nThen it\u2019s just a check to see if the ASCII code is between 65 and 90 and the shift key is pressed. (You also need to do the same work if the ASCII code is between 97 (a) and 122 (z) and the shift key is not pressed, because shifted letters are lower-case if Caps Lock is on.)\n\nif (((which >= 65 && which <= 90) && !shift_status) || \n\t((which >= 97 && which <= 122) && shift_status)) {\n\t// uppercase, no shift key\n\t/* SHOW THE WARNING HERE */\n} else {\n\t/* HIDE THE WARNING HERE */\n}\n\nThe warning can be implemented in many different ways: highlight the password field that the user is typing into, show a tooltip, display text next to the field. For simplicity, this code shows the warning as a previously created image, with appropriate alt text. Showing the warning means creating a new <img> tag with DOM scripting, dropping it into the page, and positioning it so that it\u2019s next to the appropriate field. The image looks like this:\n\n\n\nYou know the position of the field the user is typing into (from its offsetTop and offsetLeft properties) and how wide it is (from its offsetWidth properties), so use createElement to make the new img element, and then absolutely position it with style properties so that it appears in the appropriate place (near to the text field). \n\nThe image is a transparent PNG with an alpha channel, so that the drop shadow appears nicely over whatever else is on the page. Because Internet Explorer version 6 and below doesn\u2019t handle transparent PNGs correctly, you need to use the AlphaImageLoader technique to make the image appear correctly.\n\nnewimage = document.createElement('img');\nnewimage.src = \"http://farm3.static.flickr.com/2145/2067574980_3ddd405905_o_d.png\";\nnewimage.style.position = \"absolute\";\nnewimage.style.top = (targ.offsetTop - 73) + \"px\";\nnewimage.style.left = (targ.offsetLeft + targ.offsetWidth - 5) + \"px\";\nnewimage.style.zIndex = \"999\";\nnewimage.setAttribute(\"alt\", \"Warning: Caps Lock is on\");\nif (newimage.runtimeStyle) {\n\t// PNG transparency for IE\n\tnewimage.runtimeStyle.filter += \"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='http://farm3.static.flickr.com/2145/2067574980_3ddd405905_o_d.png',sizingMethod='scale')\";\n}\ndocument.body.appendChild(newimage);\n\nNote that the alt text on the image is also correctly set. Next, all these parts need to be pulled together. On page load, identify all the password fields on the page, and attach a keypress handler to each. (This only needs to be done for password fields because the user can see if Caps Lock is on in ordinary text fields.)\n\nvar inps = document.getElementsByTagName(\"input\");\nfor (var i=0, l=inps.length; i\n\nThe \u201ccreate an image\u201d code from above should only be run if the image is not already showing, so instead of creating a newimage object, create the image and attach it to the password field so that it can be checked for later (and not shown if it\u2019s already showing). For safety, all the code should be wrapped up in its own object, so that its functions don\u2019t collide with anyone else\u2019s functions. So, create a single object called capslock and make all the functions be named methods of the object:\n\nvar capslock = {\n\t... \n\tkeypress: function(e) {\n\t}\n\t...\n}\n\nAlso, the \u201ccreate an image\u201d code is saved into its own named function, show_warning(), and the converse \u201cremove the image\u201d code into hide_warning(). This has the advantage that developers can include the JavaScript library that has been written here, but override what actually happens with their own code, using something like:\n\n<script src=\"jscapslock.js\" type=\"text/javascript\"></script>\n<script type=\"text/javascript\">\n\tcapslock.show_warning(target) {\n\t\t// do something different here to warn the user\n\t}\n\tcapslock.hide_warning(target) {\n\t\t// hide the warning that we created in show_warning() above\n\t}\n</script>\n\nAnd that\u2019s all. Simply include the JavaScript library in your pages, override what happens on a warning if that\u2019s more appropriate for what you\u2019re doing, and that\u2019s all you need.\n\n See the script in action.", "year": "2007", "author": "Stuart Langridge", "author_slug": "stuartlangridge", "published": "2007-12-04T00:00:00+00:00", "url": "https://24ways.org/2007/capturing-caps-lock/", "topic": "code"} {"rowid": 161, "title": "Keeping JavaScript Dependencies At Bay", "contents": "As we are writing more and more complex JavaScript applications we run into issues that have hitherto (god I love that word) not been an issue. The first decision we have to make is what to do when planning our app: one big massive JS file or a lot of smaller, specialised files separated by task. \n\nPersonally, I tend to favour the latter, mainly because it allows you to work on components in parallel with other developers without lots of clashes in your version control. It also means that your application will be more lightweight as you only include components on demand.\n\nStarting with a global object\n\nThis is why it is a good plan to start your app with one single object that also becomes the namespace for the whole application, say for example myAwesomeApp:\n\nvar myAwesomeApp = {};\n\nYou can nest any necessary components into this one and also make sure that you check for dependencies like DOM support right up front.\n\nAdding the components\n\nThe other thing to add to this main object is a components object, which defines all the components that are there and their file names.\n\nvar myAwesomeApp = {\n\tcomponents :{\n\t\tformcheck:{\n\t\t\turl:'formcheck.js',\n\t\t\tloaded:false\n\t\t},\n\t\tdynamicnav:{\n\t\t\turl:'dynamicnav.js',\n\t\t\tloaded:false\n\t\t},\n\t\tgallery:{\n\t\t\turl:'gallery.js',\n\t\t\tloaded:false\n\t\t},\n\t\tlightbox:{\n\t\t\turl:'lightbox.js',\n\t\t\tloaded:false\n\t\t}\n\t}\n};\n\nTechnically you can also omit the loaded properties, but it is cleaner this way. The next thing to add is an addComponent function that can load your components on demand by adding new SCRIPT elements to the head of the documents when they are needed.\n\nvar myAwesomeApp = {\n\tcomponents :{\n\t\tformcheck:{\n\t\t\turl:'formcheck.js',\n\t\t\tloaded:false\n\t\t},\n\t\tdynamicnav:{\n\t\t\turl:'dynamicnav.js',\n\t\t\tloaded:false\n\t\t},\n\t\tgallery:{\n\t\t\turl:'gallery.js',\n\t\t\tloaded:false\n\t\t},\n\t\tlightbox:{\n\t\t\turl:'lightbox.js',\n\t\t\tloaded:false\n\t\t}\n\t},\n\taddComponent:function(component){\n\t\tvar c = this.components[component];\n\t\tif(c && c.loaded === false){\n\t\t\tvar s = document.createElement('script');\n\t\t\ts.setAttribute('type', 'text/javascript');\n\t\t\ts.setAttribute('src',c.url);\n\t\t\tdocument.getElementsByTagName('head')[0].appendChild(s);\n\t\t}\n\t}\n};\n\nThis allows you to add new components on the fly when they are not defined:\n\nif(!myAwesomeApp.components.gallery.loaded){\n\tmyAwesomeApp.addComponent('gallery');\n};\n\nVerifying that components have been loaded\n\nHowever, this is not safe as the file might not be available. To make the dynamic adding of components safer each of the components should have a callback at the end of them that notifies the main object that they indeed have been loaded:\n\nvar myAwesomeApp = {\n\tcomponents :{\n\t\tformcheck:{\n\t\t\turl:'formcheck.js',\n\t\t\tloaded:false\n\t\t},\n\t\tdynamicnav:{\n\t\t\turl:'dynamicnav.js',\n\t\t\tloaded:false\n\t\t},\n\t\tgallery:{\n\t\t\turl:'gallery.js',\n\t\t\tloaded:false\n\t\t},\n\t\tlightbox:{\n\t\t\turl:'lightbox.js',\n\t\t\tloaded:false\n\t\t}\n\t},\n\taddComponent:function(component){\n\t\tvar c = this.components[component];\n\t\tif(c && c.loaded === false){\n\t\t\tvar s = document.createElement('script');\n\t\t\ts.setAttribute('type', 'text/javascript');\n\t\t\ts.setAttribute('src',c.url);\n\t\t\tdocument.getElementsByTagName('head')[0].appendChild(s);\n\t\t}\n\t},\n\tcomponentAvailable:function(component){\n\t\tthis.components[component].loaded = true;\n\t}\n}\n\nFor example the gallery.js file should call this notification as a last line:\n\nmyAwesomeApp.gallery = function(){\n\t// [... other code ...]\n}();\nmyAwesomeApp.componentAvailable('gallery');\n\nTelling the implementers when components are available\n\nThe last thing to add (actually as a courtesy measure for debugging and implementers) is to offer a listener function that gets notified when the component has been loaded:\n\nvar myAwesomeApp = {\n\tcomponents :{\n\t\tformcheck:{\n\t\t\turl:'formcheck.js',\n\t\t\tloaded:false\n\t\t},\n\t\tdynamicnav:{\n\t\t\turl:'dynamicnav.js',\n\t\t\tloaded:false\n\t\t},\n\t\tgallery:{\n\t\t\turl:'gallery.js',\n\t\t\tloaded:false\n\t\t},\n\t\tlightbox:{\n\t\t\turl:'lightbox.js',\n\t\t\tloaded:false\n\t\t}\n\t},\n\taddComponent:function(component){\n\t\tvar c = this.components[component];\n\t\tif(c && c.loaded === false){\n\t\t\tvar s = document.createElement('script');\n\t\t\ts.setAttribute('type', 'text/javascript');\n\t\t\ts.setAttribute('src',c.url);\n\t\t\tdocument.getElementsByTagName('head')[0].appendChild(s);\n\t\t}\n\t},\n\tcomponentAvailable:function(component){\n\t\tthis.components[component].loaded = true;\n\t\tif(this.listener){\n\t\t\tthis.listener(component);\n\t\t};\n\t}\n};\n\nThis allows you to write a main listener function that acts when certain components have been loaded, for example:\n\nmyAwesomeApp.listener = function(component){\n\tif(component === 'gallery'){\n\t showGallery();\n\t}\n};\n\nExtending with other components\n\nAs the main object is public, other developers can extend the components object with own components and use the listener function to load dependent components. Say you have a bespoke component with data and labels in extra files:\n\nmyAwesomeApp.listener = function(component){\n\tif(component === 'bespokecomponent'){\n\t\tmyAwesomeApp.addComponent('bespokelabels');\n\t};\n\tif(component === 'bespokelabels'){\n\t\tmyAwesomeApp.addComponent('bespokedata');\n\t};\n\tif(component === 'bespokedata'){\n\t\tmyAwesomeApp,bespokecomponent.init();\n\t};\n};\nmyAwesomeApp.components.bespokecomponent = {\n\turl:'bespoke.js',\n\tloaded:false\n};\nmyAwesomeApp.components.bespokelabels = {\n\turl:'bespokelabels.js',\n\tloaded:false\n};\nmyAwesomeApp.components.bespokedata = {\n\turl:'bespokedata.js',\n\tloaded:false\n};\nmyAwesomeApp.addComponent('bespokecomponent');\n\nFollowing this practice you can write pretty complex apps and still have full control over what is available when. You can also extend this to allow for CSS files to be added on demand.\n\nInfluences\n\nIf you like this idea and wondered if someone already uses it, take a look at the Yahoo! User Interface library, and especially at the YAHOO_config option of the global YAHOO.js object.", "year": "2007", "author": "Christian Heilmann", "author_slug": "chrisheilmann", "published": "2007-12-18T00:00:00+00:00", "url": "https://24ways.org/2007/keeping-javascript-dependencies-at-bay/", "topic": "code"} {"rowid": 162, "title": "Conditional Love", "contents": "\u201cBrowser.\u201d The four-letter word of web design.\n\nI mean, let\u2019s face it: on the good days, when things just work in your target browsers, it\u2019s marvelous. The air smells sweeter, birds\u2019 songs sound more melodious, and both your design and your code are looking sharp.\n\nBut on the less-than-good days (which is, frankly, most of them), you\u2019re compelled to tie up all your browsers in a sack, heave them into the nearest river, and start designing all-imagemap websites. We all play favorites, after all: some will swear by Firefox, Opera fans are allegedly legion, and others still will frown upon anything less than the latest WebKit nightly.\n\nThankfully, we do have an out for those little inconsistencies that crop up when dealing with cross-browser testing: CSS patches.\n\nSpare the Rod, Hack the Browser\n\nBefore committing browsercide over some rendering bug, a designer will typically reach for a snippet of CSS fix the faulty browser. Historically referred to as \u201chacks,\u201d I prefer Dan Cederholm\u2019s more client-friendly alternative, \u201cpatches\u201d.\n\nBut whatever you call them, CSS patches all work along the same principle: supply the proper property value to the good browsers, while giving higher maintenance other browsers an incorrect value that their frustrating idiosyncratic rendering engine can understand.\n\nTraditionally, this has been done either by exploiting incomplete CSS support:\n\n#content {\n\theight: 1%;\t // Let's force hasLayout for old versions of IE.\n\tline-height: 1.6;\n\tpadding: 1em;\n}\nhtml>body #content {\n\theight: auto; // Modern browsers get a proper height value.\n}\n\nor by exploiting bugs in their rendering engine to deliver alternate style rules:\n\n#content p {\n\tfont-size: .8em;\n\t/* Hide from Mac IE5 \\*/\n\tfont-size: .9em;\n\t/* End hiding from Mac IE5 */\n}\n\nWe\u2019ve even used these exploits to serve up whole stylesheets altogether:\n\n@import url(\"core.css\");\n@media tty {\n\ti{content:\"\\\";/*\" \"*/}} @import 'windows-ie5.css'; /*\";}\n}/* */\n\nThe list goes on, and on, and on. For every browser, for every bug, there\u2019s a patch available to fix some rendering bug.\n\nBut after some time working with standards-based layouts, I\u2019ve found that CSS patches, as we\u2019ve traditionally used them, become increasingly difficult to maintain. As stylesheets are modified over the course of a site\u2019s lifetime, inline fixes we\u2019ve written may become obsolete, making them difficult to find, update, or prune out of our CSS. A good patch requires a constant gardener to ensure that it adds more than just bloat to a stylesheet, and inline patches can be very hard to weed out of a decently sized CSS file.\n\nGiving the Kids Separate Rooms\n\nSince I joined Airbag Industries earlier this year, every project we\u2019ve worked on has this in the head of its templates:\n\n<link rel=\"stylesheet\" href=\"-/css/screen/main.css\" type=\"text/css\" media=\"screen, projection\" />\n<!--[if lt IE 7]>\n<link rel=\"stylesheet\" href=\"-/css/screen/patches/win-ie-old.css\" type=\"text/css\" media=\"screen, projection\" />\n<![endif]-->\n<!--[if gte IE 7]>\n<link rel=\"stylesheet\" href=\"-/css/screen/patches/win-ie7-up.css\" type=\"text/css\" media=\"screen, projection\" />\n<![endif]-->\n\nThe first element is, simply enough, a link element that points to the project\u2019s main CSS file. No patches, no hacks: just pure, modern browser-friendly style rules. Which, nine times out of ten, will net you a design that looks like spilled eggnog in various versions of Internet Explorer.\n\nBut don\u2019t reach for the mulled wine quite yet. Immediately after, we\u2019ve got a brace of conditional comments wrapped around two other link elements. These odd-looking comments allow us to selectively serve up additional stylesheets just to the version of IE that needs them. We\u2019ve got one for IE 6 and below:\n\n<!--[if lt IE 7]>\n<link rel=\"stylesheet\" href=\"-/css/screen/patches/win-ie-old.css\" type=\"text/css\" media=\"screen, projection\" />\n<![endif]-->\n\nAnd another for IE7 and above:\n\n<!--[if gte IE 7]>\n<link rel=\"stylesheet\" href=\"-/css/screen/patches/win-ie7-up.css\" type=\"text/css\" media=\"screen, projection\" />\n<![endif]-->\n\nMicrosoft\u2019s conditional comments aren\u2019t exactly new, but they can be a valuable alternative to cooking CSS patches directly into a master stylesheet. And though they\u2019re not a W3C-approved markup structure, I think they\u2019re just brilliant because they innovate within the spec: non-IE devices will assume that the comments are just that, and ignore the markup altogether.\n\nThis does, of course, mean that there\u2019s a little extra markup in the head of our documents. But this approach can seriously cut down on the unnecessary patches served up to the browsers that don\u2019t need them. Namely, we no longer have to write rules like this in our main stylesheet:\n\n#content {\n\theight: 1%;\t// Let's force hasLayout for old versions of IE.\n\tline-height: 1.6;\n\tpadding: 1em;\n}\nhtml>body #content {\n\theight: auto;\t// Modern browsers get a proper height value.\n}\n\nRather, we can simply write an un-patched rule in our core stylesheet:\n\n#content {\n\tline-height: 1.6;\n\tpadding: 1em;\n}\n\nAnd now, our patch for older versions of IE goes in\u2014you guessed it\u2014the stylesheet for older versions of IE:\n\n#content {\n\theight: 1%;\n}\n\nThe hasLayout patch is applied, our design\u2019s repaired, and\u2014most importantly\u2014the patch is only seen by the browser that needs it. The \u201cgood\u201d browsers don\u2019t have to incur any added stylesheet weight from our IE patches, and Internet Explorer gets the conditional love it deserves.\n\nMost importantly, this \u201ccompartmentalized\u201d approach to CSS patching makes it much easier for me to patch and maintain the fixes applied to a particular browser. If I need to track down a bug for IE7, I don\u2019t need to scroll through dozens or hundreds of rules in my core stylesheet: instead, I just open the considerably slimmer IE7-specific patch file, make my edits, and move right along.\n\nEven Good Children Misbehave\n\nWhile IE may occupy the bulk of our debugging time, there\u2019s no denying that other popular, modern browsers will occasionally disagree on how certain bits of CSS should be rendered. But without something as, well, pimp as conditional comments at our disposal, how do we bring the so-called \u201cgood browsers\u201d back in line with our design?\n\nAssuming you\u2019re loving the \u201cone patch file per browser\u201d model as much as I do, there\u2019s just one alternative: JavaScript.\n\nfunction isSaf() {\n\tvar isSaf = (document.childNodes && !document.all && !navigator.taintEnabled && !navigator.accentColorName) ? true : false;\n\treturn isSaf;\n}\nfunction isOp() {\n\tvar isOp = (window.opera) ? true : false;\n\treturn isOp;\n}\n\nInstead of relying on dotcom-era tactics of parsing the browser\u2019s user-agent string, we\u2019re testing here for support for various DOM objects, whose presence or absence we can use to reasonably infer the browser we\u2019re looking at. So running the isOp() function, for example, will test for Opera\u2019s proprietary window.opera object, and thereby accurately tell you if your user\u2019s running Norway\u2019s finest browser.\n\nWith scripts such as isOp() and isSaf() in place, you can then reasonably test which browser\u2019s viewing your content, and insert additional link elements as needed.\n\nfunction loadPatches(dir) {\n\tif (document.getElementsByTagName() && document.createElement()) {\n\t\tvar head = document.getElementsByTagName(\"head\")[0];\n\t\tif (head) {\n\t\t\tvar css = new Array();\n\t\t\tif (isSaf()) {\n\t\t\t\tcss.push(\"saf.css\");\n\t\t\t} else if (isOp()) {\n\t\t\t\tcss.push(\"opera.css\");\n\t\t\t}\n\t\t\tif (css.length) {\n\t\t\t\tvar link = document.createElement(\"link\");\n\t\t\t\tlink.setAttribute(\"rel\", \"stylesheet\");\n\t\t\t\tlink.setAttribute(\"type\", \"text/css\");\n\t\t\t\tlink.setAttribute(\"media\", \"screen, projection\");\n\t\t\t\tfor (var i = 0; i < css.length; i++) {\n\t\t\t\t\tvar tag = link.cloneNode(true);\n\t\t\t\t\ttag.setAttribute(\"href\", dir + css[0]);\n\t\t\t\t\thead.appendChild(tag);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nHere, we\u2019re testing the results of isSaf() and isOp(), one after the other. For each function that returns true, then the name of a new stylesheet is added to the oh-so-cleverly named css array. Then, for each entry in css, we create a new link element, point it at our patch file, and insert it into the head of our template.\n\nFire it up using your favorite onload or DOMContentLoaded function, and you\u2019re good to go.\n\nScripteat Emptor\n\nAt this point, some of the audience\u2019s more conscientious \u2018scripters may be preparing to lob figgy pudding at this author\u2019s head. And that\u2019s perfectly understandable; relying on JavaScript to patch CSS chafes a bit against the normally clean separation we have between our pages\u2019 content, presentation, and behavior layers.\n\nAnd beyond the philosophical concerns, this approach comes with a few technical caveats attached:\n\nBrowser detection? So un-133t.\n\nBrowser detection is not something I\u2019d typically recommend. Whenever possible, a proper DOM script should check for the support of a given object or method, rather than the device with which your users view your content.\n\nIt\u2019s JavaScript, so don\u2019t count on it being available.\n\nAccording to one site, roughly four percent of Internet users don\u2019t have JavaScript enabled. Your site\u2019s stats might be higher or lower than this number, but still: don\u2019t expect that every member of your audience will see these additional stylesheets, and ensure that your content\u2019s still accessible with JS turned off.\n\nBe a constant gardener.\n\nThe sample isSaf() and isOp() functions I\u2019ve written will tell you if the user\u2019s browser is Safari or Opera. As a result, stylesheets written to patch issues in an old browser may break when later releases repair the relevant CSS bugs.\n\nYou can, of course, add logic to these simple little scripts to serve up version-specific stylesheets, but that way madness may lie. In any event, test your work vigorously, and keep testing it when new versions of the targeted browsers come out. Make sure that a patch written today doesn\u2019t become a bug tomorrow.\n\nPatching Firefox, Opera, and Safari isn\u2019t something I\u2019ve had to do frequently: still, there have been occasions where the above script\u2019s come in handy. Between conditional comments, careful CSS auditing, and some judicious JavaScript, browser-based bugs can be handled with near-surgical precision.\n\nSo pass the \u2018nog. It\u2019s patchin\u2019 time.", "year": "2007", "author": "Ethan Marcotte", "author_slug": "ethanmarcotte", "published": "2007-12-15T00:00:00+00:00", "url": "https://24ways.org/2007/conditional-love/", "topic": "code"} {"rowid": 163, "title": "Get To Grips with Slippy Maps", "contents": "Online mapping has definitely hit mainstream. Google Maps made \u2018slippy maps\u2019 popular and made it easy for any developer to quickly add a dynamic map to his or her website. You can now find maps for store locations, friends nearby, upcoming events, and embedded in blogs. \n\nIn this tutorial we\u2019ll show you how to easily add a map to your site using the Mapstraction mapping library. There are many map providers available to choose from, each with slightly different functionality, design, and terms of service. Mapstraction makes deciding which provider to use easy by allowing you to write your mapping code once, and then easily switch providers.\n\nAssemble the pieces\n\nUtilizing any of the mapping library typically consists of similar overall steps:\n\n\n\tCreate an HTML div to hold the map\n\tInclude the Javascript libraries\n\tCreate the Javascript Map element\n\tSet the initial map center and zoom level\n\tAdd markers, lines, overlays and more\n\n\nCreate the Map Div\n\nThe HTML div is where the map will actually show up on your page. It needs to have a unique id, because we\u2019ll refer to that later to actually put the map here. This also lets you have multiple maps on a page, by creating individual divs and Javascript map elements. The size of the div also sets the height and width of the map. You set the size using CSS, either inline with the element, or via a CSS reference to the element id or class. For this example, we\u2019ll use inline styling.\n\n<div id=\"map\" style=\"width: 400px; height: 400px;\"></div>\n\nInclude Javascript libraries\n\nA mapping library is like any Javascript library. You need to include the library in your page before you use the methods of that library. For our tutorial, we\u2019ll need to include at least two libraries: Mapstraction, and the mapping API(s) we want to display. Our first example we\u2019ll use the ubiquitous Google Maps library. However, you can just as easily include Yahoo, MapQuest, or any of the other supported libraries.\n\nAnother important aspect of the mapping libraries is that many of them require an API key. You will need to agree to the terms of service, and get an API key these.\n\n<script src=\"http://maps.google.com/maps?file=api&v=2&key=YOUR_KEY\" type=\"text/javascript\"></script>\n<script type=\"text/javascript\" src=\"http://mapstraction.com/src/mapstraction.js\"></script>\n\nCreate the Map\n\nGreat, we\u2019ve now put in all the pieces we need to start actually creating our map. This is as simple as creating a new Mapstraction object with the id of the HTML div we created earlier, and the name of the mapping provider we want to use for this map. \n\nWith several of the mapping libraries you will need to set the map center and zoom level before the map will appear. The map centering actually triggers the initialization of the map. \n\nvar mapstraction = new Mapstraction('map','google');\nvar myPoint = new LatLonPoint(37.404,-122.008);\nmapstraction.setCenterAndZoom(myPoint, 10);\n\nA note about zoom levels. The setCenterAndZoom function takes two parameters, the center as a LatLonPoint, and a zoom level that has been defined by mapping libraries. The current usage is for zoom level 1 to be \u201czoomed out\u201d, or view the entire earth \u2013 and increasing the zoom level as you zoom in. Typically 17 is the maximum zoom, which is about the size of a house. \n\nDifferent mapping providers have different quality of zoomed in maps over different parts of the world. This is a perfect reason why using a library like Mapstraction is very useful, because you can quickly change mapping providers to accommodate users in areas that have bad coverage with some maps. \n\nTo switch providers, you just need to include the Javascript library, and then change the second parameter in the Mapstraction creation. Or, you can call the switch method to dynamically switch the provider.\n\nSo for Yahoo Maps (demo):\n\nvar mapstraction = new Mapstraction('map','yahoo');\n\nor Microsoft Maps (demo):\n\nvar mapstraction = new Mapstraction('map','microsoft');\n\nwant a 3D globe in your browser? try FreeEarth (demo):\n\nvar mapstraction = new Mapstraction('map','freeearth');\n\nor even OpenStreetMap (free your data!) (demo):\n\nvar mapstraction = new Mapstraction('map','openstreetmap');\n\nVisit the Mapstraction multiple map demo page for an example of how easy it is to have many maps on your page, each with a different provider. \n\nAdding Markers\n\nWhile adding your first map is fun, and you can probably spend hours just sliding around, the point of adding a map to your site is usually to show the location of something. So now you want to add some markers. There are a couple of ways to add to your map.\n\nThe simplest is directly creating markers. You could either hard code this into a rather static page, or dynamically generate these using whatever tools your site is built on.\n\nvar marker = new Marker( new LatLonPoint(37.404,-122.008) );\nmarker.setInfoBubble(\"It's easy to add maps to your site\");\nmapstraction.addMarker( marker );\n\nThere is a lot more you can do with markers, including changing the icon, adding timestamps, automatically opening the bubble, or making them draggable. \n\nWhile it is straight-forward to create markers one by one, there is a much easier way to create a large set of markers. And chances are, you can make it very easy by extending some data you already are sharing: RSS. \n\nSpecifically, using GeoRSS you can easily add a large set of markers directly to a map. GeoRSS is a community built standard (like Microformats) that added geographic markup to RSS and Atom entries. It\u2019s as simple as adding <georss:point>42 -83</georss:point> to your feeds to share items via GeoRSS. Once you\u2019ve done that, you can add that feed as an \u2018overlay\u2019 to your map using the function:\n\nmapstraction.addOverlay(\"http://api.flickr.com/services/feeds/groups_pool.gne?id=322338@N20&format=rss_200&georss=1\");\n\nMapstraction also supports KML for many of the mapping providers. So it\u2019s easy to add various data sources together with your own data. Check out Mapufacture for a growing index of available GeoRSS feeds and KML documents. \n\nPlay with your new toys\n\nMapstraction offers a lot more functionality you can utilize for demonstrating a lot of geographic data on your website. It also includes geocoding and routing abstraction layers for making sure your users know where to go. You can see more on the Mapstraction website: http://mapstraction.com.", "year": "2007", "author": "Andrew Turner", "author_slug": "andrewturner", "published": "2007-12-02T00:00:00+00:00", "url": "https://24ways.org/2007/get-to-grips-with-slippy-maps/", "topic": "code"} {"rowid": 164, "title": "My Other Christmas Present Is a Definition List", "contents": "A note from the editors: readers should note that the HTML5 redefinition of definition lists has come to pass and is now \u00e0 la mode.\n \n \n \n Last year, I looked at how the markup for tag clouds was generally terrible. I thought this year I would look not at a method of marking up a common module, but instead just at a simple part of HTML and how it generally gets abused.\n\nNo, not tables. Definition lists. Ah, definition lists. Often used but rarely understood.\n\nExamining the definition of definitions\n\nTo start with, let\u2019s see what the HTML spec has to say about them.\n\n\n\tDefinition lists vary only slightly from other types of lists in that list items consist of two parts: a term and a description.\n\n\nThe canonical example of a definition list is a dictionary. Words can have multiple descriptions (even the word definition has at least five). Also, many terms can share a single definition (for example, the word colour can also be spelt color, but they have the same definition).\n\nExcellent, we can all grasp that. But it very quickly starts to fall apart. Even in the HTML specification the definition list is mis-used.\n\n\n\tAnother application of DL, for example, is for marking up dialogues, with each DT naming a speaker, and each DD containing his or her words.\n\n\nWrong. Completely and utterly wrong. This is the biggest flaw in the HTML spec, along with dropping support for the start attribute on ordered lists. \u201cWhy?\u201d, you may ask. Let me give you an example from Romeo and Juliet, act 2, scene 2.\n\n<dt>Juliet</dt>\n\t<dd>Romeo!</dd>\n<dt>Romeo</dt>\n\t<dd>My niesse?</dd>\n<dt>Juliet</dt>\n\t<dd>At what o'clock tomorrow shall I send to thee?</dd>\n<dt>Romeo</dt>\n\t<dd>At the hour of nine.</dd>\n\nNow, the problem here is that a given definition can have multiple descriptions (the DD). Really the dialog \u201cdescriptions\u201d should be rolled up under the terms, like so:\n\n<dt>Juliet</dt>\n\t<dd>Romeo!</dd>\n\t<dd>At what o'clock tomorrow shall I send to thee?</dd>\n<dt>Romeo</dt>\n\t<dd>My niesse?</dd>\n\t<dd>At the hour of nine.</dd>\n\nSuddenly the play won\u2019t make anywhere near as much sense. (If it\u2019s anything, the correct markup for a play is an ordered list of CITE and BLOCKQUOTE elements.)\n\nThis is the first part of the problem. That simple example has turned definition lists in everyone\u2019s mind from pure definitions to more along the lines of a list with pre-configured heading(s) and text(s).\n\nScreen reader, enter stage left.\n\nIn many screen readers, a simple definition list would be read out as \u201cdefinition term equals definition description\u201d. So in our play excerpt, Juliet equals Romeo! That\u2019s not right, either. But this also leads a lot of people astray with definition lists to believing that they are useful for key/value pairs.\n\nBehaviour and convention\n\nThe WHAT-WG have noticed the common mis-use of the DL, and have codified it into the new spec. In the HTML5 draft, a definition list is no longer a definition list.\n\n\n\tThe dl element introduces an unordered association list consisting of zero or more name-value groups (a description list). Each group must consist of one or more names (dt elements) followed by one or more values (dd elements).\n\n\nThey also note that the \u201cdl element is inappropriate for marking up dialogue, since dialogue is ordered\u201d. So for that example they have created a DIALOG (sic) element.\n\nStrange, then, that they keep DL as-is but instead refer to it an \u201cassociation list\u201d. They have not created a new AL element, and kept DL for the original purpose. They have chosen not to correct the usage or to create a new opportunity for increased specificity in our HTML, but to \u201cpave the cowpath\u201d of convention.\n\nHow to use a definition list\n\nGiven that everyone else is using a DL incorrectly, should we? Well, if they all jumped off a bridge, would you too? No, of course you wouldn\u2019t. We don\u2019t have HTML5 yet, so we\u2019re stuck with the existing semantics of HTML4 and XHTML1. Which means that:\n\n\n\tListing dialogue is not defining anything.\n\tListing the attributes of a piece of hardware (resolution = 1600\u00d71200) is illustrating sample values, not defining anything (however, stating what \u2018resolution\u2019 actually means in this context would be a definition).\n\tListing the cast and crew of a given movie is not defining the people involved in making movies. (Stuart Gordon may have been the director of Space Truckers, but that by no means makes him the true definition of a director.)\n\tA menu of navigation items is simply a nested ordered or unordered list of links, not a definition list.\n\tApplying styling handles to form labels and elements is not a good use for a definition list.\n\n\nAnd so on.\n\nLiving by the specification, a definition list should be used for term definitions \u2013 glossaries, lexicons and dictionaries \u2013 only.\n\nAnything else is a crime against markup.", "year": "2007", "author": "Mark Norman Francis", "author_slug": "marknormanfrancis", "published": "2007-12-05T00:00:00+00:00", "url": "https://24ways.org/2007/my-other-christmas-present-is-a-definition-list/", "topic": "code"}