{"rowid": 101, "title": "Easing The Path from Design to Development", "contents": "As a web developer, I have the pleasure of working with a lot of different designers. There has been a lot of industry discussion of late about designers and developers, focusing on how different we sometimes are and how the interface between our respective phases of a project (that is to say moving from a design phase into production) can sometimes become a battleground.\n\nI don\u2019t believe it has to be a battleground. It\u2019s actually more like being a dance partner \u2013 our steps are different, but as long as we know our own part and have a little knowledge of our partner\u2019s steps, it all goes together to form a cohesive dance. Albeit with less spandex and fewer sequins (although that may depend on the project in question).\n\nAs the process usually flows from design towards development, it\u2019s most important that designers have a little knowledge of how the site is going to be built. At the specialist web development agency I\u2019m part of, we find that designs that have been well considered from a technical perspective help to keep the project on track and on budget.\n\nBased on that experience, I\u2019ve put together my checklist of things that designers should consider before handing their work over to a developer to build.\n\nLayout\n\nOne rookie mistake made by traditionally trained designers transferring to the web is to forget a web browser is not a fixed medium. Unlike designing a magazine layout or a piece of packaging, there are lots of available options to consider. Should the layout be fluid and resize with the window, or should it be set to a fixed width? If it\u2019s fluid, which parts expand and which not? If it\u2019s fixed, should it sit in the middle of the window or to one side?\n\nIf any part of the layout is going to be flexible (get wider and narrower as required), consider how any graphics are affected. Images don\u2019t usually look good if displayed at anything other that their original size, so should they behave? If a column is going to get wider than it\u2019s shown in the Photoshop comp, it may be necessary to provide separate wider versions of any background images.\n\nText size and content volume\n\nA related issue is considering how the layout behaves with both different sizes of text and different volumes of content. Whilst text zooming rather than text resizing is becoming more commonplace as the default behaviour in browsers, it\u2019s still a fundamentally important principal of web design that we are suggesting and not dictating how something should look. Designs must allow for a little give and take in the text size, and how this affects the design needs to be taken into consideration.\n\nKeep in mind that the same font can display differently in different places and platforms. Something as simple as Times will display wider on a Mac than on Windows. However, the main impact of text resizing is the change in how much vertical space copy takes up. This is particularly important where space is limited by the design (making text bigger causes many more problems than making text smaller). Each element from headings to box-outs to navigation items and buttons needs to be able to expand at least vertically, if not horizontally as well. This may require some thought about how elements on the page may wrap onto new lines, as well as again making sure to provide extended versions of any graphical elements.\n\nSimilarly, it\u2019s rare theses days to know exactly what content you\u2019re working with when a site is designed. Many, if not most sites are designed as a series of templates for some kind of content management system, and so designs cannot be tweaked around any specific item of content. Designs must be able to cope with both much greater and much lesser volumes of content that might be thrown in at the lorem ipsum phase.\n\nParticular things to watch out for are things like headings (how do they wrap onto multiple lines) and any user-generated items like usernames. It can be very easy to forget that whilst you might expect something like a username to be 8-12 characters, if the systems powering your site allow for 255 characters they\u2019ll always be someone who\u2019ll go there. Expect them to do so.\n\nAgain, if your site is content managed or not, consider the possibility that the structure might be expanded in the future. Consider how additional items might be added to each level of navigation. Whilst it\u2019s rarely desirable to make significant changes without revisiting the site\u2019s information architecture more thoroughly, it\u2019s an inevitable fact of life that the structure needs a little bit of flexibility to change over time.\n\nInteractions with and without JavaScript\n\nA great number of sites now make good use of JavaScript to streamline the user interface and make everything just that touch more usable. Remember, though, that any developer worth their salt will start by building the interface without JavaScript, get it all working, and then layer that JavaScript on top. This is to allow for users viewing the site without JavaScript available or enabled in their browser.\n\nDesigners need to consider both states of any feature they\u2019re designing \u2013 how it looks and functions with and without JavaScript. If the feature does something fancy with Ajax, consider how the same can be achieved with basic HTML forms, links and intermediary pages. These all need to be designed, because this is how some of your users will interact with the site.\n\nLogged in and logged out states\n\nWhen designing any type of web application or site that has a membership system \u2013 that is to say users can create an account and log into the site \u2013 the design will need to consider how any element is presented in both logged in and logged out states. For some items there\u2019ll be no difference, whereas for others there may be considerable differences.\n\nShould an item be hidden completely not logged out users? Should it look different in some way? Perhaps it should look the same, but prompt the user to log in when they interact with it. If so, what form should that prompt take on and how does the user progress through the authentication process to arrive back at the task they were originally trying to complete?\n\nCouple logged in and logged out states with the possible absence of JavaScript, and every feature needs to be designed in four different states:\n\n\n\tLogged out with JavaScript available\n\tLogged in with JavaScript available\n\tLogged out without JavaScript available\n\tLogged in without JavaScript available\n\n\nFonts\n\nThere are three main causes of war in this world; religions, politics and fonts. I\u2019ve said publicly before that I believe the responsibility for this falls squarely at the feet of Adobe Photoshop. Photoshop, like a mistress at a brothel, parades a vast array of ropey, yet strangely enticing typefaces past the eyes of weak, lily-livered designers, who can\u2019t help but crumble to their curvy charms.\n\nYet, on the web, we have to be a little more restrained in our choice of typefaces. The purest solution is always to make the best use of the available fonts, but this isn\u2019t always the most desirable solution from a design point of view. There are several technical solutions such as techniques that utilise Flash (like sIFR), dynamically generated images and even canvas in newer browsers. Discuss the best approach with your developer, as every different technique has different trade-offs, and this may impact the design in other ways.\n\nMessaging\n\nAny site that has interactive elements, from a simple contact form through to fully featured online software application, involves some kind of user messaging. By this I mean the error messages when something goes wrong and the success and thank-you messages when something goes right. These typically appear as the result of an interaction, so are easy to forget and miss off a Photoshop comp.\n\nFor every form, consider what gets displayed to the user if they make a mistake or miss something out, and also what gets displayed back when the interaction is successful. What do they see and where do the go next?\n\nWith Ajax interactions, the user doesn\u2019t get any visual feedback of the site waiting for a response from the server unless you design it that way. Consider using a \u2018waiting\u2019 or \u2018in progress\u2019 spinner to give the user some visual feedback of any background processes. How should these look? How do they animate?\n\nSimilarly, also consider the big error pages like a 404. With luck, these won\u2019t often be seen, but it\u2019s at the point that they are when careful design matters the most.\n\nForm fields\n\nDepending on the visual style of your site, the look of a browser\u2019s default form fields and buttons can sometimes jar. It\u2019s understandable that many a designer wants to change the way they look. Depending on the browser in question, various things can be done to style form fields and their buttons (although it\u2019s not as flexible as most would like).\n\nA common request is to replace the default buttons with a graphical button. This is usually achievable in most cases, although it\u2019s not easy to get a consistent result across all browsers \u2013 particularly when it comes to vertical positioning and the space surrounding the button. If the layout is very precise, or if space is at a premium, it\u2019s always best to try and live with the browser\u2019s default form controls.\n\nWhichever way you go, it\u2019s important to remember that in general, each form field should have a label, and each form should have a submit button. If you find that your form breaks either of those rules, you should double check.\n\nPractical tips for handing files over\n\nThere are a couple of basic steps that a design can carry out to make sure that the developer has the best chance of implementing the design exactly as envisioned.\n\nIf working with Photoshop of Fireworks or similar comping tool, it helps to group and label layers to make it easy for a developer to see which need to be turned on and off to get to isolate parts of the page and different states of the design. Also, if you don\u2019t work in the same office as your developer (and so they can\u2019t quickly check with you), provide a PDF of each page and state so that your developer can see how each page should look aside from any confusion with quick layers are switched on or off. These also act as a handy quick reference that can be used without firing up Photoshop (which can kill both productivity and your machine).\n\nFinally, provide a colour reference showing the RGB values of all the key colours used throughout the design. Without this, the developer will end up colour-picking from the comps, and could potentially end up with different colours to those you intended. Remember, for a lot of developers, working in a tool like Photoshop is like presenting a designer with an SSH terminal into a web server. It\u2019s unfamiliar ground and easy to get things wrong. Be the expert of your own domain and help your colleagues out when they\u2019re out of their comfort zone. That goes both ways.\n\nIn conclusion\n\nWhen asked the question of how to smooth hand-over between design and development, almost everyone who has experienced this situation could come up with their own list. This one is mine, based on some of the more common experiences we have at edgeofmyseat.com. So in bullet point form, here\u2019s my checklist for handing a design over.\n\n\n\tIs the layout fixed, or fluid?\n\tDoes each element cope with expanding for larger text and more content?\n\tAre all the graphics large enough to cope with an area expanding?\n\tDoes each interactive element have a state for with and without JavaScript?\n\tDoes each element have a state for logged in and logged out users?\n\tHow are any custom fonts being displayed? (and does the developer have the font to use?)\n\tDoes each interactive element have error and success messages designed?\n\tDo all form fields have a label and each form a submit button?\n\tIs your Photoshop comp document well organised?\n\tHave you provided flat PDFs of each state?\n\tHave you provided a colour reference?\n\tAre we having fun yet?", "year": "2008", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2008-12-01T00:00:00+00:00", "url": "https://24ways.org/2008/easing-the-path-from-design-to-development/", "topic": "process"}
{"rowid": 102, "title": "Art Directing with Looking Room", "contents": "Using photographic composition techniques to start to art direct on the template-driven web.\n\nThink back to last night. There you are, settled down in front of the TV, watching your favourite soap opera, with nice hot cup of tea in hand. Did you notice \u2013 whilst engrossed in the latest love-triangle \u2013 that the cameraman has worked very hard to support your eye\u2019s natural movement on-screen? He\u2019s carefully framed individual shots to create balance.\n\nThink back to last week. There you were, sat with your mates watching the big match. Did you notice that the cameraman frames the shot to go with the direction of play? A player moving right will always be framed so that he is on the far left, with plenty of \u2018room\u2019 to run into.\n\nBoth of these cameramen use a technique called Looking Room, sometimes called Lead Room. Looking Room is the space between the subject (be it a football, or a face), and the edge of the screen. Specifically, Looking Room is the negative space on the side the subject is looking or moving. The great thing is, it\u2019s not just limited to photography, film or television; we can use it in web design too.\n\nBasic Framing\n\nBefore we get into Looking Room, and how it applies to web, we need to have a look at some basics of photographic composition.\n\nMany web sites use imagery, or photographs, to enhance the content. But even with professionally shot photographs, without a basic understanding of framing or composition, you can damage how the image is perceived. \n\nA simple, easy way to make photographs more interesting is to fill the frame. \n\nTake this rather mundane photograph of a horse:\n\n\n\nA typical point and click affair. But, we can work with this.\n\nBy closely cropping, and filling the frame, we can instantly change the mood of the shot.\n\n\n\nI\u2019ve also added Looking Room on the right of the horse. This is space that the horse would be walking into. It gives the photograph movement.\n\nSubject, Space, and Movement\n\nGenerally speaking, a portrait photograph will have a subject and space around them. Visual interest in portrait photography can come from movement; how the eye moves around the shot. To get the eye moving, the photographer modifies the space around the subject.\n\nLook at this portrait:\n\n\n\nThe photography has framed the subject on the right, allowing for whitespace, or Looking Room, in the direction the subject is looking. The framing of the subject (1), with the space to the left (2) \u2013 the Looking Room \u2013 creates movement, shown by the arrow (3).\n\n\n\nNote the subject is not framed centrally (shown by the lighter dotted line).\n\nIf the photographer had framed the subject with equal space either side, the resulting composition is static, like our horse.\n\n\n\nIf the photographer framed the subject way over on the left, as she is looking that way, the resulting whitespace on the right leads a very uncomfortable composition.\n\n\n\nThe root of this discomfort is what the framing is telling our eye to do. The subject, looking to the left, suggests to us that we should do the same. However, the Looking Room on the right is telling our eye to occupy this space. The result is a confusing back and forth.\n\nHow Looking Room applies to the web\n\nWe can apply the same theory to laying out a web page or application. Taking the three same elements \u2013 Subject, Space, and resulting Movement \u2013 we can guide a user\u2019s eye to the elements we need to. As designers, or content editors, framing photographs correctly can have a subtle but important effect on how a page is visually scanned. Take this example:\n\n\n\nThe BBC homepage uses great photography as a way of promoting content. Here, they have cropped the main photograph to guide the user\u2019s eye into the content. \n\nBy applying the same theory, the designer or content editor has applied considerable Looking Room (2) to the photograph to create balance with the overall page design, but also to create movement of the user\u2019s eye toward the content (1)\n\n\n\nIf the image was flipped horizontally. The Looking Room is now on the right. The subject of the photograph is looking off the page, drawing the user\u2019s eye away from the content. Once again, this results in a confusing back and forth as your eye fights its way over to the left of the page.\n\n\n\nA little bit of Art Direction\n\nArt Direction can be described as the act or process of managing the visual presentation of content. Art Direction is difficult to do on the web, because content and presentation are, more often than not, separated. But where there are images, and when we know the templates that those images will populate, we can go a little way to bridging the gap between content and presentation.\n\nBy understanding the value of framing and Looking Room, and the fact that it extends beyond just a good looking photograph, we can start to see photography playing more of an integral role in the communication of content. \n\nWe won\u2019t just be populating templates. We\u2019ll be art directing.\n\nPhoto credits: \n\n\n\tPortrait by Carsten Tolkmit\n\tHorse by Mike Pedroncelli", "year": "2008", "author": "Mark Boulton", "author_slug": "markboulton", "published": "2008-12-05T00:00:00+00:00", "url": "https://24ways.org/2008/art-directing-with-looking-room/", "topic": "design"}
{"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": 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
\n\nThe Google equivalent is:\n\n\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\n\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\n\t
\n\t\t\n\t\t\n\t\t\n\t\t\n\t
\n\n\n\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": 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": 106, "title": "Checking Out: Progress Meters", "contents": "It\u2019s the holiday season, so you know what that means: online shopping! When I started developing Web sites back in the 90s, many of my first clients were small local shops wanting to sell their goods online, so I developed many a checkout system. And because of slow dial-up speeds back then, informing the user about where they were in the checkout process was pretty important.\n\nEven though we\u2019re (mostly) beyond the dial-up days, informing users about where they are in a flow is still important. In usability tests at the companies I\u2019ve worked at, I\u2019ve seen time and time again how not adequately informing the user about their state can cause real frustration. This is especially true for two sets of users: mobile users and users of assistive devices, in particular, screen readers.\n\nThe progress meter is a very common design solution used to indicate to the user\u2019s state within a flow. On the design side, much effort may go in to crafting a solution that is as visually informative as possible. On the development side, however, solutions range widely. I\u2019ve checked out the checkouts at a number of sites and here\u2019s what I\u2019ve found when it comes to progress meters: they\u2019re sometimes inaccessible and often confusing or unhelpful \u2014 all because of the way in which they\u2019re coded. For those who use assistive devices or text-only browsers, there must be a better way to code the progress meter \u2014 and there is.\n\n(Note: All code samples are from live sites but have been tweaked to hide the culprits\u2019 identities.)\n\nHow not to make progress\n\nA number of sites assemble their progress meters using non- or semi-semantic markup and images with no alternate text. On text-only browsers (like my mobile phone) and to screen readers, this looks and reads like chunks of content with no context given.\n\n
\n\t\n\tShipping information\n\t\n\t\n\tPayment information\n\t\n\t\n\tPlace your order\n
\n\nIn the above example, the third state, \u201cPlace your order\u201d, is the current state. But a screen reader may not know that, and my cell phone only displays \"Shipping informationPayment informationPlace your order\". Not good.\n\nIs this progress?\n\nOther sites present the entire progress meter as a graphic, like the following:\n\n\n\nNow, I have no problem with using a graphic to render a very stylish progress meter (my sample above is probably not the most stylish example, of course, but you understand my point). What becomes important in this case is the use of appropriate alternate text to describe the image. Disappointingly, sites today have a wide range of solutions, including using no alternate text. Check out these code samples which call progress meter images.\n\n\n\nI think we can all agree that the above is bad, unless you really don\u2019t care whether or not users know where they are in a flow.\n\n\n\nThe alt text in the example above just copies all of the text found in the graphic, but it doesn\u2019t represent the status at all. So for every page in the checkout, the user sees or hears the same text. Sure, by the second or third page in the flow, the user has figured out what\u2019s going on, but she or he had to think about it. I don\u2019t think that\u2019s good.\n\n\n\nThe above probably has the best alternate text out of these examples, because the user at least understands that they\u2019re in the Checkout process, on the Place your order page. But going through the flow with alt text like this, the user doesn\u2019t know how many steps are in the flow.\n\nSemantic progress\n\nOf course, there are some sites that use an ordered list when marking up the progress meter. Hooray! Unfortunately, no text-only browser or screen reader would be able to describe the user\u2019s current state given this markup.\n\n\n\t
shipping information
\n\t
payment information
\n\t
place your order
\n\n\nWithout CSS enabled, the above is rendered as follows:\n\n\n\nProgress at last\n\nWe all know that semantic markup makes for the best foundation, so we\u2019ll start with the markup found above. In order to make the state information accessible, let\u2019s add some additional text in paragraph and span elements.\n\n
\n\t
There are three steps in this checkout process.
\n\t\n\t\t
Enter your shipping information
\n\t\t
Enter your payment information
\n\t\t
Review details and place your order
\n\t\n
\n\nAdd on some simple CSS to hide the paragraph and spans, and arrange the list items on a single line with a background image to represent the large number, and this is what you\u2019ll get:\n\n \n\tThere are three steps in this checkout process.\n\t\n\t\tEnter your shipping information\n\t\tEnter your payment information\n\t\tReview details and place your order\n\t\n \n\nTo display and describe a state as active, add the class \u201ccurrent\u201d to one of the list items. Then change the hidden content such that it better describes the state to the user.\n\n
\n\t
There are three steps in this checkout process.
\n\t\n\t\t
You are currently entering your shipping information
\n\t\t
In the next step, you will enter your payment information
\n\t\t
In the last step, you will review the details and place your order
\n\t\n
\n\nThe end result is an attractive progress meter that gives much greater semantic and contextual information.\n\n \n\tThere are three steps in this checkout process.\n\t\n\t\tYou are currently entering your shipping information\n\t\tIn the next step, you will enter your payment information\n\t\tIn the last step, you will review the details and place your order\n\t\n \n\nFor example, the above example renders in a text-only browser as follows:\n\n \n\tThere are three steps in this checkout process.\n\t\n\t\tYou are currently entering your shipping information\n\t\tIn the next step, you will enter your payment information\n\t\tIn the last step, you will review the details and place your order\n\t\n \n\nAnd the screen reader I use for testing announces the following:\n\n \n\tThere are three steps in this checkout process. List of three items. You are currently entering your shipping information. In the next step, you will enter your payment information. In the last step, you will review the details and place your order. List end.\n \n\nHere\u2019s a sample code page that summarises this approach.\n\nHappy frustration-free online shopping with this improved progress meter!", "year": "2008", "author": "Kimberly Blessing", "author_slug": "kimberlyblessing", "published": "2008-12-12T00:00:00+00:00", "url": "https://24ways.org/2008/checking-out-progress-meters/", "topic": "ux"}
{"rowid": 107, "title": "Using Google App Engine as Your Own Content Delivery Network", "contents": "Do you remember, years ago, when hosting was expensive, domain names were the province of the rich, and you hosted your web pages on Geocities? It seems odd to me now that there was a time when each and every geek didn\u2019t have his own top-level domain and super hosting setup. But as the parts became more and more affordable a man could become an outcast if he didn\u2019t have his own slightly surreal-sounding TLD.\n\nAnd so it will be in the future when people realise with surprise there was a time before affordable content delivery networks.\n\nA content delivery network, or CDN, is a system of servers spread around the world, serving files from the nearest physical location. Instead of waiting for a file to find its way from a server farm in Silicon Valley 8,000 kilometres away, I can receive it from London, Dublin, or Paris, cutting down the time I wait. The big names \u2014 Google, Yahoo, Amazon, et al \u2014 use CDNs for their sites, but they\u2019ve always been far too expensive for us mere mortals. Until now.\n\nThere\u2019s a service out there ready for you to use as your very own CDN. You have the company\u2019s blessing, you won\u2019t need to write a line of code, and \u2014 best of all \u2014 it\u2019s free. The name? Google App Engine.\n\nIn this article you\u2019ll find out how to set up a CDN on Google App Engine. You\u2019ll get the development software running on your own computer, tell App Engine what files to serve, upload them to a web site, and give everyone round the world access to them.\n\nCreating your first Google App Engine project\n\nBefore we do anything else, you\u2019ll need to download the Google App Engine software development kit (SDK). You\u2019ll need Python 2.5 too \u2014 you won\u2019t be writing any Python code but the App Engine SDK will need it to run on your computer. If you don\u2019t have Python, App Engine will install it for you (if you use Mac OS X 10.5 or a Linux-based OS you\u2019ll have Python; if you use Windows you won\u2019t).\n\nDone that? Excellent, because that\u2019s the hardest step. The rest is plain sailing.\n\nYou\u2019ll need to choose a unique \u2018application id\u2019 \u2014 nothing more than a name \u2014 for your project. Make sure it consists only of lowercase letters and numbers. For this article I\u2019ll use 24ways2008, but you can choose anything you like.\n\nOn your computer, create a folder named after your application id. This folder can be anywhere you want: your desktop, your documents folder, or wherever you usually keep your web files. Within your new folder, create a folder called assets, and within that folder create three folders called images, css, and javascript. These three folders are the ones you\u2019ll fill with files and serve from your content delivery network. You can have other folders too, if you like.\n\nThat will leave you with a folder structure like this:\n\n24ways2008/\n\t\tassets/\n\t\t\tcss/\n\t\t\timages/\n\t\t\tjavascript/\n\nNow you need to put a few files in these folders, so we can later see our CDN in action. You can put anything you want in these folders, but for this example we\u2019ll include an HTML file, a style sheet, an image, and a Javascript library.\n\nIn the top-level folder (the one I\u2019ve called 24ways2008), create a file called index.html. Fill this with any content you want. In the assets/css folder, create a file named core.css and throw in a couple of CSS rules for good measure. In the assets/images directory save any image that takes your fancy \u2014 I\u2019ve used the silver badge from the App Engine download page. Finally, to fill the JavaScript folder, add in this jQuery library file. If you\u2019ve got the time and the inclination, you can build a page that uses all these elements.\n\nSo now we should have a set of files and folders that look something like this:\n\n24ways2008/\n\t\tassets/\n\t\t\t\tindex.html\n\t\t\t\tcss/\n\t\t\t\t\t\tcore.css\n\t\t\t\timages/\n\t\t\t\t\t\tappengine-silver-120x30.gif\n\t\t\t\tjavascript/\n\t\t\t\t\t\tjquery-1.2.6.min.js\n\nWhich leaves us with one last file to create. This is the important one: it tells App Engine what to do with your files. It\u2019s named app.yaml, it sits at the top-level (inside the folder I\u2019ve named 24ways2008), and it needs to include these lines:\n\napplication: 24ways2008\nversion: 1\nruntime: python\napi_version: 1\n\nhandlers:\n- url: /\n\tstatic_files: assets/index.html\n\tupload: assets/index.html\n\n- url: /\n\tstatic_dir: assets\n\nYou need to make sure you change 24ways2008 on the first line to whatever you chose as your application id, but otherwise the content of your app.yaml file should be identical. And with that, you\u2019ve created your first App Engine project. If you want it, you can download a zip file containing my project.\n\nTesting your project\n\nAs it stands, your project is ready to be uploaded to App Engine. But we couldn\u2019t call ourselves professionals if we didn\u2019t test it, could we? So, let\u2019s put that downloaded SDK to good use and run the project from your own computer.\n\nOne of the files you\u2019ll find App Engine installed is named dev_appserver.py, a Python script used to simulate App Engine on your computer. You\u2019ll find lots of information on how to do this in the documentation on the development web server, but it boils down to running the script like so (the space and the dot at the end are important):\n\ndev_appserver.py .\n\nYou\u2019ll need to run this from the command-line: Mac users can run the Terminal application, Linux users can run their favourite shell, and Windows users will need to run it via the Command Prompt (open the Start menu, choose \u2018Run\u2026\u2019, type \u2018cmd\u2018, and click \u2018OK\u2019). Before you run the script you\u2019ll need to make sure you\u2019re in the project folder \u2014 in my case, as I saved it to my desktop I can go there by typing \n\ncd ~/Desktop/24ways2008\n\nin my Mac\u2019s Terminal app; if you\u2019re using Windows you can type \n\ncd \"C:\\Documents and Settings\\username\\Desktop\\24ways2008\"\n\nIf that\u2019s successful, you\u2019ll see a few lines of output, the last looking something like this:\n\nINFO 2008-11-22 14:35:00,830 dev_appserver_main.py] Running application 24ways2008 on port 8080: http://localhost:8080\n\nNow you can power up your favourite browser, point it to http://localhost:8080/, and you\u2019ll see the page you saved as index.html. You\u2019ll also find your CSS file at http://localhost:8080/css/core.css. In fact, anything you put inside the assets folder in the project will be accessible from this domain. You\u2019re running our own App Engine web server!\n\nNote that no-one else will be able to see your files: localhost is a special domain that you can only see from your computer \u2014 and once you stop the development server (by pressing Control\u2013C) you\u2019ll not be able to see the files in your browser until you start it again.\n\nYou might notice a new file has turned up in your project: index.yaml. App Engine creates this file when you run the development server, and it\u2019s for internal App Engine use only. If you delete it there are no ill effects, but it will reappear when you next run the development server. If you\u2019re using version control (e.g. Subversion) there\u2019s no need to keep a copy in your repository.\n\nSo you\u2019ve tested your project and you\u2019ve seen it working on your own machine; now all you need to do is upload your project and the world will be able to see your files too.\n\nUploading your project\n\nIf you don\u2019t have a Google account, create one and then sign in to App Engine. Tell Google about your new project by clicking on the \u2018Create an Application\u2019 button. Enter your application id, give the application a name, and agree to the terms and conditions. That\u2019s it. All we need do now is upload the files.\n\nOpen your Mac OS X Terminal, Windows Command Prompt, or Linux shell window again, move to the project folder, and type (again, the space and the dot at the end are important):\n\nappcfg.py update .\n\nEnter your email address and password when prompted, and let App Engine do it\u2019s thing. It\u2019ll take no more than a few seconds, but in that time App Engine will have done the equivalent of logging in to an FTP server and copying files across. It\u2019s fairly understated, but you now have your own project up and running. You can see mine at http://24ways2008.appspot.com/, and everyone can see yours at http://your-application-id.appspot.com/. Your files are being served up over Google\u2019s content delivery network, at no cost to you!\n\nBenefits of using Google App Engine\n\nThe benefits of App Engine as a CDN are obvious: your own server doesn\u2019t suck up the bandwidth, while your visitors will appreciate a faster site. But there are also less obvious benefits.\n\nFirst, once you\u2019ve set up your site, updating it is an absolute breeze. Each time you update a file (or a batch of files) you need only run appcfg.py to see the changes appear on your site. To paraphrase Joel Spolsky, a good web site must be able to be updated in a single step. Many designers and developers can\u2019t make that claim, but with App Engine, you can.\n\nApp Engine also allows multiple people to work on one application. If you want a friend to be able to upload files to your site you can let him do so without giving him usernames and passwords \u2014 all he needs is his own Google account. App Engine also gives you a log of all actions taken by collaborators, so you can see who\u2019s made updates, and when.\n\nAnother bonus is the simple version control App Engine offers. Do you remember the file named app.yaml you created a while back? The second line looked like this:\n\nversion: 1\n\nIf you change the version number to 2 (or 3, or 4, etc), App Engine will keep a copy of the last version you uploaded. If anything goes wrong with your latest version, you can tell App Engine to revert back to that last saved version. It\u2019s no proper version control system, but it could get you out of a sticky situation.\n\nOne last thing to note: if you\u2019re not happy using your-application-id.appspot.com as your domain, App Engine will quite happily use any domain you own.\n\nThe weak points of Google App Engine\n\nIn the right circumstances, App Engine can be a real boon. I run my own site using the method I\u2019ve discussed above, and I\u2019m very happy with it. But App Engine does have its disadvantages, most notably those discussed by Aral Balkan in his post \u2018Why Google App Engine is broken and what Google must do to fix it\u2018.\n\nAral found the biggest problems while using App Engine as a web application platform; I wouldn\u2019t recommend using it as such either (at least for now) but for our purposes as a CDN for static files, it\u2019s much more worthy. Still, App Engine has two shortcomings you should be aware of.\n\nThe first is that you can\u2019t host a file larger than one megabyte. If you want to use App Engine to host that 4.3MB download for your latest-and-greatest desktop software, you\u2019re out of luck. The only solution is to stick to smaller files.\n\nThe second problem is the quota system. Google\u2019s own documentation says you\u2019re allowed 650,000 requests a day and 10,000 megabytes of bandwidth in and out (20,000 megabytes in total), which should be plenty for most sites. But people have seen sites shut down temporarily for breaching quotas \u2014 in some cases after inexplicable jumps in Google\u2019s server CPU usage. Aral, who\u2019s seen it happen to his own sites, seemed genuinely frustrated by this, and if you measure your hits in the hundreds of thousands and don\u2019t want to worry about uptime, App Engine isn\u2019t for you.\n\nThat said, for most of us, App Engine offers a fantastic resource: the ability to host files on Google\u2019s own content delivery network, at no charge.\n\nConclusion\n\nIf you\u2019ve come this far, you\u2019ve seen how to create a Google App Engine project and host your own files on Google\u2019s CDN. You\u2019ve seen the great advantages App Engine offers \u2014 an excellent content delivery network, the ability to update your site with a single command, multiple authors, simple version control, and the use of your own domain \u2014 and you\u2019ve come across some of its weaknesses \u2014 most importantly the limit on file sizes and the quota system. All that\u2019s left to do is upload those applications \u2014 but not before you\u2019ve finished your Christmas shopping.", "year": "2008", "author": "Matt Riggott", "author_slug": "mattriggott", "published": "2008-12-06T00:00:00+00:00", "url": "https://24ways.org/2008/using-google-app-engine-as-your-own-cdn/", "topic": "process"}
{"rowid": 108, "title": "A Festive Type Folly", "contents": "\u2018Tis the season to be jolly, so the carol singers tell us. At 24 ways, we\u2019re keeping alive another British tradition that includes the odd faux-Greco-Roman building dotted around the British countryside, Tower Bridge built in 1894, and your Dad\u2019s Christmas jumper with the dancing reindeer motif. \u2018Tis the season of the folly!\n\n \n 24 Ways to impress your friends\n \n\nThe example is not an image, just text. You may wish to see a screenshot in Safari to compare with your own operating system and browser rendering.\n\nLike all follies this is an embellishment\u200a\u2014\u200aa bit of web typography fun. It\u2019s similar to the masthead text at my place, but it\u2019s also a hyperlink. Unlike the architectural follies of the past, no child labour was used to fund or build it, just some HTML flavoured with CSS, and a heavy dose of Times New Roman. Why Times New Roman, you ask? Well, after a few wasted hours experimenting with heaps of typefaces, seeking an elusive consistency of positioning and rendering across platforms, it proved to be the most consistent. Who\u2019d\u2018a thought? To make things more interesting, I wanted to use a traditional scale and make the whole thing elastic by using relative lengths that would react to a person\u2019s font size. So, to the meat of this festive frippery:\n\nThere are three things we rely on to create this indulgence:\n\n\n\tDescendant selectors\n\tAbsolute positioning\n\tInheritance\n\n\nHTML & Descendant Selectors\n\nThe markup for the folly might seem complex at first glance. To semantics pedants and purists it may seem outrageous. If that\u2019s you, read on at your peril! Here it is with lots of whitespace:\n\n
\n\nWhy so much markup? Well, we want to individually style many of the glyphs. By nesting the elements, we can pick out the bits we need as descendant selectors.\n\nTo retain a smidgen of semantics, the text is wrapped in
\n\n\t\n\t\t 1485 Laperri\u00e8re Avenue \n\t\t Ottawa ON K1Z 7S8 \n\t\tCanada\n\t\n\n\t\n\t\tPhone/Fax: Work: 61 2 9365 5007\n\t\tEmail: info@webdirections.org\n\t\n\n\nWe\u2019ll be using a variation on the now well established \u201csliding doors\u201d technique (if you create a CSS technique, remember it\u2019s very important to give it a memorable name or acronym, and bonus points if you get your name in there!) by Douglas Bowman, enhanced by Scott Schiller (see http://www.schillmania.com/projects/dialog/,) which will give us a design which looks like this\n\n\n\nThe technique, in a nutshell, uses background images on four elements, two at the top, and two at the bottom, to add each rounded corner.\n\nWe are going to make this design \u201cfluid\u201d in the sense that it grows and shrinks in proportion with the size of the font that the text of the element is displayed with. This is sometimes referred to as an \u201cem driven design\u201d (we\u2019ll see why in a moment).\n\nTo see how this works in practice, here\u2019s the same design with the text \u201czoomed\u201d up in size\n\n\n\nand the same design again, when we zoom the text size down\n\n\n\nBy the way, the hCard image comes from Chris Messina, and you can download it and other microformat icons from the microformats wiki.\n\nNow, with CSS3, this whole task would be considerably easier, because we can add multiple background images to an element, and border images for each edge of an element. Safari, version 1.3 up, actually supports multiple background images, but sadly, it\u2019s not supported in Firefox 1.5, or even Firefox 2.0 (let\u2019s not mention IE7 eh?). So it\u2019s probably too little supported to use now. So instead we\u2019ll use a technique that only involves CSS2, and works in pretty much any browser.\n\nVery often, developers add div or span elements as containers for these background images, and in fact, if you visit Scott Shiller\u2019s site, that\u2019s what he has done there. But if at all possible we shouldn\u2019t be adding any HTML simply for presentational purposes, even if the presentation is done via CSS. What we can do is to use the HTML we have already, as much as is possible, to add the style we want. This can take some creative thinking, but once you get the hang of this approach it becomes a more natural way of using HTML compared with simply adding divs and spans at will as hooks for style. Of course, this technique isn\u2019t always simple, and in fact sometimes simply not possible, requiring us to add just a little HTML to provide the \u201chooks\u201d for CSS.\n\nLet\u2019s go to work\n\nThe first step is to add a background image to the whole vCard element.\n\n\n\nWe make this wide enough (for example 1000 or more pixels) and tall enough that no matter how large the content of the vCard grows, it will never overflow this area. We can\u2019t simply repeat the image, because the top left corner will show when the image repeats.\n\nWe add this as the background image of the vCard element using CSS.\n\nWhile we are at it, let\u2019s give the text a sans-serif font, some color so that it will be visible, and stop the image repeating.\n\n.vcard {\n\tbackground-image: url(images/vcardfill.png);\n\tbackground-repeat: no-repeat;\n\tcolor: #666;\n\tfont-family: \"Lucida Grande\", Verdana, Helvetica, Arial, sans-serif;\n}\n\nWhich in a browser, will look something like this.\n\n\n\nNext step we need to add the top right hand corner of the hCard. In keeping with our aim of not adding HTML simply for styling purposes, we want to use the existing structure of the page where possible. Here, we\u2019ll use the paragraph of class fn and org, which is the first child element of the vcard element.\n\n
Web Directions Conference Pty Ltd
\n\nHere\u2019s our CSS for this element\n\n.fn {\n\tbackground-image: url(images/topright.png);\n\tbackground-repeat: no-repeat;\n\tbackground-position: top right;\n\tpadding-top: 2em;\n\tfont-weight: bold;\n\tfont-size: 1.1em;\n}\n\nAgain, we don\u2019t want it to repeat, but this time, we\u2019ve specified a background position for the image. This will make the background image start from the top, but its right edge will be located at the right edge of the element. I also made the font size a little bigger, and the weight bold, to differentiate it from the rest of the text in the hCard.\n\nHere\u2019s the image we are adding as the background to this element.\n\n\n\nSo, putting these two CSS statements together we get\n\n\n\nWe specified a padding-top of 2em to give some space between the content of the fn element and the edge of the fn element. Otherwise the top of the hCard image would be hard against the border. To see this in action, just remove the padding-top: 2em; declaration and preview in a browser.\n\nSo, with just two statements, we are well under way. We\u2019ve not even had to add any HTML so far. Let\u2019s turn to the bottom of the element, and add the bottom border (well, the background image which will serve as that border).\n\nNow, which element are we going to use to add this background image to?\n\nOK, here I have to admit to a little, teensie bit of cheating. If you look at the HTML of the hCard, I\u2019ve grouped the email and telephone properties into a div, with a class of telecommunications. This grouping is not strictly requred for our hCard.\n\n
\n\nNow, I chose that class name because that is what the vCard specification calls this group of properties. And typically, I do tend to group together related elements using divs when I mark up content. I find it makes the page structure more logical and readable. But strictly speaking, this isn\u2019t necessary, so you may consider it cheating. But my lesson in this would be, if you are going to add markup, try to make it as meaningful as possible.\n\nAs you have probably guessed by now, we are going to add one part of the bottom border image to this element. We\u2019re going to add this image as the background-image.\n\n\n\nAgain, it will be a very wide image, like the top left one, so that no matter how wide the element might get, the background image will still be wide enough. Now, we\u2019ll need to make this image sit in the bottom left of the element we attach it to, so we use a backgound position of left bottom (we put the horizontal position before the vertical). Here\u2019s our CSS statement for this\n\n.telecommunications {\n\tbackground-image: url(images/bottom-left.png);\n\tbackground-repeat: no-repeat;\n\tbackground-position: left bottom;\n\tmargin-bottom: 2em;\n}\n\nAnd that will look like this\n\n\n\nNot quite there, but well on the way. Time for the final piece in the puzzle.\n\nOK, I admit, I might have cheated just a little bit more in this step. But like the previous step, all valid, and (hopefully) quite justifiable markup. If we look at the HTML again, you\u2019ll find that our email address is marked up like this\n\n
\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
. 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
\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 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\n\t
\n\t...\n\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 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 is emphasis, and is for stronger emphasis. Nesting 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 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": 144, "title": "The Mobile Web, Simplified", "contents": "A note from the editors: although eye-opening in 2006, this article is no longer relevant to today\u2019s mobile web.\n \n \n \n Considering a foray into mobile web development? Following are four things you need to know before making the leap.\n\n1. 4 billion mobile subscribers expected by 2010\n\nFancy that. Coupled with the UN prediction of 6.8 billion humans by 2010, 4 billion mobile subscribers (source) is an astounding 59% of the planet. Just how many of those subscribers will have data plans and web-enabled phones is still in question, but inevitably this all means one thing for you and me: A ton of potential eyes to view our web content on a mobile device.\n\n2. Context is king\n\nYour content is of little value to users if it ignores the context in which it is viewed. Consider how you access data on your mobile device. You might be holding a bottle of water or gripping a handle on the subway/tube. You\u2019re probably seeking specific data such as directions or show times, rather than the plethora of data at your disposal via a desktop PC.\n\nThe mobile web, a phrase often used to indicate \u201caccessing the web on a mobile device\u201d, is very much a context-, content-, and component-specific environment. Expressed in terms of your potential target audience, access to web content on a mobile device is largely influenced by surrounding circumstances and conditions, information relevant to being mobile, and the feature set of the device being used. Ask yourself, What is relevant to my users and the tasks, problems, and needs they may encounter while being mobile? Answer that question and you\u2019ll be off to a great start.\n\n3. WAP 2.0 is an XHTML environment\n\nIn a nutshell, here are a few fundamental tenets of mobile internet technology:\n\n\n\tWireless Application Protocol (WAP) is the protocol for enabling mobile access to internet content.\n\tWireless Markup Language (WML) was the language of choice for WAP 1.0.\n\tNearly all devices sold today are WAP 2.0 devices.\n\tWith the introduction of WAP 2.0, XHTML Mobile Profile (XHTML-MP) became the preferred markup language.\n\tXHTML-MP will be familiar to anyone experienced with XHTML Transitional or Strict.\n\n\nSummary? The mobile web is rapidly becoming an XHTML environment, and thus you and I can apply our existing \u201cdesktop web\u201d skills to understand how to develop content for it. With WML on the decline, the learning curve is much smaller today than it was several years ago. I\u2019m generalizing things gratuitously, but the point remains: Get off yo\u2019 lazy butt and begin to take mobile seriously.\n\nI\u2019ll even pass you a few tips for getting started. First, the DOCTYPE for XHTML-MP is as follows:\n\n\n\nAs for MIME type, Open Mobile Alliance (OMA) specifies using the MIME type application/vnd.wap.xhtml+xml, but ultimately you need to ensure the server delivering your mobile content is configured properly for the MIME type you choose to use, as there are other options (see Setting up WAP Servers).\n\nOnce you\u2019ve made it to the body, the XHTML-MP markup is not unlike what you\u2019re already used to. A few resources worth skimming:\n\n\n\tDevelopers Home XHTML-MP Tutorial \u2013 An impressively replete resource for all things XHTML-MP\n\tXHTML-MP Tags List \u2013 A complete list of XHTML-MP elements and accompanying attributes\n\n\nAnd last but certainly not least, CSS. There exists WAP CSS, which is essentially a subset of CSS2 with WAP-specific extensions. For all intents and purposes, much of the CSS you\u2019re already comfortable using will be transferrable to mobile. As for including CSS in your pages, your options are the same as for desktop sites: external, embedded, and inline. Some experts will argue embedded or inline over external in favor of reducing the number of HTTP connections per page request, yet many popular mobilized sites and apps employ external linking without issue.\n\nStocking stuffers: Flickr Mobile, Fandango Mobile, and Popurls Mobile. A few sites with whom you can do the View Source song and dance for further study.\n\n4. \u201cCell phone\u201d is so DynaTAC\n\nIf you\u2019re a U.S. resident, listen up: You must rid your vocabulary of the term \u201ccell phone\u201d. We\u2019re one of the few economies on the planet to refer to a mobile phone accordingly. If you care to find yourself in any of the worthwhile mobile development circles, begin using terms more widely accepted: \u201cmobile\u201d or \u201cmobile phone\u201d or \u201chandset\u201d or \u201chandy\u201d. If you\u2019re not sure which, go for \u201cmobile\u201d. Such as, \u201cYo dog, check out my new mobile.\u201d\n\nMore importantly, however, is overcoming the mentality that access to the mobile web can be done only with a phone. Instead, \u201cdevice\u201d encourages us to think phone, handheld computer, watch, Nintendo DS, car, you name it.\n\nSimple enough?", "year": "2006", "author": "Cameron Moll", "author_slug": "cameronmoll", "published": "2006-12-19T00:00:00+00:00", "url": "https://24ways.org/2006/the-mobile-web-simplified/", "topic": "ux"}
{"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": 146, "title": "Increase Your Font Stacks With Font Matrix", "contents": "Web pages built in plain old HTML and CSS are displayed using only the fonts installed on users\u2019 computers (@font-face implementations excepted). To enable this, CSS provides the font-family property for specifying fonts in order of preference (often known as a font stack). For example:\n\nh1 {font-family: 'Egyptienne F', Cambria, Georgia, serif}\n\nSo in the above rule, headings will be displayed in Egyptienne F. If Egyptienne F is not available then Cambria will be used, failing that Georgia or the final fallback default serif font. This everyday bit of CSS will be common knowledge among all 24 ways readers.\n\nIt is also a commonly held belief that the only fonts we can rely on being installed on users\u2019 computers are the core web fonts of Arial, Times New Roman, Verdana, Georgia and friends. But is that really true?\n\nIf you look in the fonts folder of your computer, or even your Mum\u2019s computer, then you are likely to find a whole load of fonts besides the core ones. This is because many software packages automatically install extra typefaces. For example, Office 2003 installs over 100 additional fonts. Admittedly not all of these fonts are particularly refined, and not all are suitable for the Web. However they still do increase your options. \n\nThe Matrix\n\nI have put together a matrix of (western) fonts showing which are installed with Mac and Windows operating systems, which are installed with various versions of Microsoft Office, and which are installed with Adobe Creative Suite.\n\n\n\nThe matrix is available for download as an Excel file and as a CSV. There are no readily available statistics regarding the penetration of Office or Creative Suite, but you can probably take an educated guess based on your knowledge of your readers.\n\nThe idea of the matrix is that use can use it to help construct your font stack. First of all pick the font you\u2019d really like for your text \u2013 this doesn\u2019t have to be in the matrix. Then pick the generic family (serif, sans-serif, cursive, fantasy or monospace) and a font from each of the operating systems. Then pick any suitable fonts from the Office and Creative Suite lists.\n\nFor example, you may decide your headings should be in the increasingly ubiquitous Clarendon. This is a serif type face. At OS-level the most similar is arguably Georgia. Adobe CS2 comes with Century Old Style which has a similar feel. Century Schoolbook is similar too, and is installed with all versions of Office. Based on this your font stack becomes:\n\nfont-family: 'Clarendon Std', 'Century Old Style Std', 'Century Schoolbook', Georgia, serif\n\n\n\n\n\n\nNote the \u2018Std\u2019 suffix indicating a \u2018standard\u2019 OpenType file, which will normally be your best bet for more esoteric fonts.\n\nI\u2019m not suggesting the process of choosing suitable fonts is an easy one. Firstly there are nearly two hundred fonts in the matrix, so learning what each font looks like is tricky and potentially time consuming (if you haven\u2019t got all the fonts installed on a machine to hand you\u2019ll be doing a lot of Googling for previews). And it\u2019s not just as simple as choosing fonts that look similar or have related typographic backgrounds, they need to have similar metrics as well, This is especially true in terms of x-height which gives an indication of how big or small a font looks.\n\nOver to You\n\nThe main point of all this is that there are potentially more fonts to consider than is generally accepted, so branch out a little (carefully and tastefully) and bring a little variety to sites out there. If you come up with any novel font stacks based on this approach, please do blog them (tagged as per the footer) and at some point they could all be combined in one place for everyone to consider.\n\nAppendix\n\nWhat about Linux?\n\nThe only operating systems in the matrix are those from Microsoft and Apple. For completeness, Linux operating systems should be included too, although these are many and varied and very much in a minority, so I omitted them for time being. For the record, some Linux distributions come packaged with Microsoft\u2019s core fonts. Others use the Vera family, and others use the Liberation family which comprises fonts metrically identical to Times New Roman and Arial.\n\nSources\n\nThe sources of font information for the matrix are as follows:\n\n\n\tWindows XP SP2\n\tWindows Vista\n\tOffice 2003\n\tOffice 2007\n\tMac OSX Tiger\n\tMac OSX Leopard (scroll down two thirds)\n\tOffice 2004 (Mac) by inspecting my Microsoft Office 2004/Office/Fonts folder\n\tOffice 2008 (Mac) is expected to be as Office 2004 with the addition of the Vista ClearType fonts\n\tCreative Suite 2 (see pdf link in first comment)\n\tCreative Suite 3", "year": "2007", "author": "Richard Rutter", "author_slug": "richardrutter", "published": "2007-12-17T00:00:00+00:00", "url": "https://24ways.org/2007/increase-your-font-stacks-with-font-matrix/", "topic": "design"}
{"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\nui.html\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\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\ntrue\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\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\n\t\n\t\n\t
\n\n\nNow we need to wire up that button to actually add a new item to our to-do list.\n\n\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": 148, "title": "Typesetting Tables", "contents": "Tables have suffered in recent years on the web. They were used for laying out web pages. Then, following the Web Standards movement, they\u2019ve been renamed by the populous as `data tables\u2019 to ensure that we all know what they\u2019re for. There have been some great tutorials for the designing tables using CSS for presentation and focussing on the semantics in the displaying of data in the correct way. However, typesetting tables is a subtle craft that has hardly had a mention.\n\nTable design can often end up being a technical exercise. What data do we need to display? Where is the data coming from and what form will it take? When was the last time your heard someone talk about lining numerals? Or designing to the reading direction?\n\nTables are not read like sentences\n\nWhen a reader looks at, and tries to understand, tabular data, they\u2019re doing a bunch of things at the same time.\n\n\n\tGenerally, they\u2019re task based; they\u2019re looking for something.\n\tThey are reading horizontally AND vertically\n\n\nReading a table is not like reading a paragraph in a novel, and therefore shouldn\u2019t be typeset in the same way. Designing tables is information design, it\u2019s functional typography\u2014it\u2019s not a time for eye candy.\n\nTypesetting tables\n\nTypesetting great looking tables is largely an exercise in restraint. Minimal interference with the legibility of the table should be in the forefront of any designers mind.\n\nWhen I\u2019m designing tables I apply some simple rules:\n\n\n\tPlenty of negative space\n\tUse the right typeface\n\tGo easy on the background tones, unless you\u2019re giving reading direction visual emphasis\n\tDesign to the reading direction\n\n\nBy way of explanation, here are those rules as applied to the following badly typeset table.\n\nYour default table\n\nThis table is a mess. There is no consideration for the person trying to read it. Everything is too tight. The typeface is wrong. It\u2019s flat. A grim table indeed.\n\n\n\nLet\u2019s see what we can do about that.\n\nPlenty of negative space\n\nThe badly typeset table has been set with default padding. There has been little consideration for the ascenders and descenders in the type interfering with the many horizontal rules.\n\nThe first thing we do is remove most of the lines, or rules. You don\u2019t need them \u2013 the data in the rows forms its own visual rules. Now, with most of the rules removed, the ones that remain mean something; they are indicating some kind of hierarchy to the help the reader understand what the different table elements mean \u2013 in this case the column headings.\n\n\n\nNow we need to give the columns and rows more negative space. Note the framing of the column headings. I\u2019m giving them more room at the bottom. This negative space is active\u2014it\u2019s empty for a reason. The extra air in here also gives more hierarchy to the column headings.\n\n\n\nUse the right typeface\n\nThe default table is set in a serif typeface. This isn\u2019t ideal for a couple of reasons. This serif typeface has a standard set of text numerals. These dip below the baseline and are designed for using figures within text, not on their own. What you need to use is a typeface with lining numerals. These align to the baseline and are more legible when used for tables.\n\n\n\nSans serif typefaces generally have lining numerals. They are also arguably more legible when used in tables.\n\nGo easy on the background tones, unless you\u2019re giving reading direction visual emphasis \n\nWe\u2019ve all seen background tones on tables. They have their use, but my feeling is that use should be functional and not decorative.\n\nIf you have a table that is long, but only a few columns wide, then alternate row shading isn\u2019t that useful for showing the different lines of data. It\u2019s a common misconception that alternate row shading is to increase legibility on long tables. That\u2019s not the case. Shaded rows are to aid horizontal reading across multiple table columns. On wide tables they are incredibly useful for helping the reader find what they want.\n\n\n\nBackground tone can also be used to give emphasis to the reading direction. If we want to emphasis a column, that can be given a background tone.\n\n\n\nHierarchy\n\nAs I said earlier, people may be reading a table vertically, and horizontally in order to find what they want. Sometimes, especially if the table is complex, we need to give them a helping hand.\n\nVisually emphasising the hierarchy in tables can help the reader scan the data. Column headings are particularly important. Column headings are often what a reader will go to first, so we need to help them understand that the column headings are different to the stuff beneath them, and we also need to give them more visual importance. We can do this by making them bold, giving them ample negative space, or by including a thick rule above them. We can also give the row titles the same level of emphasis.\n\n\n\nIn addition to background tones, you can give emphasis to reading direction by typesetting those elements in bold. You shouldn\u2019t use italics\u2014with sans serif typefaces the difference is too subtle.\n\nSo, there you have it. A couple of simple guidelines to make your tables cleaner and more readable.", "year": "2007", "author": "Mark Boulton", "author_slug": "markboulton", "published": "2007-12-07T00:00:00+00:00", "url": "https://24ways.org/2007/typesetting-tables/", "topic": "design"}
{"rowid": 149, "title": "Underpants Over My Trousers", "contents": "With Christmas approaching faster than a speeding bullet, this is the perfect time for you to think about that last minute present to buy for the web geek in your life. If you\u2019re stuck for ideas for that special someone, forget about that svelte iPhone case carved from solid mahogany and head instead to your nearest comic-book shop and pick up a selection of comics or graphic novels. (I\u2019ll be using some of my personal favourite comic books as examples throughout). \n\nTrust me, whether your nearest and dearest has been reading comics for a while or has never peered inside this four-colour world, they\u2019ll thank-you for it.\n\nAside from indulging their superhero fantasies, comic books can provide web designers with a rich vein of inspiring ideas and material to help them create shirt button popping, trouser bursting work for the web. I know from my own personal experience, that looking at aspects of comic book design, layout and conventions and thinking about the ways that they can inform web design has taken my design work in often-unexpected directions. \n\nThere are far too many fascinating facets of comic book design that provide web designers with inspiration to cover in the time that it takes to pull your underpants over your trousers. So I\u2019m going to concentrate on one muscle bound aspect of comic design, one that will make you think differently about how you lay out the content of your pages in panels. \n\nA suitcase full of Kryptonite\n\nNow, to the uninitiated onlooker, the panels of a comic book may appear to perform a similar function to still frames from a movie. But inside the pages of a comic, panels must work harder to help the reader understand the timing of a story. It is this method for conveying narrative timing to a reader that I believe can be highly useful to designers who work on the web as timing, drama and suspense are as important in the web world as they are in worlds occupied by costumed crime fighters and superheroes.\n\nI\u2019d like you to start by closing your eyes and thinking about your own process for laying out panels of content on a page. OK, you\u2019ll actually be better off with your eyes open if you\u2019re going to carry on reading.\n\nI\u2019ll bet you a suitcase full of Kryptonite that you often, if not always, structure your page layouts, and decide on the dimensions of those panels according to either:\n\n\n\tThe base grid that you are working to\n\tThe Golden Ratio or another mathematical schema\n\n\nMore likely, I bet that you decide on the size and the number of your panels based on the amount of content that will be going into them. From today, I\u2019d like you to think about taking a different approach. This approach not only addresses horizontal and vertical space, but also adds the dimension of time to your designs.\n\nSlowing down the action\n\nA comic book panel not only acts as a container for its content but also indicates to a reader how much time passes within the panel and as a result, how much time the reader should focus their attention on that one panel. \n\nSmaller panels create swift eye movement and shorter bursts of attention. Larger panels give the perception of more time elapsing in the story and subconsciously demands that a reader devotes more time to focus on it. \n\nConcrete by Paul Chadwick (Dark Horse Comics)\n\nThis use of panel dimensions to control timing can also be useful for web designers in designing the reading/user experience. Imagine a page full of information about a product or service. You\u2019ll naturally want the reader to focus for longer on the key benefits of your offering rather than perhaps its technical specifications.\n\nNow take a look at this spread of pages from Watchmen by Alan Moore and Dave Gibbons.\n\nWatchmen by Alan Moore and Dave Gibbons (Diamond Comic Distributors 2004)\n\nThroughout this series of (originally) twelve editions, artist Dave Gibbons stuck rigidly to his 3\u00d73 panels per page design and deviated from it only for dramatic moments within the narrative. \n\nIn particular during the last few pages of chapter eleven, Gibbons adds weight to the impending doom by slowing down the action by using larger panels and forces the reader to think longer about what was coming next. The action then speeds up through twelve smaller panels until the final panel: nothing more than white space and yet one of the most iconic and thought provoking in the entire twelve book series.\n\nWatchmen by Alan Moore and Dave Gibbons (Diamond Comic Distributors 2004)\n\nOn the web it is common for clients to ask designers to fill every pixel of screen space with content, perhaps not understanding the drama that can be added by nothing more than white space.\n\nIn the final chapter, Gibbons emphasises the carnage that has taken place (unseen between chapters eleven and twelve) by presenting the reader with six full pages containing only single, large panels. \n\nWatchmen by Alan Moore and Dave Gibbons (Diamond Comic Distributors 2004)\n\nThis drama, created by the artist\u2019s use of panel dimensions to control timing, is a technique that web designers can also usefully employ when emphasising important areas of content.\n\nThink back for a moment to the home page of Apple Inc., during the launch of their iconic iPhone, where the page contained nothing more than a large image and the phrase \u201cSay hello to iPhone\u201d. Rather than fill the page with sales messages, Apple\u2019s designers allowed the space itself to tell the story and created a real sense of suspense and expectation among their readers.\n\nBorders\n\nWhereas on the web, panel borders are commonly used to add emphasis to particular areas of content, in comic books they take on a different and sometimes opposite role. \n\nIn the examples so far, borders have contained all of the action. Removing a border can have the opposite effect to what you might at first think. Rather than taking emphasis away from their content, in comics, borderless panels allow the reader\u2019s eyes to linger for longer on the content adding even stronger emphasis.\n\nConcrete by Paul Chadwick (Dark Horse Comics)\n\nThis effect is amplified when the borderless content is allowed to bleed to the edges of a page. Because the content is no longer confined, except by the edges of the page (both comic and web) the reader\u2019s eye is left to wander out into open space. \n\nConcrete by Paul Chadwick (Dark Horse Comics)\n\nThis type of open, borderless content panel can be highly useful in placing emphasis on the most important content on a page in exactly the very opposite way that we commonly employ on the web today. \n\nSo why is time an important dimension to think about when designing your web pages? On one level, we are often already concerned with the short attention spans of visitors to our pages and should work hard to allow them to quickly and easily find and read the content that both they and we think is important. Learning lessons from comic book timing can only help us improve that experience.\n\nOn another: timing, suspense and drama are already everyday parts of the web browsing experience. Will a reader see what they expect when they click from one page to the next? Or are they in for a surprise? \n\nMost importantly, I believe that the web, like comics, is about story telling: often the story of the experiences that a customer will have when they use our product or service or interact with our organisation. It is this element of story telling than can be greatly improved by learning from comics.\n\nIt is exactly this kind of learning and adapting from older, more established and at first glance unrelated media that you will find can make a real distinctive difference to the design work that you create.\n\nFill your stockings\n\nIf you\u2019re a visual designer or developer and are not a regular reader of comics, from the moment that you pick up your first title, I know that you will find them inspiring. \n\nI will be writing more, and speaking about comic design applied to the web at several (to be announced) events this coming year. I hope you\u2019ll be slipping your underpants over your trousers and joining me then. In the meantime, here is some further reading to pick up on your next visit to a comic book or regular bookshop and slip into your stockings:\n\n\n\tComics and Sequential Art by Will Eisner (Northern Light Books 2001)\n\tUnderstanding Comics: The Invisible Art by Scott McCloud (Harper Collins 1994)\n\n\nHave a happy superhero season.\n\n(I would like to thank all of the talented artists, writers and publishers whose work I have used as examples in this article and the hundreds more who inspire me every day with their tall tales and talent.)", "year": "2007", "author": "Andy Clarke", "author_slug": "andyclarke", "published": "2007-12-14T00:00:00+00:00", "url": "https://24ways.org/2007/underpants-over-my-trousers/", "topic": "design"}
{"rowid": 150, "title": "A Gift Idea For Your Users: Respect, Yo", "contents": "If, indeed, it is the thought that counts, maybe we should pledge to make more thoughtful design decisions. In addition to wowing people who use the Web sites we build with novel features, nuanced aesthetics and the new new thing, maybe we should also thread some subtle things throughout our work that let folks know: hey, I\u2019m feeling ya. We\u2019re simpatico. I hear you loud and clear.\n\nIt\u2019s not just holiday spirit that moves me to talk this way. As good as people are, we need more than the horizon of karma to overcome that invisible demon, inertia. Makers of the Web, respectful design practices aren\u2019t just the right thing, they are good for business. Even if your site is the one and only place to get experience x, y or zed, you don\u2019t rub someone\u2019s face in it. You keep it free flowing, you honor the possible back and forth of a healthy transaction, you are Johnny Appleseed with the humane design cues. You make it clear that you are in it for the long haul.\n\nA peek back:\n\n\n\nThink back to what search (and strategy) was like before Google launched a super clean page with \u201cI\u2019m Feeling Lucky\u201d button. Aggregation was the order of the day (just go back and review all the \u2018strategic alliances\u2019 that were announced daily.) Yet the GOOG comes along with this zen layout (nope, we\u2019re not going to try to make you look at one of our media properties) and a bold, brash, teleport-me-straight-to-the-first-search-result button. It could have been titled \u201cWe\u2019re Feeling Cocky\u201d. These were radical design decisions that reset how people thought about search services. Oh, you mean I can just find what I want and get on with it?\n\nIt\u2019s maybe even more impressive today, after the GOOG has figured out how to monetize attention better than anyone. \u201cI\u2019m Feeling Lucky\u201d is still there. No doubt, it costs the company millions. But by leaving a little money on the table, they keep the basic bargain they started to strike in 1997. We\u2019re going to get you where you want to go as quickly as possible.\n\nWhere are the places we might make the same kind of impact in our work? Here are a few ideas:\n\nRespect People\u2019s Time\n\nAs more services become more integrated with our lives, this will only become more important. How can you make it clear that you respect the time a user has granted you?\n\nUser-Oriented Defaults\n\nDefault design may be the psionic tool in your belt. Unseen, yet pow-er-ful. Look at your defaults. Who are they set up to benefit? Are you depending on users not checking off boxes so you can feel ok about sending them email they really don\u2019t want? Are you depending on users not checking off boxes so you tilt privacy values in ways most beneficial for your SERPs? Are you making it a little too easy for 3rd party applications to run buckwild through your system?\n\nThere\u2019s being right and then there\u2019s being awesome. Design to the spirit of the agreement and not the letter.\n\nSee this?\n\n\n\nMake sure that\u2019s really the experience you think people want. Whenever I see a service that defaults to not opting me in their newsletter just because I bought a t shirt from them, you can be sure that I trust them that much more. And they are likely to see me again.\n\nReduce, Reuse\n\nIt\u2019s likely that people using your service will have data and profile credentials elsewhere. You should really think hard about how you can let them repurpose some of that work within your system. Can you let them reduce the number of logins/passwords they have to manage by supporting OpenID? Can you let them reuse profile information from another service by slurping in (or even subscribing) to hCards? Can you give them a leg up by reusing a friends list they make available to you? (Note: please avoid the anti-pattern of inviting your user to upload all her credential data from 3rd party sites into your system.)\n\nThis is a much larger issue, and if you\u2019d like to get involved, have a look at the wiki, and dive in.\n\nMake it simple to leave\n\nOh, this drives me bonkers. Again, the more simple you make it to increase or decrease involvement in your site, or to just opt-out altogether, the better. This example from Basecamp is instructive:\n\n\n\nAt a glance, I can see what the implications are of choosing a different type of account. I can also move between account levels with one click. Finally, I can cancel the service easily. No hoop jumping. Also, it should be simple for users to take data with them or delete it.\n\nLet Them Have Fun\n\nDon\u2019t overlook opportunities for pleasure. Even the most mundane tasks can be made more enjoyable. Check out one of my favorite pieces of interaction design from this past year:\n\n\n\nHoly knob fiddling, Batman! What a great way to get people to play with preference settings: an equalizer metaphor. Those of a certain age will recall how fun it was to make patterns with your uncle\u2019s stereo EQ. I think this is a delightful way to encourage people to optimize their own experience of the news feed feature. Given the killer nature of this feature, it was important for Facebook to make it easy to fine tune.\n\nI\u2019d also point you to Flickr\u2019s Talk Like A Pirate Day Easter egg as another example of design that delights. What a huge amount of work for a one-off, totally optional way to experience the site. And what fun. And how true to its brand persona. Brill.\n\nAnti-hype\n\nDon\u2019t talk so much. Rather, ship and sample. Release code, tell the right users. See what happens. Make changes. Extend the circle a bit by showing some other folks. Repeat.\n\nThe more you hype coming features, the more you talk about what isn\u2019t yet, the more you build unrealistic expectations. Your genius can\u2019t possibly match our collective dreaming. Disappointment is inevitable. Yet, if you craft the right melody and make it simple for people to hum your tune, it will spread. Give it time. Listen.\n\nSpeak the Language of the Tribe\n\nIt\u2019s respectful to speak in a human way. Not that you have to get all zOMGWTFBBQ!!1 in your messaging. People respond when you speak to them in a way that sounds natural. Natural will, of course, vary according to context. Again, listen in and people will signal the speech that works in that group for those tasks. Reveal those cues in your interface work and you\u2019ll have powerful proof that actual people are working on your Web site.\n\nThis example of Pownce\u2018s gender selector is the kind of thing I\u2019m talking about:\n\n\n\nNow, this doesn\u2019t mean you should mimic the lingo on some cool kidz site. Your service doesn\u2019t need to have a massage when it\u2019s down. Think about what works for you and your tribe. Excellent advice here from Feedburner\u2019s Dick Costolo on finding a voice for your service. Also, Mule Design\u2019s Erika Hall has an excellent talk on improving your word fu.\n\nPass the mic, yo\n\nHere is a crazy idea: you could ask your users what they want. Maybe you could even use this input to figure out what they really want. Tools abound. Comments, wikis, forums, surveys. Embed the sexy new Get Satisfaction widget and have a dynamic FAQ running.\n\nThe point is that you make it clear to people that they have a means of shaping the service with you. And you must showcase in some way that you are listening, evaluating and taking action against some of that user input.\n\nYou get my drift. There are any number of ways we can show respect to those who gift us with their time, data, feedback, attention, evangelism, money. Big things are in the offing. I can feel the love already.", "year": "2007", "author": "Brian Oberkirch", "author_slug": "brianoberkirch", "published": "2007-12-23T00:00:00+00:00", "url": "https://24ways.org/2007/a-gift-idea-for-your-users-respect-yo/", "topic": "ux"}
{"rowid": 151, "title": "Get In Shape", "contents": "Pop quiz: what\u2019s wrong with the following navigation?\n\n\n\nMaybe nothing. But then again, maybe there\u2019s something bugging you about the way it comes together, something you can\u2019t quite put your finger on. It seems well-designed, but it also seems a little\u2026 off.\n\nThe design decisions that led to this eventual form were no doubt well-considered:\n\n\n\tClient: The top level needs to have a \u201ccurrent page\u201d status indicator of some sort.\n\tDesigner: How about a white tab?\n\tClient: Great! The second level needs to show up underneath the first level though\u2026\n\tDesigner: Okay, but that white tab I just added makes it hard to visually connect the bottom nav to the top.\n\tClient: Too late, we\u2019ve seen the white tab and we love it. Try and make it work.\n\tDesigner: Right. So I placed the second level in its own box.\n\tClient: Hmm. They seem too separated. I can\u2019t tell that the yellow nav is the second level of the first.\n\tDesigner: How about an indicator arrow?\n\tClient: Brilliant!\n\n\nThe problem is that the end result feels awkward and forced. During the design process, little decisions were made that ultimately affect the overall shape of the navigation. What started out as a neatly contained rounded rectangle ended up as an ambiguous double shape that looks funny, though it\u2019s often hard to pinpoint precisely why.\n\nThe Shape of Things\n\nWell the why in this case is because seemingly unrelated elements in a design still end up visually interacting. Adding a new item to a page impacts everything surrounding it. In this navigation example, we\u2019re looking at two individual objects that are close enough to each other that they form a relationship; if we reduce them to strictly their outlines, it\u2019s a little easier to see that this particular combination registers oddly.\n\n\n\nThe two shapes float with nothing really grounding them. If they were connected, perhaps it would be a different story. The white tab divides the top shape in half, leaving a gap in the middle of it. There\u2019s very little balance in this pairing because the overall shape of the navigation wasn\u2019t considered during the design process.\n\nHere\u2019s another example: Gmail. Great email client, but did you ever closely look at what\u2019s going on in that left hand navigation? The continuous blue bar around the message area spills out into the navigation. If we remove all text, we\u2019re left with this odd configuration:\n\n\n\nThough the reasoning for anchoring the navigation highlight against the message area might be sound, the result is an irregular shape that doesn\u2019t correspond with anything in reality. You may never consciously notice it, but once you do it\u2019s hard to miss. One other example courtesy of last.fm:\n\n\n\nThe two header areas are the same shade of pink so they appear to be closely connected. When reduced to their outlines it\u2019s easy to see that this combination is off-balance: the edges don\u2019t align, the sharp corners of the top shape aren\u2019t consistent with the rounded corners of the bottom, and the part jutting out on the right of the bottom one seems fairly random. The result is a duo of oddly mis-matched shapes.\n\nDesign Strategies\n\nOur minds tend to pick out familiar patterns. A clever designer can exploit this by creating references in his or her work to shapes and combinations with which viewers are already familiar. There are a few simple ideas that can be employed to help you achieve this: consistency, balance, and completion.\n\nConsistency\n\nA fairly simple way to unify the various disparate shapes on a page is by designing them with a certain amount of internal consistency. You don\u2019t need to apply an identical size, colour, border, or corner treatment to every single shape; devolving a design into boring repetition isn\u2019t what we\u2019re after here. But it certainly doesn\u2019t hurt to apply a set of common rules to most shapes within your work.\n\n\n\nConsider purevolume and its multiple rounded-corner panels. From the bottom of the site\u2019s main navigation to the grey \u201cExtras\u201d panels halfway down the page (shown above), multiple shapes use a common border radius for unity. Different colours, different sizes, different content, but the consistent outlines create a strong sense of similarity. Not that every shape on the site follows this rule; they break the pattern right at the top with a darker sharp-cornered header, and again with the thumbnails below. But the design remains unified, nonetheless.\n\nBalance\n\nArguably the biggest problem with the last.fm example earlier is one of balance. The area poking out of the bottom shape created a fairly obvious imbalance for no apparent reason. The right hand side is visually emphasized due to the greater area of pink coverage, but with the white gap left beside it, the emphasis seems unwarranted. It\u2019s possible to create tension in your design by mismatching shapes and throwing off the balance, but when that happens unintentionally it can look like a mistake.\n\n\n\nAbove are a few examples of design elements in balanced and unbalanced configurations. The examples in the top row are undeniably more pleasing to the eye than those in the bottom row. If these were fleshed out into full designs, those derived from the templates in the top row would naturally result in stronger work.\n\nTake a look at the header on 9Rules for a study in well-considered balance. On the left you\u2019ll see a couple of paragraphs of text, on the right you have floating navigational items, and both flank the site\u2019s logo. This unusual layout combines multiple design elements that look nothing alike, and places them together in a way that anchors each so that no one weighs down the header.\n\nCompletion\n\nAnd finally we come to the idea of completion. Shapes don\u2019t necessarily need hard outlines to be read visually as shapes, which can be exploited for various purposes. Notice how Zend\u2019s mid-page \u201cBusiness Topics\u201d and \u201cNews\u201d items (below) fade out to the right and bottom, but the placement of two of these side-by-side creates an impression of two panels rather than three disparate floating columns. By allowing the viewer\u2019s eye to complete the shapes, they\u2019ve lightened up the design of the page and removed inessential lines. In a busy design this technique could prove quite handy.\n\n\n\nAlong the same lines, the individual shapes within your design may also be combined visually to form outlines of larger shapes. The differently-coloured header and main content/sidebar shapes on Veerle\u2019s blog come together to form a single central panel, further emphasized by the slight drop shadow to the right.\n\nImplementation\n\nStudying how shape can be used effectively in design is simply a starting point. As with all things design-related, there are no hard and fast rules here; ultimately you may choose to bring these principles into your work more often, or break them for effect. But understanding how shapes interact within a page, and how that effect is ultimately perceived by viewers, is a key design principle you can use to impress your friends.", "year": "2007", "author": "Dave Shea", "author_slug": "daveshea", "published": "2007-12-16T00:00:00+00:00", "url": "https://24ways.org/2007/get-in-shape/", "topic": "design"}
{"rowid": 152, "title": "CSS for Accessibility", "contents": "CSS is magical stuff. In the right hands, it can transform the plainest of (well-structured) documents into a visual feast. But it\u2019s not all fur coat and nae knickers (as my granny used to say). Here are some simple ways you can use CSS to improve the usability and accessibility of your site. \n\nEven better, no sexy visuals will be harmed by the use of these techniques. Promise.\n\nNae knickers\n\nThis is less of an accessibility tip, and more of a reminder to check that you\u2019ve got your body background colour specified.\n\nIf you\u2019re sitting there wondering why I\u2019m mentioning this, because it\u2019s a really basic thing, then you might be as surprised as I was to discover that from a sample of over 200 sites checked last year, 35% of UK local authority websites were missing their body background colour.\n\nForgetting to specify your body background colour can lead to embarrassing gaps in coverage, which are not only unsightly, but can prevent your users reading the text on your site if they use a different operating system colour scheme.\n\nAll it needs is the following line to be added to your CSS file:\n\nbody {background-color: #fff;}\n\nIf you pair it with \n\ncolor: #000;\n\n\u2026 you\u2019ll be assured of maintaining contrast for any areas you inadvertently forget to specify, no matter what colour scheme your user needs or prefers.\n\nEven better, if you\u2019ve got standard reset CSS you use, make sure that default colours for background and text are specified in it, so you\u2019ll never be caught with your pants down. At the very least, you\u2019ll have a white background and black text that\u2019ll prompt you to change them to your chosen colours.\n\nElbow room\n\nPaying attention to your typography is important, but it\u2019s not just about making it look nice. \n\nCareful use of the line-height property can make your text more readable, which helps everyone, but is particularly helpful for those with dyslexia, who use screen magnification or simply find it uncomfortable to read lots of text online. \n\nWhen lines of text are too close together, it can cause the eye to skip down lines when reading, making it difficult to keep track of what you\u2019re reading across. \n\nSo, a bit of room is good.\n\nThat said, when lines of text are too far apart, it can be just as bad, because the eye has to jump to find the next line. That not only breaks up the reading rhythm, but can make it much more difficult for those using Screen Magnification (especially at high levels of magnification) to find the beginning of the next line which follows on from the end of the line they\u2019ve just read.\n\nUsing a line height of between 1.2 and 1.6 times normal can improve readability, and using unit-less line heights help take care of any pesky browser calculation problems.\n\nFor example: \n\np {\n\tfont-family: \"Lucida Grande\", Lucida, Verdana, Helvetica, sans-serif;\n\tfont-size: 1em;\n\tline-height: 1.3;\n}\n\nor if you want to use the shorthand version:\n\np {\n\tfont: 1em/1.3 \"Lucida Grande\", Lucida, Verdana, Helvetica, sans-serif;\n}\n\nView some examples of different line-heights, based on default text size of 100%/1em.\n\nFurther reading on Unitless line-heights from Eric Meyer.\n\nTransformers: Initial case in disguise\n\nNobody wants to shout at their users, but there are some occasions when you might legitimately want to use uppercase on your site.\n\nAvoid screen-reader pronunciation weirdness (where, for example, CONTACT US would be read out as Contact U S, which is not the same thing \u2013 unless you really are offering your users the chance to contact the United States) caused by using uppercase by using title case for your text and using the often neglected text-transform property to fake uppercase.\n\nFor example:\n\n.uppercase {\n\ttext-transform: uppercase\n} \n\nDon\u2019t overdo it though, as uppercase text is harder to read than normal text, not to mention the whole SHOUTING thing.\n\nLinky love\n\nWhen it comes to accessibility, keyboard only users (which includes those who use voice recognition software) who can see just fine are often forgotten about in favour of screen reader users.\n\nThis Christmas, share the accessibility love and light up those links so all of your users can easily find their way around your site.\n\nThe link outline\n\nAKA: the focus ring, or that dotted box that goes around links to show users where they are on the site.\n\nThe techniques below are intended to supplement this, not take the place of it. You may think it\u2019s ugly and want to get rid of it, especially since you\u2019re going to the effort of tarting up your links.\n\nDon\u2019t. \n\nJust don\u2019t.\n\nThe non-underlined underline\n\nIf you listen to Jacob Nielsen, every link on your site should be underlined so users know it\u2019s a link.\n\nYou might disagree with him on this (I know I do), but if you are choosing to go with underlined links, in whatever state, then remove the default underline and replacing it with a border that\u2019s a couple of pixels away from the text. \n\nThe underline is still there, but it\u2019s no longer cutting off the bottom of letters with descenders (e.g., g and y) which makes it easier to read.\n\nThis is illustrated in Examples 1 and 2.\n\nYou can modify the three lines of code below to suit your own colour and border style preferences, and add it to whichever link state you like.\n\ntext-decoration: none;\nborder-bottom: 1px #000 solid;\npadding-bottom: 2px;\n\nStanding out from the crowd\n\nWhatever way you choose to do it, you should be making sure your links stand out from the crowd of normal text which surrounds them when in their default state, and especially in their hover or focus states.\n\nA good way of doing this is to reverse the colours when on hover or focus.\n\nWell-focused\n\nEveryone knows that you can use the :hover pseudo class to change the look of a link when you mouse over it, but, somewhat ironically, people who can see and use a mouse are the group who least need this extra visual clue, since the cursor handily (sorry) changes from an arrow to a hand.\n\nSo spare a thought for the non-pointing device users that visit your site and take the time to duplicate that hover look by using the :focus pseudo class.\n\nOf course, the internets being what they are, it\u2019s not quite that simple, and predictably, Internet Explorer is the culprit once more with it\u2019s frustrating lack of support for :focus. Instead it applies the :active pseudo class whenever an anchor has focus.\n\nWhat this means in practice is that if you want to make your links change on focus as well as on hover, you need to specify focus, hover and active.\n\nEven better, since the look and feel necessarily has to be the same for the last three states, you can combine them into one rule.\n\nSo if you wanted to do a simple reverse of colours for a link, and put it together with the non-underline underlines from before, the code might look like this:\n\na:link {\n\tbackground: #fff;\n\tcolor: #000;\n\tfont-weight: bold;\n\ttext-decoration: none; \n\tborder-bottom: 1px #000 solid; \n\tpadding-bottom: 2px;\n}\na:visited {\n\tbackground: #fff;\n\tcolor: #800080;\n\tfont-weight: bold;\n\ttext-decoration: none; \n\tborder-bottom: 1px #000 solid; \n\tpadding-bottom: 2px;\n}\na:focus, a:hover, a:active {\n\tbackground: #000;\n\tcolor: #fff;\n\tfont-weight: bold;\n\ttext-decoration: none; \n\tborder-bottom: 1px #000 solid; \n\tpadding-bottom: 2px;\n}\n\nExample 3 shows what this looks like in practice.\n\nLocation, Location, Location\n\nTo take this example to it\u2019s natural conclusion, you can add an id of current (or something similar) in appropriate places in your navigation, specify a full set of link styles for current, and have a navigation which, at a glance, lets users know which page or section they\u2019re currently in.\n\nExample navigation using location indicators.\n\nand the source code\n\nConclusion\n\nAll the examples here are intended to illustrate the concepts, and should not be taken as the absolute best way to format links or style navigation bars \u2013 that\u2019s up to you and whatever visual design you\u2019re using at the time.\n\nThey\u2019re also not the only things you should be doing to make your site accessible. \n\nAbove all, remember that accessibility is for life, not just for Christmas.", "year": "2007", "author": "Ann McMeekin", "author_slug": "annmcmeekin", "published": "2007-12-13T00:00:00+00:00", "url": "https://24ways.org/2007/css-for-accessibility/", "topic": "design"}
{"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 ' + pretty_num(total)\n\t\t+ ' 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 %s 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%s 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": 154, "title": "Diagnostic Styling", "contents": "We\u2019re all used to using CSS to make our designs live and breathe, but there\u2019s another way to use CSS: to find out where our markup might be choking on missing accessibility features, targetless links, and just plain missing content. \n\nNote: the techniques discussed here mostly work in Firefox, Safari, and Opera, but not Internet Explorer. I\u2019ll explain why that\u2019s not really a problem near the end of the article \u2014 and no, the reason is not \u201ceveryone should just ignore IE anyway\u201d.\n\nBasic Diagnostics\n\nTo pick a simple example, suppose you want to call out all holdover font and center elements in a site. Simple: you just add the following to your styles.\n\nfont, center {outline: 5px solid red;}\n\nYou could take it further and add in a nice lime background or some such, but big thick red outlines should suffice. Now you\u2019ll be able to see the offenders wherever as you move through the site. (Of course, if you do this on your public server, everyone else will see the outlines too. So this is probably best done on a development server or local copy of the site.)\n\nNot everyone may be familiar with outlines, which were introduced in CSS2, so a word on those before we move on. Outlines are much like borders, except outlines don\u2019t affect layout. Eh? Here\u2019s a comparison.\n\n\n\nOn the left, you have a border. On the right, an outline. The border takes up layout space, pushing other content around and generally being a nuisance. The outline, on the other hand, just draws into quietly into place. In most current browsers, it will overdraw any content already onscreen, and will be overdrawn by any content placed later \u2014 which is why it overlaps the images above it, and is overlapped by those below it.\n\nOkay, so we can outline deprecated elements like font and center. Is that all? Oh no.\n\nAttribution\n\nLet\u2019s suppose you also want to find any instances of inline style \u2014 that is, use of the style attribute on elements in the markup. This is generally discouraged (outside of HTML e-mails, which I\u2019m not going to get anywhere near), as it\u2019s just another side of the same coin of using font: baking the presentation into the document structure instead of putting it somewhere more manageable. So:\n\n*[style], font, center {outline: 5px solid red;}\n\nAdding that attribute selector to the rule\u2019s grouped selector means that we\u2019ll now be outlining any element with a style attribute.\n\nThere\u2019s a lot more that attribute selectors will let use diagnose. For example, we can highlight any images that have empty alt or title text.\n\nimg[alt=\"\"] {border: 3px dotted red;}\nimg[title=\"\"] {outline: 3px dotted fuchsia;}\n\nNow, you may wonder why one of these rules calls for a border, and the other for an outline. That\u2019s because I want them to \u201cadd together\u201d \u2014 that is, if I have an image which possesses both alt and title, and the values of both are empty, then I want it to be doubly marked.\n\n\n\nSee how the middle image there has both red and fuchsia dots running around it? (And am I the only one who sorely misses the actual circular dots drawn by IE5/Mac?) That\u2019s due to its markup, which we can see here in a fragment showing the whole table row.\n\n
\n
empty title
\n
\n
\n
\n
\n\nRight, that\u2019s all well and good, but it misses a rather more serious situation: the selector img[alt=\"\"] won\u2019t match an img element that doesn\u2019t even have an alt attribute. How to tackle this problem?\n\nNot a Problem\n\nWell, if you want to select something based on a negative, you need a negative selector.\n\nimg:not([alt]) {border: 5px solid red;}\n\nThis is really quite a break from the rest of CSS selection, which is all positive: \u201cselect anything that has these characteristics\u201d. With :not(), we have the ability to say (in supporting browsers) \u201cselect anything that hasn\u2019t these characteristics\u201d. In the above example, only img elements that do not have an alt attribute will be selected. So we expand our list of image-related rules to read:\n\nimg[alt=\"\"] {border: 3px dotted red;}\nimg[title=\"\"] {outline: 3px dotted fuchsia;}\nimg:not([alt]) {border: 5px solid red;}\nimg:not([title]) {outline: 5px solid fuchsia;}\n\nWith the following results:\n\n\n\nWe could expand this general idea to pick up tables who lack a summary, or have an empty summary attribute.\n\ntable[summary=\"\"] {outline: 3px dotted red;}\ntable:not([summary]) {outline: 5px solid red;}\n\nWhen it comes to selecting header cells that lack the proper scope, however, we have a trickier situation. Finding headers with no scope attribute is easy enough, but what about those that have a scope attribute with an incorrect value?\n\nIn this case, we actually need to pull an on-off maneuver. This has us setting all th elements to have a highlight style, and then turn it off for the elements that meet our criteria.\n\nth {border: 2px solid red;}\nth[scope=\"col\"], th[scope=\"row\"] {border: none;}\n\nThis was necessary because of the way CSS selectors work. For example, consider this:\n\nth:not([scope=\"col\"]), th:not([scope=\"row\"]) {border: 2px solid red;}\n\nThat would select\u2026all th elements, regardless of their attrributes. That\u2019s because every th element doesn\u2019t have a scope of col, doesn\u2019t have a scope of row, or doesn\u2019t have either. There\u2019s no escaping this selector o\u2019 doom!\n\nThis limitation arises because :not() is limited to containing a single \u201cthing\u201d within its parentheses. You can\u2019t, for example, say \u201cselect all elements except those that are images which descend from list items\u201d. Reportedly, this limitation was imposed to make browser implementation of :not() easier.\n\nStill, we can make good use of :not() in the service of further diagnosing. Calling out links in trouble is a breeze:\n\na[href]:not([title]) {border: 5px solid red;}\na[title=\"\"] {outline: 3px dotted red;}\na[href=\"#\"] {background: lime;}\na[href=\"\"] {background: fuchsia;}\n\n\n\nHere we have a set that will call our attention to links missing title information, as well as links that have no valid target, whether through a missing URL or a JavaScript-driven page where there are no link fallbacks in the case of missing or disabled JavaScript (href=\"#\").\n\nAnd What About IE?\n\nAs I said at the beginning, much of what I covered here doesn\u2019t work in Internet Explorer, most particularly :not() and outline. (Oh, so basically everything? -Ed.)\n\nI can\u2019t do much about the latter. For the former, however, it\u2019s possible to hack your way around the problem by doing some layered on-off stuff. For example, for images, you replace the previously-shown rules with the following:\n\nimg {border: 5px solid red;}\nimg[alt][title] {border-width: 0;}\nimg[alt] {border-color: fuchsia;}\nimg[alt], img[title] {border-style: double;}\nimg[alt=\"\"][title],\nimg[alt][title=\"\"] {border-width: 3px;}\nimg[alt=\"\"][title=\"\"] {border-style: dotted;}\n\nIt won\u2019t have exactly the same set of effects, given the inability to use both borders and outlines, but will still highlight troublesome images.\n\n\n\nIt\u2019s also the case that IE6 and earlier lack support for even attribute selectors, whereas IE7 added pretty much all the attribute selector types there are, so the previous code block won\u2019t have any effect previous to IE7.\n\nIn a broader sense, though, these kinds of styles probably aren\u2019t going to be used in the wild, as it were. Diagnostic styles are something only you see as you work on a site, so you can make sure to use a browser that supports outlines and :not() when you\u2019re diagnosing. The fact that IE users won\u2019t see these styles is irrelevant since users of any browser probably won\u2019t be seeing these styles.\n\nPersonally, I always develop in Firefox anyway, thanks to its ability to become a full-featured IDE through the addition of extensions like Firebug and the Web Developer Toolbar.\n\n\nYeah, About That\u2026\n\nIt\u2019s true that much of what I describe in this article is available in the WDT. I feel there are two advantages to writing your own set of diagnostic styles.\n\n\n\tWhen you write your own styles, you can define exactly what the visual results will be, and how they will interact. The WDT doesn\u2019t let you make its outlines thicker or change their colors.\n\tYou can combine a bunch of diagnostics into a single set of rules and add it to your site\u2019s style sheet during the diagnostic portion, thus ensuring they persist as you surf around. This can be done in the WDT, but it isn\u2019t as easy (and, at least for me, not as reliable).\n\n\nIt\u2019s also true that a markup validator will catch many of the errors I mentioned, such as missing alt and summary attributes. For some, that\u2019s sufficient. But it won\u2019t catch everything diagnostic styles can, like empty alt values or untargeted links, which are perfectly valid, syntactically speaking.\n\n\nDiagnosis Complete?\n\nI hope this has been a fun look at the concept of diagnostic styling as well as a quick introduction into possibly new concepts like :not() and outlines. This isn\u2019t all there is to say, of course: there is plenty more that could be added to a diagnostic style sheet. And everyone\u2019s diagnostics will be different, tuned to meet each person\u2019s unique situation.\n\nMostly, though, I hope this small exploration triggers some creative thinking about the use of CSS to do more than just lay out pages and colorize text. Given the familiarity we acquire with CSS, it only makes sense to use it wherever it might be useful, and setting up visible diagnostic flags is just one more place for it to help us.", "year": "2007", "author": "Eric Meyer", "author_slug": "ericmeyer", "published": "2007-12-20T00:00:00+00:00", "url": "https://24ways.org/2007/diagnostic-styling/", "topic": "process"}
{"rowid": 155, "title": "Minification: A Christmas Diet", "contents": "The festive season is generally more about gorging ourselves than staying thin but we\u2019re going to change all that with a quick introduction to minification.\n\nPerformance has been a hot topic this last year. We\u2019re building more complex sites and applications but at the same time trying to make then load faster and behave more responsively. What is a discerning web developer to do?\n\nMinification is the process of make something smaller, in the case of web site performance we\u2019re talking about reducing the size of files we send to the browser. The primary front-end components of any website are HTML, CSS, Javascript and a sprinkling of images. Let\u2019s find some tools to trim the fat and speed up our sites.\n\nFor those that want to play along at home you can download the various utilities for Mac or Windows. You\u2019ll want to be familiar with running apps on the command line too.\n\nHTMLTidy\n\nHTMLTidy optimises and strips white space from HTML documents. It also has a pretty good go at correcting any invalid markup while it\u2019s at it.\n\ntidy -m page.html\n\nCSSTidy\n\nCSSTidy takes your CSS file, optimises individual rules (for instance transforming padding-top: 10px; padding-bottom: 10px; to padding: 10px 0;) and strips unneeded white space.\n\ncsstidy style.css style-min.css\n\nJSMin\n\nJSMin takes your javascript and makes it more compact. With more and more websites using javascript to power (progressive) enhancements this can be a real bandwidth hog. Look out for pre-minified versions of libraries and frameworks too.\n\njsmin script-min.js\n\nRemember to run JSLint before you run JSMin to catch some common problems.\n\nOptiPNG\n\nImages can be a real bandwidth hog and making all of them smaller with OptiPNG should speed up your site.\n\noptipng image.png\n\nAll of these tools have an often bewildering array of options and generally good documentation included as part of the package. A little experimentation will get you even more bang for your buck.\n\nFor larger projects you likely won\u2019t want to be manually minifying all your files. The best approach here is to integrate these tools into your build process and have your live website come out the other side smaller than it went in.\n\nYou can also do things on the server to speed things up; GZIP compression for instance or compilation of resources to reduce the number of HTTP requests. If you\u2019re interested in performance a good starting point is the Exceptional Performance section on the Yahoo Developer Network and remember to install the YSlow Firebug extension while you\u2019re at it.", "year": "2007", "author": "Gareth Rushgrove", "author_slug": "garethrushgrove", "published": "2007-12-06T00:00:00+00:00", "url": "https://24ways.org/2007/minification-a-christmas-diet/", "topic": "process"}
{"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": 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 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\n\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": 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": 159, "title": "How Media Studies Can Massage Your Message", "contents": "A young web designer once told his teacher \u2018just get to the meat already.\u2019 He was frustrated with what he called the \u2018history lessons and name-dropping\u2019 aspects of his formal college course. He just wanted to learn how to build Web sites, not examine the reasons why.\n\nTechnique and theory are both integrated and necessary portions of a strong education. The student\u2019s perspective has direct value, but also holds a distinct sorrow: Knowing the how without the why creates a serious problem. Without these surrounding insights we cannot tap into the influence of the history and evolved knowledge that came before. We cannot properly analyze, criticize, evaluate and innovate beyond the scope of technique.\n\nHistory holds the key to transcending former mistakes. Philosophy encourages us to look at different points of view. Studying media and social history empowers us as Web workers by bringing together myriad aspects of humanity in direct relation to the environment of society and technology. Having an understanding of media, communities, communication arts as well as logic, language and computer savvy are all core skills of the best of web designers in today\u2019s medium.\n\nControlling the Message\n\n\n\t\u2018The computer can\u2019t tell you the emotional story. It can give you the exact mathematical design, but what\u2019s missing is the eyebrows.\u2019 \u2013 Frank Zappa\n\n\nMedia is meant to express an idea. The great media theorist Marshall McLuhan suggests that not only is media interesting because it\u2019s about the expression of ideas, but that the media itself actually shapes the way a given idea is perceived. This is what McLuhan meant when he uttered those famous words: \u2018The medium is the message.\u2019\n\nIf instead of actually serving a steak to a vegetarian friend, what might a painting of the steak mean instead? Or a sculpture of a cow? Depending upon the form of media in question, the message is altered.\n\nFigure 1\n\nMust we know the history of cows to appreciate the steak on our plate? Perhaps not, but if we begin to examine how that meat came to be on the plate, the social, cultural and ideological associations of that cow, we begin to understand the complexity of both medium and message. A piece of steak on my plate makes me happy. A vegetarian friend from India might disagree and even find that that serving her a steak was very insensitive.\n\nTakeaway: Getting the message right involves understanding that message in order to direct it to your audience accordingly.\n\nA Separate Piece\n\nIf we revisit the student who only wants technique, while he might become extremely adept at the rendering of an idea, without an understanding of the medium, how is he to have greater control over how that idea is perceived? Ultimately, his creativity is limited and his perspective narrowed, and the teacher has done her student a disservice without challenging him, particularly in a scholastic environment, to think in liberal, creative and ultimately innovative terms.\n\nFor many years, web pundits including myself have promoted the idea of separation as a core concept within creating effective front-end media for the Web. By this, we\u2019ve meant literal separation of the technologies and documents: Markup for content; CSS for presentation; DOM Scripting for behavior. While the message of separation was an important part of understanding and teaching best practices for manageable, scalable sites, that separation is really just a separation of pieces, not of entire disciplines.\n\nFor in fact, the medium of the Web is an integrated one. That means each part of the desired message must be supported by the media silos within a given site. The visual designer must study the color, space, shape and placement of visual objects (including type) into a meaningful expression. The underlying markup is ideally written as semantically as possible, promote the meaning of the content it describes. Any interaction and functionality must make the process of the medium support, not take away from, the meaning of the site or Web application. \n\nExamination: The Glass Bead Game\n\nFigure 2\n\nFigure 2 shows two screenshots of CoreWave\u2019s historic \u2018Glass Bead Game.\u2019 Fashioned after Herman Hesse\u2019s novel of the same name, the game was an exploration of how ideas are connected to other ideas via multiple forms of media. It was created for the Web in 1996 using server-side randomization with .htmlx files in order to allow players to see how random associations are in fact not random at all.\n\nTakeaway: We can use the medium itself to explore creative ideas, to link us from one idea to the next, and to help us better express those ideas to our audiences.\n\nComputers and Human Interaction\n\nSince our medium involves computers and human interaction, it does us well to look to foundations of computers and reason. Not long ago I was chatting with Jared Spool on IM about this and that, and he asked me \u2018So how do you feel about that?\u2019 This caused me no end of laughter and I instantly quipped back \u2018It\u2019s okay by me ELIZA.\u2019 We both enjoyed the joke, but then I tried to share it with another dare I say younger colleague, and the reference was lost.\n\nRaise your hand if you got the reference! Some of you will, but many people who come to the Web medium do not get the benefit of such historical references because we are not formally educated in them. Joseph Weizenbaum created the ELIZA program, which emulates a Rogerian Therapist, in 1966. It was an early study of computers and natural human language. I was a little over 2 years old, how about you?\n\nConversation with Eliza\n\nThere are fortunately a number of ELIZA emulators on the Web. I found one at http://www.chayden.net/eliza/Eliza.html that actually contains the source code (in Java) that makes up the ELIZA script.\n\nFigure 3 shows a screen shot of the interaction. ELIZA first welcomes me, says \u2018Hello, How do you do. Please state your problem\u2019 and we continue in a short loop of conversation, the computer using cues from my answers to create new questions and leading fragments of conversation.\n\nFigure 3\n\nAlbeit a very limited demonstration of how humans could interact with a computer in 1966, it\u2019s amusing to play with now and compare it to something as richly interactive as the Microsoft Surface (Figure 4). Here, we see clear Lucite blocks that display projected video. Each side of the block has a different view of the video, so not only does one have to match up the images as they are moving, but do so in the proper directionality.\n\nFigure 4\n\nTakeway: the better we know our environment, the more we can alter it to emulate, expand and even supersede our message.\n\nLeveraging Holiday Cheer\n\nSince most of us at least have a few days off for the holidays now that Christmas is upon us, now\u2019s a perfect time to reflect on ones\u2019 environment and examine the messages within it. Convince your spouse to find you a few audio books for stocking stuffers. Find interactive games to play with your kids and observe them, and yourself, during the interaction. Pour a nice egg-nog and sit down with a copy of Marshall McLuhan\u2019s \u2018The Medium is the Massage.\u2019 Leverage that holiday cheer and here\u2019s to a prosperous, interactive new year.", "year": "2007", "author": "Molly Holzschlag", "author_slug": "mollyholzschlag", "published": "2007-12-22T00:00:00+00:00", "url": "https://24ways.org/2007/how-media-studies-can-massage-your-message/", "topic": "ux"}
{"rowid": 160, "title": "Tracking Christmas Cheer with Google Charts", "contents": "A note from the editors: Since this article was written Google has retired the Charts API.\n \n \n \n Let\u2019s get something out in the open: I love statistics. As an informatician I can\u2019t get enough graphs, charts, and numbers. So you can imagine when Google released their Charts API I thought Christmas had come early. I immediately began to draw up graphs for the holiday season using the new API; and using my new found chart-making skills I\u2019ll show you what you can and can\u2019t do with Google Charts.\n\nMummy, it\u2019s my first chart\n\nThe Google Charts API allows you to send data to Google; in return they give you back a nicely-rendered graph. All the hard work is done on Google\u2019s servers \u2014 you need only reference an image in your HTML. You pass along the data \u2014 the numbers for the charts, axis labels, and so on \u2014 in the query string of the image\u2019s URL. If you want to add charts to your blog or web site, there\u2019s probably no quicker way to get started.\n\nHere\u2019s a simple example: if we add the following line to an HTML page:\n\n\n\nThen we\u2019ll see the line graph in Figure 1 appear in our page. That graph is hosted on Google\u2019s own server1: http://chart.apis.google.com/.\n\nFigure 1: A simple example of a line graph created with Google Charts.\n\nIf you look at the URL used in the example you\u2019ll notice we\u2019re passing some parameters along in the query string (the bit after the question mark). The query string looks like this:\n\ncht=lc&chs=200x125&chd=s:ZreelPuevfgznf2008\n\nIt\u2019s contains everything Google Charts needs to draw the graph. There are three parameters in the query string:\n\n\n\tcht; this specifies the type of chart Google Charts will generate (in this case, lc is a line chart).\n\tchs, the value of which is 200x125; this defines the chart\u2019s size (200 pixels wide by 125 pixels high).\n\tchd, the value of which is s:ZreelPuevfgznf2008; this is the actual chart data, which we\u2019ll discuss in more detail later.\n\n\nThese three parameters are the minimum you need to send to Google Charts in order to create a chart. There are lots more parameters you can send too (giving you more choice over how a chart is displayed), but you have to include at least these three before a chart can be created. Using these three parameters you can create pie charts, scatter plots, Venn diagrams, bar charts (and more) up to 1,000 pixels wide or 1,000 pixels high (but no more than 300,000 pixels in total).\n\nChristmas pie\n\nAfter I discovered the option to create a pie chart I instantly thought of graphing all the types of food and beverages that I\u2019ll consume at this year\u2019s Christmas feast. I can represent each item as a percentage of all the food on a pie chart (just thinking about that makes me hungry).\n\nBy changing the value of the cht parameter in the image\u2019s query string I can change the chart type from a line chart to a pie chart. Google Charts offers two different types of pie chart: a fancy three-dimensional version and a two-dimensional overhead version. I want to stick with the latter, so I need to change cht=lc to cht=p (the p telling Google Charts to create a pie chart; if you want the three-dimensional version, use cht=p3). As a pie chart is circular I also need to adjust the size of the chart to make it square. Finally, it would be nice to add a title to the graph. I can do this by adding the optional parameter, chtt, to the end of the image URL. I end up with the chart you see in Figure 2.\n\nFigure 2: Pie chart with a title.\n\nTo add this chart to your own page, you include the following (notice that you can\u2019t include spaces in URLs, so you need to encode them as plus-signs.):\n\n\n\nOk, that\u2019s great, but there are still two things I want to do before I can call this pie chart complete. First I want to label each slice of the pie. And second I want to include the proper data (at the moment the slices are meaningless). If 2007 is anything like 2006, the break down will be roughly as follows:\n\n\n\t\t\n\t\t\tEgg nog\n\t\t\t10%\n\t\t\n\t\t\n\t\t\tChristmas Ham\n\t\t\t20%\n\t\t\n\t\t\n\t\t\tMilk (not including egg nog)\n\t\t\t8%\n\t\t\n\t\t\n\t\t\tCookies\n\t\t\t25%\n\t\t\n\t\t\n\t\t\tRoasted Chestnuts\n\t\t\t5%\n\t\t\n\t\t\n\t\t\tChocolate\n\t\t\t3%\n\t\t\n\t\t\n\t\t\tVarious Other Beverages\n\t\t\t15%\n\t\t\n\t\t\n\t\t\tVarious Other Foods\n\t\t\t9%\n\t\t\n\t\t\n\t\t\tSnacks\n\t\t\t5%\n\t\t\n\n\nI have nine categories of food and drink to be tracked, so I need nine slice labels. To add these to the chart, I use the chl parameter. All nine labels are sent in one value; I use the vertical-pipe character, |, to separate them. So I need to append the following to the query string:\n\nchl=Egg+nog|Christmas+Ham|Milk+(not+including+egg+nog)|Cookies|Roast+Chestnuts|Chocolate|Various+Other+Beverages|Various+Other+Foods|Snacks\n\nNext I need to add the corresponding percentage values to the chart labels. Encoding the chart data is the trickiest part of the Google Charts API \u2014 but by no means complicated. There are three different ways to encode your data on a chart. As I\u2019m only dealing with small numbers, I\u2019m going to use what Google calls simple encoding.\n\nSimple encoding offers a sixty-two value spectrum in which to represent data. Remember the mandatory option, chd, from the first example? The value for this is split into two parts: the type of encoding and the graph data itself. These two parts are separated with a colon. To use simple encoding, the first character of the chd option must be a lower case s. Follow this with a colon and everything after it is considered data for the graph.\n\nIn simple encoding, you have sixty-two values to represent your data. These values are lowercase and uppercase letters from the Latin alphabet (fifty-two characters in total) and the digits 0 to 9. Each letter of the alphabet represents a single number: A equals 0, B equals 1, and so on up to Z, which equals 25; a equals 26, b equals 27, and so on up to z, which equals 51. The ten digits represent the numbers 52 to 61: 0 equals 52, 1 equals 53, and 9 equals 61.\n\nIn the previous two examples we used the string ZreelPuevfgznf2008 as our chart data; the Z is equal to 25, the r is equal to 42, the e is equal to 30, and so on. I want to encode the percentage values 10, 20, 8, 25, 5, 3, 15, 9 and 5, so in simple encoding I would use the string KUIZFDPJF.\n\nIf you think figuring this out for each chart may make your head explode, don\u2019t worry: help is out there.\n\nDo you remember I said I needed to change the image dimensions to be square, to accommodate the pie chart? Well now I\u2019m including labels I need even more room. And as I\u2019m in a Christmassy mood I\u2019m going to add some festive colours too.\n\nThe optional chco parameter is used to change the chart color. You set this using the same hexadecimal (\u201chex\u201d) notation found in CSS. So let\u2019s make our pie chart green by adding chco=00AF33 (don\u2019t start it with a hash character as in CSS) to the image URL. If we only specify one hex colour for the pie chart Google Charts will use shades of that colour for each of the slices. To choose your own colours, pass a comma separated list of colours. The \u201cMilk\u201d and \u201cCookies\u201d slices were consumed together, so we can make those two slices more of a redish colour. I\u2019ll use shades of green for the other slices. My chco parameter now looks like this:\n\nchco=00AF33,4BB74C,EE2C2C,CC3232,33FF33,66FF66,9AFF9A,C1FFC1,CCFFCC.\n\nAfter all this, I\u2019m left with the following URL:\n\nhttp://chart.apis.google.com/chart?chco=00AF33,4BB74C,EE2C2C,CC3232,33FF33,66FF66,9AFF9A,C1FFC1,CCFFCC&chl=Egg+nog|Christmas+Ham|Milk+(not+including+egg+nog)|Cookies|Roast+Chestnuts|Chocolate|Various+Other+Beverages|Various+Other+Foods|Snacks&chtt=Food+and+Drink+Consumed+Christmas+2007&cht=p&chs=600x300&chd=s:KUIZFDPJF\n\nWhat does that give us? I\u2019m glad you asked. I have the rather beautiful 600-pixel wide pie chart you see in Figure 3.\n\nFigure 3: A Christmassy pie chart with labels.\n\nBut I don\u2019t like pie charts\n\nThe pie chart was invented by the Scottish polymath William Playfair in 1801. But not everyone is as excited by pie charts as wee Billy, so if you\u2019re an anti-pie-chartist, what can you do?\n\nYou can easily reuse the same data but display it as a bar graph in a snap. The first thing we need to do is change the value of the cht parameter from p to bhg. This creates a horizontal bar graph (you can request a vertical bar graph using bvg). The data and labels all remain the same, but we need to decide where the labels will appear. I\u2019ll talk more about how to do all this in the next section. \n\nIn Figure 4 you\u2019ll see the newly-converted bar graph. The URL for the graph is:\n\nhttp://chart.apis.google.com/chart?cht=bhg&chs=600x300&chd=s:KUIZFDPJF&chxt=x,y&chtt=Food+and+Drink+Consumed+Christmas+2007&chxl=1:|Egg+nog|Christmas+Ham|Milk+(not+including+egg+nog)|Cookies|Roast+Chestnuts|Chocolate|Various+Other+Beverages|Various+Other+Foods|Snacks&chco=00AF33\n\nFigure 4: The pie chart from Figure 3 represented as a bar chart.\n\nTwo lines, one graph\n\nPie charts and bar charts are interesting, but what if I want to compare last year\u2019s Christmas cheer with this year\u2019s? That sounds like I\u2019ll need two lines on one graph.\n\nThe code is much the same as the previous examples; the most obvious difference is I need to set up the chart as a line graph. Creating some dummy values for the required parameters, I end up with:\n\n\n\nThe chs=800x300 sets the dimensions of the new chart, while cht=lxy describes the type of chart we are using (in this case a line chart with x and y co-ordinates). For the chart data I\u2019m going to demostrate a different encoding, text encoding. To use this I start the value of the chd parameter with \u201ct:\u201d instead of \u201cs:\u201d, and follow it with a list of x coordinates, a vertical pipe, |, and a list of y coordinates. Given the URL above, Google Charts will render the chart shown in Figure 5.\n\nFigure 5: A simple line graph with x and y co-ordinates.\n\nTo make this graph a little more pleasing to the eye, I can add much the same as I did to the pie chart. I\u2019ll add a chart title. Maybe something like \u201cProjected Christmas Cheer for 2007\u201d. Just as before I would add a chtt parameter to the image URL:\n\n&chtt=Projected+Christmas+Cheer+for+2007\n\nNext, let\u2019s add some labels on the y axis to represent a scale from 0 to 100. On the x axis let\u2019s label for the most important days of December. To do this I need to use the chart axis type parameter, chxt. This allows us to specify the axes and associate some labels with them. As I\u2019m only interested in the y-axis (to the left of the chart) and the x-axis (below the chart), we add chxt=x,y to our image URL.\n\nNow I need my label data. This is slightly more tricky because I want the data evenly spaced without labelling every item. The parameter for labels is chxl, the chart axis label. You match a label to an axis by using a number. So 0:Label1 is the zero index of chxt \u2014 in this case the x-axis. 1:Label2 is the first index of chxt \u2014 the y-axis. The order of these parameters or labels doesn\u2019t matter as long as you associate them to their chxt correctly.\n\nThe next thing to know about chxl is that you can add an empty label. Labels are separated by vertical pipe; if you don\u2019t put any text in a label, you just leave the two vertical pipes empty (\u201c||\u201d) and Google Charts will allocate space but no label.\n\nFor our vertical y axis, we want to label only 50% and 100% on the graph and plot them in their respective places. Since the y-axis is the second item, 1: (remember to start counting at zero), we add ten spaces to our image URL, chxl=1:||||||50|||||100 This will output the 50 halfway and the 100 at the top; all the other spaces will be empty.\n\nWe can do the same thing to get specific dates along the x-axis as well. Let\u2019s add the 1st of December, St. Nick\u2019s Day (the 6th), Christmas Day, Boxing Day (a holiday common in the UK and the Commonwealth, on the 26th), and the final day of the month, the 31st. Since this is the x-axis I\u2019ll use 0: as a reference in the chxt parameter tell Google Charts which axis to label. In full, the chxl parameter now looks like:\n\nchxl=1:||||||50|||||100|0:|Dec+1st|||||6th||||10th|||||15th|||||20th|||||25th|26th|||||Dec+31st\n\nThat\u2019s pretty.\n\nBefore we begin to graph our data, I\u2019ll do one last thing: add some grid lines to the chart so to better connect the data to the labels. The parameter for this is chg, short for chart grid lines. The parameter takes four comma-separated arguments. The first is the x-axis spacing for the grid. I have thirty-one days, so I need thirty vertical lines. The chart is 100% wide, so 3.33 (100 divided by 30) is the required spacing.\n\nAs for the y-axis: the axis goes up to 100% but we probably only need to have a horizontal line every 10%, so the required spacing is 10 (100 divided by 10). That is the second argument.\n\nThe last two arguments control the dash-style of the grid-lines. The first number is the length of the line dash and the second is the space between the dashes. So 6,3 would mean a six-unit dash with a three-unit space. I like a ratio of 1,3 but you can change this as you wish. Now that I have the four arguments, the chg parameter looks like:\n\nchg=3.333,10,1,3\n\nIf I add that to the chart URL I end up with:\n\nhttp://chart.apis.google.com/chart?chs=800x300&cht=lxy&chd=t:0,100|0,100&chtt=Projected+Christmas+Cheer+for+2007&chxt=x,y&chxl=0:|Dec+1st|||||6th|||||||||||||||||||25th|26th|||||Dec+31st|1:||||||50|||||100&chg=3.3333,10,1,3\n\nWhich results in the chart shown in Figure 6.\n\nFigure 6: Chart ready to receive the Christmas cheer values.\n\nReal data\n\nNow the chart is ready I can add historical data from 2006 and current data from 2007.\n\nHaving a look at last year\u2019s cheer levels we find some highs and lows through-out the month:\n\n\n\t\t\n\t\t\tDec 1st\n\t\t\tAdvent starts; life is good\n\t\t\t30%\n\t\t\n\t\t\n\t\t\tDec 6th\n\t\t\tSt. Nick\u2019s Day, awake to find good things in my shoes\n\t\t\t45%\n\t\t\n\t\t\n\t\t\tDec 8th\n\t\t\tWent Christmas carolling, nearly froze\n\t\t\t20%\n\t\t\n\t\t\n\t\t\tDec 10th\n\t\t\tChristmas party at work, very nice dinner\n\t\t\t50%\n\t\t\n\t\t\n\t\t\tDec 18th\n\t\t\tPanic Christmas shopping, hate rude people\n\t\t\t15%\n\t\t\n\t\t\n\t\t\tDec 23rd\n\t\t\tOff Work, home eating holiday food\n\t\t\t80%\n\t\t\n\t\t\n\t\t\tDec 25th\n\t\t\tOpened presents, good year, but got socks again from Grandma\n\t\t\t60%\n\t\t\n\t\t\n\t\t\tDec 26th\n\t\t\tBoxing Day; we\u2019re off and no one knows why\n\t\t\t70%\n\t\t\n\t\t\n\t\t\tDec 28th\n\t\t\tThird day of left overs\n\t\t\t40%\n\t\t\n\t\t\n\t\t\tDec 29th\n\t\t\tProcured some fireworks for new years\n\t\t\t55%\n\t\t\n\t\t\n\t\t\tDec 31st\n\t\t\tNew Year\u2019s Eve\n\t\t\t80%\n\t\t\n\n\nSince I\u2019m plotting data for 2006 and 2007 on the same graph I\u2019ll need two different colours \u2014 one for each year\u2019s line \u2014 and a key to denote what each colour represents. The key is controlled by the chdl (chart data legend) parameter. Again, each part of the parameter is separated by a vertical pipe, so for two labels I\u2019ll use chdl=2006|2007. I also want to colour-code them, so I\u2019ll need to add the chco as I did for the pie chart. I want a red line and a green line, so I\u2019ll use chco=458B00,CD2626 and add this to the image URL.\n\nLet\u2019s begin to plot the 2006 data on the Chart, replacing our dummy data of chd=t:0,100|0,100 with the correct information. The chd works by first listing all the x coordinates (each separated by a comma), then a vertical pipe, and then all the y coordinates (also comma-separated). The chart is 100% wide, so I need to convert the days into a percentage of the month.\n\nThe 1st of December is 0 and the 31st is 100. Everything else is somewhere in between. Our formula is:\n\n(d \u2013 1) \u00d7 100 \u00f7 (31 \u2013 1)\n\nWhere d is the day of the month. The formula states that each day will be printed every 3.333 units; so the 6th of December will be printed at 16.665 units. I can repeat the process for the other dates listed to get the following x coordinates: 0,16.7,23.3,33.3,60,76.7,83.3,86.7,93.3,96.7. The y axis coordinates are easy because our scale is 100%, just like our rating, so we can simply copy them across as 30,45,20,50,15,80,60,70,40,55,80. This gives us a final chd value of:\n\nchd=t:0,16.7,23.3,33.3,60,76.7,83.3,86.7,93.3,96.7,100|30,45,20,50,15,80,60,70,40,55,80\n\nOnto 2007: I can put the data for the month so far to see how we are trending.\n\n\n\t\t\n\t\t\tDec 1st\n\t\t\tChristmas shopping finished already\n\t\t\t50%\n\t\t\n\t\t\n\t\t\tDec 4th\n\t\t\tComputer hard disk drive crashed (not Christmas related accident, but put me in a bad mood)\n\t\t\t10%\n\t\t\n\t\t\n\t\t\tDec 6th\n\t\t\tMissed St. Nick\u2019s Day completely due to travelling\n\t\t\t30%\n\t\t\n\t\t\n\t\t\tDec 9th\n\t\t\tDinner with friends before they travel\n\t\t\t55%\n\t\t\n\t\t\n\t\t\tDec 11th\n\t\t\t24ways article goes live\n\t\t\t60%\n\t\t\n\n\nUsing the same system we did for 2006, I can take the five data points and plot them on the chart. The new x axis values will be 0,10,16.7,26.7 and the new y axis 50,10,30,65. We incorporate those into the image URL by appending these values onto the chd parameter we already have, which then becomes:\n\nchd=t:0,16.7,23.3,33.3,60,76.7,83.3,86.7,93.3,96.7,100|30,45,20,50,15,80,60,70,40,55,80|0,10,16.7,26.7,33.3|50,10,30,55,60\n\nPassing this to Google Charts results in Figure 7.\n\nhttp://chart.apis.google.com/chart?chs=800x300&cht=lxy&chd=t:0,100|0,100&chtt=Projected+Christmas+Cheer+for+2007&chxt=x,y&chxl=0:|Dec+1st|||||6th|||||||||||||||||||25th|26th|||||Dec+31st|1:||||||50|||||100&chg=3.3333,10,1,3&chd=t:0,16.7,23.3,33.3,60,76.7,83.3,86.7,93.3,96.7,100|30,45,20,50,15,80,60,70,40,55,80|0,10,16.7,26.7,33.3|50,10,30,55,60&chco=458B00,CD2626&chdl=2006|2007\n\nFigure 7: Projected Christmas cheer for 2006 and 2007.\n\nDid someone mention Edward Tufte?\n\nGoogle Charts are a robust set of chart types that you can create easily and freely using their API. As you can see, you can graph just about anything you want using the line graph, bar charts, scatter plots, venn diagrams and pie charts. One type of chart conspicuously missing from the API is sparklines. Sparklines were proposed by Edward Tufte as \u201csmall, high resolution graphics embedded in a context of words, numbers, images\u201d. They can be extremely useful, but can you create them in Google Charts?\n\nThe answer is: \u201cYes, but it\u2019s an undocumented feature\u201d. (The usual disclaimer about undocumented features applies.)\n\nIf we take our original line graph example, and change the value of the cht parameter from lc (line chart) to lfi (financial line chart) the axis-lines are removed. This allows you to make a chart \u2014 a sparkline \u2014 small enough to fit into a sentence. Google uses the lfi type all throughout the their financial site, but it\u2019s not yet part of the official API.\n\n\n\t\t\n\t\t\tMerryChristmas\n\t\t\t\n\t\t\thttp://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:MerryChristmas\n\t\t\n\t\t\n\t\t\t24ways\n\t\t\t\n\t\t\thttp://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:24ways&chco=999999\n\t\t\n\t\t\n\t\t\tHappyHolidays\n\t\t\t\n\t\t\thttp://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:HappyHolidays&chco=ff0000\n\t\t\n\t\t\n\t\t\tHappyNewYear\n\t\t\t\n\t\t\thttp://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:HappyNewYear&chco=0000ff\n\t\t\n\n\nSummary\n\nThe new Google Charts API is a powerful method for creating charts and graphs of all types. If you apply a little bit of technical skill you can create pie charts, bar graphs, and even sparklines as and when you need them. Now you\u2019ve finished ready the article I hope you waste no more time: go forth and chart!\n\nFurther reading\n\n\n\tGoogle Charts API\n\tMore on Google Charts\n\tHow to handle negative numbers\n\t12 Days of Christmas Pie Chart\n\n\n1 In order to remain within the 50,000 requests a day limit the Google Charts API imposes, chart images on this page have been cached and are being served from our own servers. But the URLs work \u2013 try them!", "year": "2007", "author": "Brian Suda", "author_slug": "briansuda", "published": "2007-12-11T00:00:00+00:00", "url": "https://24ways.org/2007/tracking-christmas-cheer-with-google-charts/", "topic": "ux"}
{"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\n\n\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\n\nAnd another for IE7 and above:\n\n\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\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\n\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 42 -83 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
Juliet
\n\t
Romeo!
\n
Romeo
\n\t
My niesse?
\n
Juliet
\n\t
At what o'clock tomorrow shall I send to thee?
\n
Romeo
\n\t
At the hour of nine.
\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
Juliet
\n\t
Romeo!
\n\t
At what o'clock tomorrow shall I send to thee?
\n
Romeo
\n\t
My niesse?
\n\t
At the hour of nine.
\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"}
{"rowid": 165, "title": "Transparent PNGs in Internet Explorer 6", "contents": "Newer breeds of browser such as Firefox and Safari have offered support for PNG images with full alpha channel transparency for a few years. With the use of hacks, support has been available in Internet Explorer 5.5 and 6, but the hacks are non-ideal and have been tricky to use. With IE7 winning masses of users from earlier versions over the last year, full PNG alpha-channel transparency is becoming more of a reality for day-to-day use.\n\nHowever, there are still numbers of IE6 users out there who we can\u2019t leave out in the cold this Christmas, so in this article I\u2019m going to look what we can do to support IE6 users whilst taking full advantage of transparency for the majority of a site\u2019s visitors.\n\nSo what\u2019s alpha channel transparency?\n\nCast your minds back to the Ghost of Christmas Past, the humble GIF. Images in GIF format offer transparency, but that transparency is either on or off for any given pixel. Each pixel\u2019s either fully transparent, or a solid colour. In GIF, transparency is effectively just a special colour you can chose for a pixel.\n\nThe PNG format tackles the problem rather differently. As well as having any colour you chose, each pixel also carries a separate channel of information detailing how transparent it is. This alpha channel enables a pixel to be fully transparent, fully opaque, or critically, any step in between.\n\nThis enables designers to produce images that can have, for example, soft edges without any of the \u2018halo effect\u2019 traditionally associated with GIF transparency. If you\u2019ve ever worked on a site that has different colour schemes and therefore requires multiple versions of each graphic against a different colour, you\u2019ll immediately see the benefit. \n\nWhat\u2019s perhaps more interesting than that, however, is the extra creative freedom this gives designers in creating beautiful sites that can remain web-like in their ability to adjust, scale and reflow.\n\nThe Internet Explorer problem\n\nUp until IE7, there has been no fully native support for PNG alpha channel transparency in Internet Explorer. However, since IE5.5 there has been some support in the form of proprietary filter called the AlphaImageLoader. Internet Explorer filters can be applied directly in your CSS (for both inline and background images), or by setting the same CSS property with JavaScript. \n\nCSS:\n\nimg {\n\tfilter: progid:DXImageTransform.Microsoft.AlphaImageLoader(...);\n}\n\nJavaScript:\n\nimg.style.filter = \"progid:DXImageTransform.Microsoft.AlphaImageLoader(...)\";\n\nThat may sound like a problem solved, but all is not as it may appear. Firstly, as you may realise, there\u2019s no CSS property called filter in the W3C CSS spec. It\u2019s a proprietary extension added by Microsoft that could potentially cause other browsers to reject your entire CSS rule. \n\nSecondly, AlphaImageLoader does not magically add full PNG transparency support so that a PNG in the page will just start working. Instead, when applied to an element in the page, it draws a new rendering surface in the same space that element occupies and loads a PNG into it. If that sounds weird, it\u2019s because that\u2019s precisely what it is. However, by and large the result is that PNGs with an alpha channel can be accommodated.\n\nThe pitfalls\n\nSo, whilst support for PNG transparency in IE5.5 and 6 is possible, it\u2019s not without its problems.\n\nBackground images cannot be positioned or repeated\n\nThe AlphaImageLoader does work for background images, but only for the simplest of cases. If your design requires the image to be tiled (background-repeat) or positioned (background-position) you\u2019re out of luck. The AlphaImageLoader allows you to set a sizingMethod to either crop the image (if necessary) or to scale it to fit. Not massively useful, but something at least.\n\nDelayed loading and resource use\n\nThe AlphaImageLoader can be quite slow to load, and appears to consume more resources than a standard image when applied. Typically, you\u2019d need to add thousands of GIFs or JPEGs to a page before you saw any noticeable impact on the browser, but with the AlphaImageLoader filter applied Internet Explorer can become sluggish after just a handful of alpha channel PNGs.\n\nThe other noticeable effect is that as more instances of the AlphaImageLoader are applied, the longer it takes to render the PNGs with their transparency. The user sees the PNG load in its original non-supported state (with black or grey areas where transparency should be) before one by one the filter kicks in and makes them properly transparent.\n\nBoth the issue of sluggish behaviour and delayed load only really manifest themselves with volume and size of image. Use just a couple of instances and it\u2019s fine, but be careful adding more than five or six. As ever, test, test, test.\n\nLinks become unclickable, forms unfocusable \n\nThis is a big one. There\u2019s a bug/weirdness with AlphaImageLoader that sometimes prevents interaction with links and forms when a PNG background image is used. This is sometimes reported as a z-index issue, but I don\u2019t believe it is. Rather, it\u2019s an artefact of that weird way the filter gets applied to the document almost outside of the normal render process. \n\nOften this can be solved by giving the links or form elements hasLayout using position: relative; where possible. However, this doesn\u2019t always work and the non-interaction problem cannot always be solved. You may find yourself having to go back to the drawing board.\n\nSidestepping the danger zones\n\nFrankly, it\u2019s pretty bad news if you design a site, have that design signed off by your client, build it and then find out only at the end (because you don\u2019t know what might trigger a problem) that your search field can\u2019t be focused in IE6. That\u2019s an absolute nightmare, and whilst it\u2019s not likely to happen, it\u2019s possible that it might. It\u2019s happened to me. So what can you do?\n\nThe best approach I\u2019ve found to this scenario is\n\n\n\tIsolate the PNG or PNGs that are causing the problem. Step through the PNGs in your page, commenting them out one by one and retesting. Typically it\u2019ll be the nearest PNG to the problem, so try there first. Keep going until you can click your links or focus your form fields.\n\tThis is where you really need luck on your side, because you\u2019re going to have to fake it. This will depend on the design of the site, but some way or other create a replacement GIF or JPEG image that will give you an acceptable result. Then use conditional comments to serve that image to only users of IE older than version 7.\n\n\nA hack, you say? Well, you started it chum.\n\nApplying AlphaImageLoader\n\nBecause the filter property is invalid CSS, the safest pragmatic approach is to apply it selectively with JavaScript for only Internet Explorer versions 5.5 and 6. This helps ensure that by default you\u2019re serving standard CSS to browsers that support both the CSS and PNG standards correct, and then selectively patching up only the browsers that need it. \n\nSeveral years ago, Aaron Boodman wrote and released a script called sleight for doing just that. However, sleight dealt only with images in the page, and not background images applied with CSS. Building on top of Aaron\u2019s work, I hacked sleight and came up with bgsleight for applying the filter to background images instead. That was in 2003, and over the years I\u2019ve made a couple of improvements here and there to keep it ticking over and to resolve conflicts between sleight and bgsleight when used together. However, with alpha channel PNGs becoming much more widespread, it\u2019s time for a new version.\n\nIntroducing SuperSleight\n\nSuperSleight adds a number of new and useful features that have come from the day-to-day needs of working with PNGs.\n\n\n\tWorks with both inline and background images, replacing the need for both sleight and bgsleight\n\tWill automatically apply position: relative to links and form fields if they don\u2019t already have position set. (Can be disabled.)\n\tCan be run on the entire document, or just a selected part where you know the PNGs are. This is better for performance.\n\tDetects background images set to no-repeat and sets the scaleMode to crop rather than scale.\n\tCan be re-applied by any other JavaScript in the page \u2013 useful if new content has been loaded by an Ajax request.\n\n\n Download SuperSleight \n\nImplementation\n\nGetting SuperSleight running on a page is quite straightforward, you just need to link the supplied JavaScript file (or the minified version if you prefer) into your document inside conditional comments so that it is delivered to only Internet Explorer 6 or older.\n\n\n\nSupplied with the JavaScript is a simple transparent GIF file. The script replaces the existing PNG with this before re-layering the PNG over the top using AlphaImageLoaded. You can change the name or path of the image in the top of the JavaScript file, where you\u2019ll also find the option to turn off the adding of position: relative to links and fields if you don\u2019t want that.\n\nThe script is kicked off with a call to supersleight.init() at the bottom. The scope of the script can be limited to just one part of the page by passing an ID of an element to supersleight.limitTo(). And that\u2019s all there is to it.\n\nUpdate March 2008: a version of this script as a jQuery plugin is also now available.", "year": "2007", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2007-12-01T00:00:00+00:00", "url": "https://24ways.org/2007/supersleight-transparent-png-in-ie6/", "topic": "code"}
{"rowid": 166, "title": "Performance On A Shoe String", "contents": "Back in the summer, I happened to notice the official Wimbledon All England Tennis Club site had jumped to the top of Alexa\u2019s Movers & Shakers list \u2014 a list that tracks sites that have had the biggest upturn or downturn in traffic. The lawn tennis championships were underway, and so traffic had leapt from almost nothing to crazy-busy in a no time at all. \n\nMany sites have similar peaks in traffic, especially when they\u2019re based around scheduled events. No one cares about the site for most of the year, and then all of a sudden \u2013 wham! \u2013 things start getting warm in the data centre. Whilst the thought of chestnuts roasting on an open server has a certain appeal, it\u2019s less attractive if you care about your site being available to visitors. Take a look at this Alexa traffic graph showing traffic patterns for superbowl.com at the beginning of each year, and wimbledon.org in the month of July.\n\nTraffic graph from Alexa.com \n\nWhilst not on the same scale or with such dramatic peaks, we have a similar pattern of traffic here at 24ways.org. Over the last three years we\u2019ve seen a dramatic pick up in traffic over the month of December (as would be expected) and then a much lower, although steady load throughout the year. What we do have, however, is the luxury of knowing when the peaks will be. For a normal site, be that a blog, small scale web app, or even a small corporate site, you often just cannot predict when you might get slashdotted, end up on the front page of Digg or linked to from a similarly high-profile site. You just don\u2019t know when the peaks will be.\n\nIf you\u2019re a big commercial enterprise like the Super Bowl, scaling up for that traffic is simply a cost of doing business. But for most of us, we can\u2019t afford to have massive capacity sat there unused for 90% of the year. What you have to do instead is work out how to deal with as much traffic as possible with the modest resources you have.\n\nIn this article I\u2019m going to talk about some of the things we\u2019ve learned about keeping 24 ways running throughout December, whilst not spending a fortune on hosting we don\u2019t need for 11 months of each year. We\u2019ve not always got it right, but we\u2019ve learned a lot along the way.\n\nThe Problem\n\nTo know how to deal with high traffic, you need to have a basic idea of what happens when a request comes into a web server. 24 ways is hosted on a single small virtual dedicated server with a great little hosting company in the UK. We run Apache with PHP and MySQL all on that one server. When a request comes in a new Apache process is started to deal with the request (or assigned if there\u2019s one available not doing anything). Each process takes a bunch of memory, so there\u2019s a finite number of processes that you can run, and therefore a finite number of pages you can serve at once before your server runs out of memory.\n\nWith our budget based on whatever is left over after beer, we need to get best performance we can out of the resources available. As the goal is to serve as many pages as quickly as possible, there are several approaches we can take:\n\n\n\tReducing the amount of memory needed by each Apache process\n\tReducing the amount of time each process is needed\n\tReducing the number of requests made to the server\n\n\nYahoo! have published some information on what they call Exceptional Performance, which is well worth reading, and compliments many of my examples here. The Yahoo! guidelines very much look at things from a user perspective, which is always important.\n\nServer tweaking\n\nIf you\u2019re in the position of being able to change your server configuration (our set-up gives us root access to what is effectively a virtual machine) there are some basic steps you can take to maximise the available memory and reduce the memory footprint. Without getting too boring and technical (whole books have been written on this) there are a couple of things to watch out for.\n\nFirstly, check what processes you have running that you might not need. Every megabyte of memory that you free up might equate to several thousand extra requests being served each day, so take a look at top and see what\u2019s using up your resources. Quite often a machine configured as a web server will have some kind of mail server running by default. If your site doesn\u2019t use mail (ours doesn\u2019t) make sure it\u2019s shut down and not using resources.\n\nSecondly, have a look at your Apache configuration and particularly what modules are loaded. The method for doing this varies between versions of Apache, but again, every module loaded increases the amount of memory that each Apache process requires and therefore limits the number of simultaneous requests you can deal with.\n\nThe final thing to check is that Apache isn\u2019t configured to start more servers than you have memory for. This is usually done by setting the MaxClients directive. When that limit is reached, your site is going to stop responding to further requests. However, if all else goes well that threshold won\u2019t be reached, and if it does it will at least stop the weight of the traffic taking the entire server down to a point where you can\u2019t even log in to sort it out.\n\nThose are the main tidbits I\u2019ve found useful for this site, although it\u2019s worth repeating that entire books have been written on this subject alone.\n\nCaching\n\nAlthough the site is generated with PHP and MySQL, the majority of pages served don\u2019t come from the database. The process of compiling a page on-the-fly involves quite a few trips to the database for content, templates, configuration settings and so on, and so can be slow and require a lot of CPU. Unless a new article or comment is published, the site doesn\u2019t actually change between requests and so it makes sense to generate each page once, save it to a file and then just serve all following requests from that file.\n\nWe use QuickCache (or rather a plugin based on it) for this. The plugin integrates with our publishing system (Textpattern) to make sure the cache is cleared when something on the site changes. A similar plugin called WP-Cache is available for WordPress, but of course this could be done any number of ways, and with any back-end technology.\n\nThe important principal here is to reduce the time it takes to serve a page by compiling the page once and serving that cached result to subsequent visitors. Keep away from your database if you can.\n\nOutsource your feeds\n\nWe get around 36,000 requests for our feed each day. That really only works out at about 7,000 subscribers averaging five-and-a-bit requests a day, but it\u2019s still 36,000 requests we could easily do without. Each request uses resources and particularly during December, all those requests can add up. \n\nThe simple solution here was to switch our feed over to using FeedBurner. We publish the address of the FeedBurner version of our feed here, so those 36,000 requests a day hit FeedBurner\u2019s servers rather than ours. In addition, we get pretty graphs showing how the subscriber-base is building.\n\n\n\nOff-load big files\n\nLarger files like images or downloads pose a problem not in bandwidth, but in the time it takes them to transfer. A typical page request is very quick, a few seconds at the most, resulting in the connection being freed up promptly. Anything that keeps a connection open for a long time is going to start killing performance very quickly.\n\nThis year, we started serving most of the images for articles from a subdomain \u2013 media.24ways.org. Rather than pointing to our own server, this subdomain points to an Amazon S3 account where the files are held. It\u2019s easy to pigeon-hole S3 as merely an online backup solution, and whilst not a fully fledged CDN, S3 works very nicely for serving larger media files. The roughly 20GB of files served this month have cost around $5 in Amazon S3 charges. That\u2019s so affordable it may not be worth even taking the files back off S3 once December has passed.\n\nI found this article on Scalable Media Hosting with Amazon S3 to be really useful in getting started. I upload the files via a Firefox plugin (mentioned in the article) and then edit the ACL to allow public access to the files. The way S3 enables you to point DNS directly at it means that you\u2019re not tied to always using the service, and that it can be transparent to your users.\n\nIf your site uses photographs, consider uploading them to a service like Flickr and serving them directly from there. Many photo sharing sites are happy for you to link to images in this way, but do check the acceptable use policies in case you need to provide a credit or link back.\n\nOff-load small files\n\nYou\u2019ll have noticed the pattern by now \u2013 get rid of as much traffic as possible. When an article has a lot of comments and each of those comments has an avatar along with it, a great many requests are needed to fetch each of those images. In 2006 we started using Gravatar for avatars, but their servers were slow and were holding up page loads. To get around this we started caching the images on our server, but along with that came the burden of furnishing all the image requests.\n\nEarlier this year Gravatar changed hands and is now run by the same team behind WordPress.com. Those guys clearly know what they\u2019re doing when it comes to high performance, so this year we went back to serving avatars directly from them.\n\nIf your site uses avatars, it really makes sense to use a service like Gravatar where your users probably already have an account, and where the image requests are going to be dealt with for you. \n\nKnow what you\u2019re paying for\n\nThe server account we use for 24 ways was opened in November 2005. When we first hit the front page of Digg in December of that year, we upgraded the server with a bit more memory, but other than that we were still running on that 2005 spec for two years. Of course, the world of technology has moved on in those years, prices have dropped and specs have improved. For the same amount we were paying for that 2005 spec server, we could have an account with twice the CPU, memory and disk space.\n\nSo in November of this year I took out a new account and transferred the site from the old server to the new. In that single step we were prepared for dealing with twice the amount of traffic, and because of a special offer at the time I didn\u2019t even have to pay the setup cost on the new server. So it really pays to know what you\u2019re paying for and keep an eye out of ways you can make improvements without needing to spend more money.\n\nFurther steps\n\nThere\u2019s nearly always more that can be done. For example, there are some media files (particularly for older articles) that are not on S3. We also serve our CSS directly and it\u2019s not minified or compressed. But by tackling the big problems first we\u2019ve managed to reduce load on the server and at the same time make sure that the load being placed on the server can be dealt with in the most frugal way.\n\nOver the last 24 days we\u2019ve served up articles to more than 350,000 visitors without breaking a sweat. On a busy day, that\u2019s been nearly 20,000 visitors in just 24 hours. While in the grand scheme of things that\u2019s not a huge amount of traffic, it can be a lot if you\u2019re not prepared for it. However, with a little planning for the peaks you can help ensure that when the traffic arrives you\u2019re ready to capitalise on it.\n\nOf course, people only visit 24 ways for the wealth of knowledge and experience that\u2019s tied up in the articles here. Therefore I\u2019d like to take the opportunity to thank all our authors this year who have given their time as a gift to the community, and to wish you all a very happy Christmas.", "year": "2007", "author": "Drew McLellan", "author_slug": "drewmclellan", "published": "2007-12-24T00:00:00+00:00", "url": "https://24ways.org/2007/performance-on-a-shoe-string/", "topic": "ux"}
{"rowid": 167, "title": "Back To The Future of Print", "contents": "By now we have weathered the storm that was the early days of web development, a dangerous time when we used tables, inline CSS and separate pages for print only versions. We can reflect in a haggard old sea-dog manner (\u201cyarrr\u2026 I remember back in the browser wars\u2026\u201d) on the bad practices of the time. We no longer need convincing that print stylesheets are the way to go1, though some of the documentation for them is a little outdated now.\n\nI am going to briefly cover 8 tips and 4 main gotchas when creating print stylesheets in our more enlightened era.\n\nGetting started\n\nAs with regular stylesheets, print CSS can be included in a number of ways2, for our purposes we are going to be using the link\nelement.\n\n\n\nThis is still my favourite way of linking to CSS files, its easy to see what files are being included and to what media they are being applied to. Without the media attribute specified the link element defaults to the media type \u2018all\u2019 which means that the styles within then apply to print and screen alike. The media type \u2018screen\u2019 only applies to the screen and wont be picked up by print, this is the best way of hiding styles from print.\n\nMake sure you include your print styles after all your other CSS, because you will need to override certain rules and this is a lot easier if you are flowing with the cascade than against it!\n\nAnother thing you should be thinking is \u2018does it need to be printed\u2019. Consider the context3, if it is not a page that is likely to be printed, such as a landing page or a section index then the print styles should resemble the way the page looks on the screen.\n\nContext is really important for the design of your print stylesheet, all the tips and tricks that follow should be taken in the context of the page. If for example you are designing a print stylesheet for an item in a shopping cart, it is irrelevant for the user to know the exact url of the link that takes them to your checkout.\n\nTips and tricks\n\nDuring these tip\u2019s we are going to build up print styles for a textileRef:11112857385470b854b8411:linkStartMarker:\u201csimple\nexample\u201d:/examples/back-to-the-future-of-print/demo-1.html\n\n1. Remove the cruft\n\nFirst things first, navigation, headers and most page furniture are pretty much useless and dead space in print so they will need to be removed, using display:none;.\n\n2. Linearise your content\n\nContent doesn\u2019t work so well in columns in print, especially if the content columns are long and intend to stretch over multiple columns (as mentioned in the gotcha section below). You might want to consider Lineariseing the content to flow down the page. If you have your source order in correct priority this will make things a lot easier4.\n\n3. Improve your type\n\nOnce you have removed all the useless cruft and jiggled things about a bit, you can concentrate more on the typography of the page.\n\nTypography is a complex topic5, but simply put serif-ed fonts such as Georgia work better on print and sans serif-ed fonts such as Verdana are more appropriate for screen use. You will probably want to increase font size and line height and change from px to pt (which is specifically a print measurement).\n\n4. Go wild on links\n\nThere are some incredibly fun things you can do with links in print using CSS. There are two schools of thought, one that consider it is best to disguise inline links as body text because they are not click-able on paper. Personally I believe it is useful to know for reference that the document did link to somewhere originally.\n\nWhen deciding which approach to take, consider the context of your document, do people need to know where they would have gone to? will it help or hinder them to know this information? Also for an alternative to the below, take a look at Aaron Gustafson\u2019s article on generating footnotes for print6.\n\nUsing some clever selector trickery and CSS generated content you can have the location of the link generated after the link itself.\n\nHTML:\n\n
\n\nCSS:\n\na:link:after,\na:visited:after,\na:hover:after,\na:active:after {\n\tcontent: \" <\" attr(href) \"> \";\n}\n\nBut this is not perfect, in the above example the content of the href is just naively plonked after the link text:\n\nI wish Google would find my keys \n\nAs looking back over this printout the user is not immediately aware of the location of the link, a better solution is to use even more crazy selectors to deal with relative links. We can also add a style to the generated content so it is distinguishable from the link text itself.\n\nCSS:\n\na:link:after,\na:visited:after,\na:hover:after,\na:active:after {\n\tcontent: \" <\" attr(href) \"> \";\n\tcolor: grey;\n\tfont-style: italic;\n\tfont-weight: normal;\n}\na[href^=\"/\"]:after {\n\tcontent: \" \";\n}\n\nThe output is now what we were looking for (you will need to replace example.com with your own root URL):\n\nI wish Google would find my keys \n\nUsing regular expressions on the attribute selectors, one final thing you can do is to suppress the generated content on mailto: links, if for example you know the link text always reflects the email address. Eg:\n\nHTML:\n\nme@example.com\n\nCSS:\n\na[href^=\"mailto\"]:after {\n\tcontent: \"\";\n}\n\nThis example shows the above in action.\n\nOf course with this clever technique, there are the usual browser support issues. While it won\u2019t look as intended in browsers such as Internet Explorer 6 and 7 (IE6 and IE7) it will not break either and will just degrade gracefully because IE cannot do generated content. To the best of my knowledge Safari 2+ and Opera 9.X support a colour set on generated content whereas Firefox 2 & Camino display this in black regardless of the link or inherited text colour.\n\n5. Jazz your headers for print\n\nThis is more of a design consideration, don\u2019t go too nuts though; there are a lot more limitations in print media than on screen. For this example we are going to go for is having a bottom border on h2\u2019s and styling other headings with graduating colors or font sizes.\n\nAnd here is the example complete with jazzy headers.\n\n6. Build in general hooks\n\nIf you are building a large site with many different types of page, you may find it useful to build into your CSS structure, classes that control what is printed (e.g. noprint and printonly). This may not be semantically ideal, but in the past I have found it really useful for maintainability of code across large and varied sites\n\n7. For that extra touch of class\n\nWhen printing pages from a long URL, even if the option is turned on to show the location of the page in the header, browsers may still display a truncated (and thus useless) version.\n\nUsing the above tip (or just simply setting to display:none in screen and display:block in print) you can insert the URL of the page you are currently on for print only, using JavaScript\u2019s window.location.href variable.\n\nfunction addPrintFooter() {\n\tvar p = document.createElement('p');\n\tp.className = 'print-footer';\n\tp.innerHTML = window.location.href;\n\tdocument.body.appendChild(p);\n}\n\nYou can then call this function using whichever onload or ondomready handler suits your fancy. Here is our familiar demo to show all the above in action\n\n8. Tabular data across pages\n\nIf you are using tabled data in your document there are a number of things you can do to increase usability of long tables over several pages. If you use the element this should repeat your table headers on the next page should your table be split. You will need to set thead {display: table-header-group;} explicitly for IE even though this should be the default value.\n\nAlso if you use tr {page-break-inside: avoid;} this should (browser support depending) stop your table row from breaking across two pages. For more information on styling tables for print please see the CSS discuss wiki7.\n\nGotchas\n\n1. Where did all my content go?\n\nAbsolutely the most common mistake I see with print styles is the truncated content bug. The symptom of this is that only the first page of a div\u2019s content will be printed, the rest will look truncated after this.\n\nFloating long columns may still have this affect, as mentioned in Eric Meyer\u2019s article on \u2018A List Apart\u2019 article from 20028; though in testing I am no longer able to replicate this. Using overflow:hidden on long content in Firefox however still causes this truncation. Overflow hidden is commonly used to clear floats9.\n\nA simple fix can be applied to resolve this, if the column is floated you can override this with float:none similarly overflow:hidden can be overridden with overflow:visible or the offending rules can be banished to a screen only stylesheet.\n\nUsing position:absolute on long columns also has a very similar effect in truncating the content, but can be overridden in print with position:static;\n\nWhilst I only recommend having a print stylesheet for content pages on your site; do at least check other landing pages, section indexes and your homepage. If these are inaccessible in print possibly due to the above gotcha, it might be wise to provide a light dusting of print styles or move the offending overflow / float rules to a screen only stylesheet to fix the issues.\n\n2. Damn those background browser settings\n\nOne of the factors of life you now need to accept is that you can\u2019t control the user\u2019s browser settings, no more than you can control whether or not they use IE6. Most browsers by default will not print background colours or images unless explicitly told to by the user.\n\nNaturally this causes a number of problems, for starters you will need to rethink things like branding. At this point it helps if you are doing the print styles early in the project so that you can control the logo not being a background image for example.\n\nWhere colour is important to the meaning of the document, for example a status on an invoice, bear in mind that a textural representation will also need to be supplied as the user may be printing in black and white. Borders will print however regardless of setting, so assuming the user is printing in colour you can always use borders to indicate colour.\n\nCheck the colour contrast of the text against white, this may need to be altered without backgrounds. You should check how your page looks with backgrounds turned on too, for consistency with the default browser settings you may want to override your background anyway.\n\nOne final issue with backgrounds being off is list items. It is relatively common practice to suppress the list-style-type and replace with a background image to finely control the bullet positioning. This technique doesn\u2019t translate to print, you will need to disable this background bullet and re-instate your trusty friend the list-style-type.\n\n3. Using JavaScript in your CSS? \u2026 beware IE6\n\nInternet explorer has an issue that when Javascript is used in a stylesheet it applies this to all media types even if only applied to screen. For example, if you happen to be using expressions to set a width for IE, perhaps to mimic min-width, a simple width:100% !important rule can overcome the effects the expression has on your print styles10.\n\n4. De-enhance your Progressive enhancements\n\nQuite a classic \u201cdoh\u201d moment is when you realise that, of course paper doesn\u2019t support Javascript. If you have any dynamic elements on the page, for example a document collapsed per section, you really should have been using Progressive enhancement techniques11 and building for browsers without Javascript first, adding in the fancy stuff later.\n\nIf this is the case it should be trivial to override your wizzy JS styles in your print stylesheet, to display all your content and make it accessible for print, which is by far the best method of achieving this affect.\n\nAnd Finally\u2026\n\nI refer you back to the nature of the document in hand, consider the context of your site and the page. Use the tips here to help you add that extra bit of flair to your printed media.\n\nBe careful you don\u2019t get caught out by the common gotchas, keep the design simple, test cross browser and relish in the medium of print.\n\nFurther Reading\n\n1 For more information constantly updated, please see the CSS discuss wiki on print stylesheets\n\n2 For more information on media types and ways of including CSS please refer to the CSS discuss wiki on Media Stylesheets\n\n3 Eric Meyer talks to ThinkVitamin about the importance of context when designing your print strategy.\n\n4 Mark Boulton describes how he applies a newspaper like print stylesheet to an article in the Guardian website. Mark also has some persuasive arguments that print should not be left to last\n\n5 Richard Rutter Has a fantastic resource on typography which also applies to print.\n\n6 Aaron Gustafson has a great solution to link problem by creating footnotes at the end of the page.\n\n7 The CSS discuss wiki has more detailed information on printing tables and detailed browser support\n\n8 This \u2018A List Apart\u2019 article is dated May 10th 2002 though is still mostly relevant\n\n9 Float clearing technique using \u2018overflow:hidden\u2019\n\n10 Autistic Cuckoo describes the interesting insight with regards to expressions specified for screen in IE6 remaining in print\n\n11 Wikipedia has a good article on the definition of progressive enhancement\n\n12 For a really neat trick involving a dynamically generated column to displaying and meanings (as well as somewhere for the user to write notes), try print previewing on Brian Suda\u2019s site", "year": "2007", "author": "Natalie Downe", "author_slug": "nataliedowne", "published": "2007-12-09T00:00:00+00:00", "url": "https://24ways.org/2007/back-to-the-future-of-print/", "topic": "design"}
{"rowid": 168, "title": "Unobtrusively Mapping Microformats with jQuery", "contents": "Microformats are everywhere. You can\u2019t shake an electronic stick these days without accidentally poking a microformat-enabled site, and many developers use microformats as a matter of course. And why not? After all, why invent your own class names when you can re-use pre-defined ones that give your site extra functionality for free?\n\nNevertheless, while it\u2019s good to know that users of tools such as Tails and Operator will derive added value from your shiny semantics, it\u2019s nice to be able to reuse that effort in your own code.\n\nWe\u2019re going to build a map of some of my favourite restaurants in Brighton. Fitting with the principles of unobtrusive JavaScript, we\u2019ll start with a semantically marked up list of restaurants, then use JavaScript to add the map, look up the restaurant locations and plot them as markers.\n\nWe\u2019ll be using a couple of powerful tools. The first is jQuery, a JavaScript library that is ideally suited for unobtrusive scripting. jQuery allows us to manipulate elements on the page based on their CSS selector, which makes it easy to extract information from microformats.\n\nThe second is Mapstraction, introduced here by Andrew Turner a few days ago. We\u2019ll be using Google Maps in the background, but Mapstraction makes it easy to change to a different provider if we want to later.\n\nGetting Started\n\nWe\u2019ll start off with a simple collection of microformatted restaurant details, representing my seven favourite restaurants in Brighton. The full, unstyled list can be seen in restaurants-plain.html. Each restaurant listing looks like this:\n\n
\n\nSince we\u2019re dealing with a list of restaurants, each hCard is marked up inside a list item. Each restaurant is an organisation; we signify this by placing the classes fn and org on the element surrounding the restaurant\u2019s name (according to the hCard spec, setting both fn and org to the same value signifies that the hCard represents an organisation rather than a person).\n\nThe address information itself is contained within a div of class adr. Note that the HTML element is not suitable here for two reasons: firstly, it is intended to mark up contact details for the current document rather than generic addresses; secondly, address is an inline element and as such cannot contain the paragraphs elements used here for the address information.\n\nA nice thing about microformats is that they provide us with automatic hooks for our styling. For the moment we\u2019ll just tidy up the whitespace a bit; for more advanced style tips consult John Allsop\u2019s guide from 24 ways 2006.\n\n.vcard p {\n\tmargin: 0;\n}\n.adr {\n\tmargin-bottom: 0.5em;\n}\n\nTo plot the restaurants on a map we\u2019ll need latitude and longitude for each one. We can find this out from their address using geocoding. Most mapping APIs include support for geocoding, which means we can pass the API an address and get back a latitude/longitude point. Mapstraction provides an abstraction layer around these APIs which can be included using the following script tag:\n\n\n\nWhile we\u2019re at it, let\u2019s pull in the other external scripts we\u2019ll be using:\n\n\n\n\n\n\nThat\u2019s everything set up: let\u2019s write some JavaScript!\n\nIn jQuery, almost every operation starts with a call to the jQuery function. The function simulates method overloading to behave in different ways depending on the arguments passed to it. When writing unobtrusive JavaScript it\u2019s important to set up code to execute when the page has loaded to the point that the DOM is available to be manipulated. To do this with jQuery, pass a callback function to the jQuery function itself:\n\njQuery(function() {\n\t// This code will be executed when the DOM is ready\n});\n\nInitialising the map\n\nThe first thing we need to do is initialise our map. Mapstraction needs a div with an explicit width, height and ID to show it where to put the map. Our document doesn\u2019t currently include this markup, but we can insert it with a single line of jQuery code:\n\njQuery(function() {\n\t// First create a div to host the map\n\tvar themap = jQuery('').css({\n\t\t'width': '90%',\n\t\t'height': '400px'\n\t}).insertBefore('ul.restaurants');\n});\n\nWhile this is technically just a single line of JavaScript (with line-breaks added for readability) it\u2019s actually doing quite a lot of work. Let\u2019s break it down in to steps:\n\nvar themap = jQuery('')\n\nHere\u2019s jQuery\u2019s method overloading in action: if you pass it a string that starts with a < it assumes that you wish to create a new HTML element. This provides us with a handy shortcut for the more verbose DOM equivalent:\n\nvar themap = document.createElement('div');\nthemap.id = 'themap';\n\nNext we want to apply some CSS rules to the element. jQuery supports chaining, which means we can continue to call methods on the object returned by jQuery or any of its methods:\n\nvar themap = jQuery('').css({\n\t'width': '90%',\n\t'height': '400px'\n})\n\nFinally, we need to insert our new HTML element in to the page. jQuery provides a number of methods for element insertion, but in this case we want to position it directly before the
we are using to contain our restaurants. jQuery\u2019s insertBefore() method takes a CSS selector indicating an element already on the page and places the current jQuery selection directly before that element in the DOM.\n\nvar themap = jQuery('').css({\n\t'width': '90%',\n\t'height': '400px'\n}).insertBefore('ul.restaurants');\n\nFinally, we need to initialise the map itself using Mapstraction. The Mapstraction constructor takes two arguments: the first is the ID of the element used to position the map; the second is the mapping provider to use (in this case google ):\n\n// Initialise the map\nvar mapstraction = new Mapstraction('themap','google');\n\nWe want the map to appear centred on Brighton, so we\u2019ll need to know the correct co-ordinates. We can use www.getlatlon.com to find both the co-ordinates and the initial map zoom level.\n\n// Show map centred on Brighton\nmapstraction.setCenterAndZoom(\n\tnew LatLonPoint(50.82423734980143, -0.14007568359375),\n\t15 // Zoom level appropriate for Brighton city centre\n);\n\nWe also want controls on the map to allow the user to zoom in and out and toggle between map and satellite view.\n\nmapstraction.addControls({\n\tzoom: 'large',\n\tmap_type: true\n});\n\nAdding the markers\n\nIt\u2019s finally time to parse some microformats. Since we\u2019re using hCard, the information we want is wrapped in elements with the class vcard. We can use jQuery\u2019s CSS selector support to find them:\n\nvar vcards = jQuery('.vcard');\n\nNow that we\u2019ve found them, we need to create a marker for each one in turn. Rather than using a regular JavaScript for loop, we can instead use jQuery\u2019s each() method to execute a function against each of the hCards.\n\njQuery('.vcard').each(function() {\n\t// Do something with the hCard\n});\n\nWithin the callback function, this is set to the current DOM element (in our case, the list item). If we want to call the magic jQuery methods on it we\u2019ll need to wrap it in another call to jQuery:\n\njQuery('.vcard').each(function() {\n\tvar hcard = jQuery(this);\n});\n\nThe Google maps geocoder seems to work best if you pass it the street address and a postcode. We can extract these using CSS selectors: this time, we\u2019ll use jQuery\u2019s find() method which searches within the current jQuery selection:\n\nvar streetaddress = hcard.find('.street-address').text();\nvar postcode = hcard.find('.postal-code').text();\n\nThe text() method extracts the text contents of the selected node, minus any HTML markup.\n\nWe\u2019ve got the address; now we need to geocode it. Mapstraction\u2019s geocoding API requires us to first construct a MapstractionGeocoder, then use the geocode() method to pass it an address. Here\u2019s the code outline:\n\nvar geocoder = new MapstractionGeocoder(onComplete, 'google');\ngeocoder.geocode({'address': 'the address goes here');\n\nThe onComplete function is executed when the geocoding operation has been completed, and will be passed an object with the resulting point on the map. We just want to create a marker for the point:\n\nvar geocoder = new MapstractionGeocoder(function(result) {\n\tvar marker = new Marker(result.point);\n\tmapstraction.addMarker(marker);\n}, 'google'); \n\nFor our purposes, joining the street address and postcode with a comma to create the address should suffice:\n\ngeocoder.geocode({'address': streetaddress + ', ' + postcode}); \n\nThere\u2019s one last step: when the marker is clicked, we want to display details of the restaurant. We can do this with an info bubble, which can be configured by passing in a string of HTML. We\u2019ll construct that HTML using jQuery\u2019s html() method on our hcard object, which extracts the HTML contained within that DOM node as a string.\n\nvar marker = new Marker(result.point);\nmarker.setInfoBubble(\n\t'
' + hcard.html() + '
'\n);\nmapstraction.addMarker(marker);\n\nWe\u2019ve wrapped the bubble in a div with class bubble to make it easier to style. Google Maps can behave strangely if you don\u2019t provide an explicit width for your info bubbles, so we\u2019ll add that to our CSS now:\n\n.bubble {\n\twidth: 300px;\n}\n\nThat\u2019s everything we need: let\u2019s combine our code together:\n\njQuery(function() {\n\t// First create a div to host the map\n\tvar themap = jQuery('').css({\n\t\t'width': '90%',\n\t\t'height': '400px'\n\t}).insertBefore('ul.restaurants');\n\t// Now initialise the map\n\tvar mapstraction = new Mapstraction('themap','google');\n\tmapstraction.addControls({\n\t\tzoom: 'large',\n\t\tmap_type: true\n\t});\n\t// Show map centred on Brighton\n\tmapstraction.setCenterAndZoom(\n\t\tnew LatLonPoint(50.82423734980143, -0.14007568359375),\n\t\t15 // Zoom level appropriate for Brighton city centre\n\t);\n\t// Geocode each hcard and add a marker\n\tjQuery('.vcard').each(function() {\n\t\tvar hcard = jQuery(this);\n\t\tvar streetaddress = hcard.find('.street-address').text();\n\t\tvar postcode = hcard.find('.postal-code').text();\n\t\tvar geocoder = new MapstractionGeocoder(function(result) {\n\t\t\tvar marker = new Marker(result.point);\n\t\t\tmarker.setInfoBubble(\n\t\t\t\t'
' + hcard.html() + '
'\n\t\t\t);\n\t\t\tmapstraction.addMarker(marker);\n\t\t}, 'google');\t \n\t\tgeocoder.geocode({'address': streetaddress + ', ' + postcode});\n\t});\n});\n\nHere\u2019s the finished code.\n\nThere\u2019s one last shortcut we can add: jQuery provides the $ symbol as an alias for jQuery. We could just go through our code and replace every call to jQuery() with a call to $(), but this would cause incompatibilities if we ever attempted to use our script on a page that also includes the Prototype library. A more robust approach is to start our code with the following:\n\njQuery(function($) {\n\t// Within this function, $ now refers to jQuery\n\t// ...\n});\n\njQuery cleverly passes itself as the first argument to any function registered to the DOM ready event, which means we can assign a local $ variable shortcut without affecting the $ symbol in the global scope. This makes it easy to use jQuery with other libraries.\n\nLimitations of Geocoding\n\nYou may have noticed a discrepancy creep in to the last example: whereas my original list included seven restaurants, the geocoding example only shows five. This is because the Google Maps geocoder incorporates a rate limit: more than five lookups in a second and it starts returning error messages instead of regular results.\n\nIn addition to this problem, geocoding itself is an inexact science: while UK postcodes generally get you down to the correct street, figuring out the exact point on the street from the provided address usually isn\u2019t too accurate (although Google do a pretty good job).\n\nFinally, there\u2019s the performance overhead. We\u2019re making five geocoding requests to Google for every page served, even though the restaurants themselves aren\u2019t likely to change location any time soon. Surely there\u2019s a better way of doing this?\n\nMicroformats to the rescue (again)! The geo microformat suggests simple classes for including latitude and longitude information in a page. We can add specific points for each restaurant using the following markup:\n\n
\n\t
E-Kagen
\n\t
\n\t\t
22-23 Sydney Street
\n\t\t
Brighton, UK
\n\t\t
BN1 4EN
\n\t
\n\t
Telephone: +44 (0)1273 687 068
\n\t
Lat/Lon: \n\t\t50.827917, \n\t\t-0.137764\n\t
\n
\n\nAs before, I used www.getlatlon.com to find the exact locations \u2013 I find satellite view is particularly useful for locating individual buildings.\n\nLatitudes and longitudes are great for machines but not so useful for human beings. We could hide them entirely with display: none, but I prefer to merely de-emphasise them (someone might want them for their GPS unit):\n\n.vcard .geo {\n\tmargin-top: 0.5em;\n\tfont-size: 0.85em;\n\tcolor: #ccc;\n}\n\nIt\u2019s probably a good idea to hide them completely when they\u2019re displayed inside an info bubble:\n\n.bubble .geo {\n\tdisplay: none;\n}\n\nWe can extract the co-ordinates in the same way we extracted the address. Since we\u2019re no longer geocoding anything our code becomes a lot simpler:\n\n$('.vcard').each(function() {\n\tvar hcard = $(this);\n\tvar latitude = hcard.find('.geo .latitude').text();\n\tvar longitude = hcard.find('.geo .longitude').text();\n\tvar marker = new Marker(new LatLonPoint(latitude, longitude));\n\tmarker.setInfoBubble(\n\t\t'
' + hcard.html() + '
'\n\t);\n\tmapstraction.addMarker(marker);\n});\n\nAnd here\u2019s the finished geo example.\n\nFurther reading\n\nWe\u2019ve only scratched the surface of what\u2019s possible with microformats, jQuery (or just regular JavaScript) and a bit of imagination. If this example has piqued your interest, the following links should give you some more food for thought.\n\n\n\tThe hCard specification\n\tNotes on parsing hCards\n\tjQuery for JavaScript programmers \u2013 my extended tutorial on jQuery.\n\tDann Webb\u2019s Sumo \u2013 a full JavaScript library for parsing microformats, based around some clever metaprogramming techniques.\n\tJeremy Keith\u2019s Adactio Austin \u2013 the first place I saw using microformats to unobtrusively plot locations on a map. Makes clever use of hEvent as well.", "year": "2007", "author": "Simon Willison", "author_slug": "simonwillison", "published": "2007-12-12T00:00:00+00:00", "url": "https://24ways.org/2007/unobtrusively-mapping-microformats-with-jquery/", "topic": "code"}
{"rowid": 169, "title": "Incite A Riot", "contents": "Given its relatively limited scope, HTML can be remarkably expressive. With a bit of lateral thinking, we can mark up content such as tag clouds and progress meters, even when we don\u2019t have explicit HTML elements for those patterns.\n\nSuppose we want to mark up a short conversation:\n\n \n Alice: I think Eve is watching. \n\n Bob: This isn\u2019t a cryptography tutorial \u2026we\u2019re in the wrong example!\n \n\n\nA note in the the HTML 4.01 spec says it\u2019s okay to use a definition list:\n\n\n\tAnother application of DL, for example, is for marking up dialogues, with each DT naming a speaker, and each DD containing his or her words.\n\n\nThat would give us:\n\n
\n\t
Alice
:
I think Eve is watching.
\n\t
Bob
:
This isn't a cryptography tutorial ...we're in the wrong example!
\n
\n\nThis usage of a definition list is proof that writing W3C specifications and smoking crack are not mutually exclusive activities. \u201cI think Eve is watching\u201d is not a definition of \u201cAlice.\u201d If you (ab)use a definition list in this way, Norm will hunt you down.\n\nThe conversation problem was revisited in HTML5. What if dt and dd didn\u2019t always mean \u201cdefinition title\u201d and \u201cdefinition description\u201d? A new element was forged: dialog. Now the the \u201cd\u201d in dt and dd doesn\u2019t stand for \u201cdefinition\u201d, it stands for \u201cdialog\u201d (or \u201cdialogue\u201d if you can spell):\n\n\n\nProblem solved \u2026except that dialog is no longer in the HTML5 spec. Hixie further expanded the meaning of dt and dd so that they could be used inside details (which makes sense\u2014it starts with a \u201cd\u201d) and figure (\u2026um). At the same time as the content model of details and figure were being updated, the completely-unrelated dialog element was dropped.\n\nBack to the drawing board, or in this case, the HTML 4.01 specification. The spec defines the cite element thusly:\n\n\n\tContains a citation or a reference to other sources.\n\n\nPerfect! There\u2019s even an example showing how this can applied when attributing quotes to people:\n\nAs Harry S. Truman said,\nThe buck stops here.\n\nFor longer quotes, the blockquote element might be more appropriate. In a conversation, where the order matters, I think an ordered list would make a good containing element for this pattern:\n\n\n\t
Alice: I think Eve is watching.
\n\t
Bob: This isn't a cryptography tutorial ...we're in the wrong example!
\n\n\nProblem solved \u2026except that the cite element has been redefined in the HTML5 spec:\n\n\n\tThe cite element represents the title of a work \u2026 A person\u2019s name is not the title of a work \u2026 and the element must therefore not be used to mark up people\u2019s names.\n\n\nHTML5 is supposed to be backwards compatible with previous versions of HTML, yet here we have a semantic pattern already defined in HTML 4.01 that is now non-conforming in HTML5. The entire justification for the change boils down to this line of reasoning:\n\n\n\tGiven that: titles of works are often italicised and\n\tgiven that: people\u2019s names are not often italicised and\n\tgiven that: most browsers italicise the contents of the cite element,\n\ttherefore: the cite element should not be used to mark up people\u2019s names.\n\n\nIn other words, the default browser styling is now dictating semantic meaning. The tail is wagging the dog.\n\nNot to worry, the HTML5 spec tells us how we can mark up names in conversations without using the cite element:\n\n\n\tIn some cases, the b element might be appropriate for names\n\n\nI believe the colloquial response to this is a combination of the letters W, T and F, followed by a question mark.\n\nThe non-normative note continues:\n\n\n\tIn other cases, if an element is really needed, the span element can be used.\n\n\nThis is not a joke. We are seriously being told to use semantically meaningless elements to mark up content that is semantically meaningful.\n\nWe don\u2019t have to take it.\n\nFirstly, any conformance checker\u2014that\u2019s the new politically correct term for \u201cvalidator\u201d\u2014cannot possibly check every instance of the cite element to see if it\u2019s really the title of a work and not the name of a person. So we can disobey the specification without fear of invalidating our documents.\n\nSecondly, Hixie has repeatedly stated that browser makers have a powerful voice in deciding what goes into the HTML5 spec; if a browser maker refuses to implement a feature, then that feature should come out of the spec because otherwise, the spec is fiction. Well, one of the design principles of HTML5 is the Priority of Constituencies:\n\n\n\tIn case of conflict, consider users over authors over implementors over specifiers over theoretical purity.\n\n\nThat places us\u2014authors\u2014above browser makers. If we resolutely refuse to implement part of the HTML5 spec, then the spec becomes fiction.\n\nJoin me in a campaign of civil disobedience against the unnecessarily restrictive, backwards-incompatible change to the cite element. Start using HTML5 but start using it sensibly. Let\u2019s ensure that bad advice remains fictitious.\n\nTantek has set up a page on the WHATWG wiki to document usage of the cite element for conversations. Please contribute to it.", "year": "2009", "author": "Jeremy Keith", "author_slug": "jeremykeith", "published": "2009-12-11T00:00:00+00:00", "url": "https://24ways.org/2009/incite-a-riot/", "topic": "code"}
{"rowid": 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": 171, "title": "Rock Solid HTML Emails", "contents": "At some stage in your career, it\u2019s likely you\u2019ll be asked by a client to design a HTML email. Before you rush to explain that all the cool kids are using social media, keep in mind that when done correctly, email is still one of the best ways to promote you and your clients online. In fact, a recent survey showed that every dollar spent on email marketing this year generated more than $40 in return. That\u2019s more than any other marketing channel, including the cool ones.\n\nThere are a whole host of ingredients that contribute to a good email marketing campaign. Permission, relevance, timeliness and engaging content are all important. Even so, the biggest challenge for designers still remains building an email that renders well across all the popular email clients.\n\nSame same, but different\n\nBefore getting into the details, there are some uncomfortable facts that those new to HTML email should be aware of. Building an email is not like building for the web. While web browsers continue their onward march towards standards, many email clients have stubbornly stayed put. Some have even gone backwards. In 2007, Microsoft switched the Outlook rendering engine from Internet Explorer to Word. Yes, as in the word processor. Add to this the quirks of the major web-based email clients like Gmail and Hotmail, sprinkle in a little Lotus Notes and you\u2019ll soon realize how different the email game is.\n\nWhile it\u2019s not without its challenges, rest assured it can be done. In my experience the key is to focus on three things. First, you should keep it simple. The more complex your email design, the more likely is it to choke on one of the popular clients with poor standards support. Second, you need to take your coding skills back a good decade. That often means nesting tables, bringing CSS inline and following the coding guidelines I\u2019ll outline below. Finally, you need to test your designs regularly. Just because a template looks nice in Hotmail now, doesn\u2019t mean it will next week.\n\nSetting your lowest common denominator\n\nTo maintain your sanity, it\u2019s a good idea to decide exactly which email clients you plan on supporting when building a HTML email. While general research is helpful, the email clients your subscribers are using can vary significantly from list to list. If you have the time there are a number of tools that can tell you specifically which email clients your subscribers are using. Trust me, if the testing shows almost none of them are using a client like Lotus Notes, save yourself some frustration and ignore it altogether. \n\nKnowing which email clients you\u2019re targeting not only makes the building process easier, it can save you lots of time in the testing phase too. For the purpose of this article, I\u2019ll be sharing techniques that give the best results across all of the popular clients, including the notorious ones like Gmail, Lotus Notes 6 and Outlook 2007. Just remember that pixel perfection in all email clients is a pipe dream.\n\nLet\u2019s get started.\n\nUse tables for layout\n\nBecause clients like Gmail and Outlook 2007 have poor support for float, margin and padding, you\u2019ll need to use tables as the framework of your email. While nested tables are widely supported, consistent treatment of width, margin and padding within table cells is not. For the best results, keep the following in mind when coding your table structure.\n\nSet the width in each cell, not the table\n\nWhen you combine table widths, td widths, td padding and CSS padding into an email, the final result is different in almost every email client. The most reliable way to set the width of your table is to set a width for each cell, not for the table itself.\n\n
\n\t
\n\t\t
\n\t\t
\n\t
\n
\n\nNever assume that if you don\u2019t specify a cell width the email client will figure it out. It won\u2019t. Also avoid using percentage based widths. Clients like Outlook 2007 don\u2019t respect them, especially for nested tables. Stick to pixels. If you want to add padding to each cell, use either the cellpadding attribute of the table or CSS padding for each cell, but never combine the two.\n\nErr toward nesting\n\nTable nesting is far more reliable than setting left and right margins or padding for table cells. If you can achieve the same effect by table nesting, that will always give you the best result across the buggier email clients.\n\nUse a container table for body background colors\n\nMany email clients ignore background colors specified in your CSS or the tag. To work around this, wrap your entire email with a 100% width table and give that a background color.\n\n
\n\t
\n\t\t
\n\t\t\tYour email code goes here.\n\t\t
\n\t
\n
\n\nYou can use the same approach for background images too. Just remember that some email clients don\u2019t support them, so always provide a fallback color.\n\nAvoid unnecessary whitespace in table cells\n\nWhere possible, avoid whitespace between your
tags. Some email clients (ahem, Yahoo! and Hotmail) can add additional padding above or below the cell contents in some scenarios, breaking your design for no apparent reason.\n\nCSS and general font formatting\n\nWhile some email designers do their best to avoid CSS altogether and rely on the dreaded tag, the truth is many CSS properties are well supported by most email clients. See this comprehensive list of CSS support across the major clients for a good idea of the safe properties and those that should be avoided. \n\nAlways move your CSS inline\n\nGmail is the culprit for this one. By stripping the CSS from the and of any email, we\u2019re left with no choice but to move all CSS inline. The good news is this is something you can almost completely automate. Free services like Premailer will move all CSS inline with the click of a button. I recommend leaving this step to the end of your build process so you can utilize all the benefits of CSS.\n\nAvoid shorthand for fonts and hex notation\n\nA number of email clients reject CSS shorthand for the font property. For example, never set your font styles like this.\n\np {\n\tfont:bold 1em/1.2em georgia,times,serif;\n}\n\nInstead, declare the properties individually like this.\n\np {\n\tfont-weight: bold;\n\tfont-size: 1em;\n\tline-height: 1.2em;\n\tfont-family: georgia,times,serif;\n}\n\nWhile we\u2019re on the topic of fonts, I recently tested every conceivable variation of @font-face across the major email clients. The results were dismal, so unfortunately it\u2019s web-safe fonts in email for the foreseeable future.\n\nWhen declaring the color property in your CSS, some email clients don\u2019t support shorthand hexadecimal colors like color:#f60; instead of color:#ff6600;. Stick to the longhand approach for the best results.\n\nParagraphs\n\nJust like table cell spacing, paragraph spacing can be tricky to get a consistent result across the board. I\u2019ve seen many designers revert to using double or DIVs with inline CSS margins to work around these shortfalls, but recent testing showed that paragraph support is now reliable enough to use in most cases (there was a time when Yahoo! didn\u2019t support the paragraph tag at all).\n\nThe best approach is to set the margin inline via CSS for every paragraph in your email, like so:\n\np {\n\tmargin: 0 0 1.6em 0;\n}\n\nAgain, do this via CSS in the head when building your email, then use Premailer to bring it inline for each paragraph later.\n\nIf part of your design is height-sensitive and calls for pixel perfection, I recommend avoiding paragraphs altogether and setting the text formatting inline in the table cell. You might need to use table nesting or cellpadding / CSS to get the desired result. Here\u2019s an example:\n\n
your height sensitive text
\n\nLinks\n\nSome email clients will overwrite your link colors with their defaults, and you can avoid this by taking two steps. First, set a default color for each link inline like so:\n\nthis is a link\n\nNext, add a redundant span inside the a tag.\n\nthis is a link\n\nTo some this may be overkill, but if link color is important to your design then a superfluous span is the best way to achieve consistency.\n\nImages in HTML emails\n\nThe most important thing to remember about images in email is that they won\u2019t be visible by default for many subscribers. If you start your design with that assumption, it forces you to keep things simple and ensure no important content is suppressed by image blocking.\n\nWith this in mind, here are the essentials to remember when using images in HTML email:\n\nAvoid spacer images\n\nWhile the combination of spacer images and nested tables was popular on the web ten years ago, image blocking in many email clients has ruled it out as a reliable technique today. Most clients replace images with an empty placeholder in the same dimensions, others strip the image altogether. Given image blocking is on by default in most email clients, this can lead to a poor first impression for many of your subscribers. Stick to fixed cell widths to keep your formatting in place with or without images.\n\nAlways include the dimensions of your image\n\nIf you forget to set the dimensions for each image, a number of clients will invent their own sizes when images are blocked and break your layout. Also, ensure that any images are correctly sized before adding them to your email. Some email clients will ignore the dimensions specified in code and rely on the true dimensions of your image. \n\nAvoid PNGs\n\nLotus Notes 6 and 7 don\u2019t support 8-bit or 24-bit PNG images, so stick with the GIF or JPG formats for all images, even if it means some additional file size.\n\nProvide fallback colors for background images\n\nOutlook 2007 has no support for background images (aside from this hack to get full page background images working). If you want to use a background image in your design, always provide a background color the email client can fall back on. This solves both the image blocking and Outlook 2007 problem simultaneously.\n\nDon\u2019t forget alt text\n\nLack of standards support means email clients have long destroyed the chances of a semantic and accessible HTML email. Even still, providing alt text is important from an image blocking perspective. Even with images suppressed by default, many email clients will display the provided alt text instead. Just remember that some email clients like Outlook 2007, Hotmail and Apple Mail don\u2019t support alt text at all when images are blocked.\n\nUse the display hack for Hotmail\n\nFor some inexplicable reason, Windows Live Hotmail adds a few pixels of additional padding below images. A workaround is to set the display property like so.\n\nimg {display:block;}\n\nThis removes the padding in Hotmail and still gives you the predicable result in other email clients.\n\nDon\u2019t use floats\n\nBoth Outlook 2007 and earlier versions of Notes offer no support for the float property. Instead, use the align attribute of the img tag to float images in your email.\n\n\n\nIf you\u2019re seeing strange image behavior in Yahoo! Mail, adding align=\u201ctop\u201d to your images can often solve this problem.\n\nVideo in email\n\nWith no support for JavaScript or the object tag, video in email (if you can call it that) has long been limited to animated gifs. However, some recent research I did into the HTML5 video tag in email showed some promising results.\n\nTurns out HTML5 video does work in many email clients right now, including Apple Mail, Entourage 2008, MobileMe and the iPhone. The real benefit of this approach is that if the video isn\u2019t supported, you can provide reliable fallback content such as an animated GIF or a clickable image linking to the video in the browser.\n\nOf course, the question of whether you should add video to email is another issue altogether. If you lean toward the \u201cyes\u201d side check out the technique with code samples.\n\nWhat about mobile email?\n\nThe mobile email landscape was a huge mess until recently. With the advent of the iPhone, Android and big improvements from Palm and RIM, it\u2019s becoming less important to think of mobile as a different email platform altogether.\n\nThat said, there are a few key pointers to keep in mind when coding your emails to get a decent result for your more mobile subscribers.\n\nKeep the width less than 600 pixels\n\nBecause of email client preview panes, this rule was important long before mobile email clients came of age. In truth, the iPhone and Pre have a viewport of 320 pixels, the Droid 480 pixels and the Blackberry models hover around 360 pixels. Sticking to a maximum of 600 pixels wide ensures your design should still be readable when scaled down for each device. This width also gives good results in desktop and web-based preview panes.\n\nBe aware of automatic text resizing\n\nIn what is almost always a good feature, email clients using webkit (such as the iPhone, Pre and Android) can automatically adjust font sizes to increase readability. If testing shows this feature is doing more harm than good to your design, you can always disable it with the following CSS rule:\n\n-webkit-text-size-adjust: none;\n\nDon\u2019t forget to test\n\nWhile standards support in email clients hasn\u2019t made much progress in the last few years, there has been continual change (for better or worse) in some email clients. Web-based providers like Yahoo!, Hotmail and Gmail are notorious for this. On countless occasions I\u2019ve seen a proven design suddenly stop working without explanation.\n\nFor this reason alone it\u2019s important to retest your email designs on a regular basis. I find a quick test every month or so does the trick, especially in the web-based clients. The good news is that after designing and testing a few HTML email campaigns, you will find that order will emerge from the chaos. Many of these pitfalls will become quite predictable and your inbox-friendly designs will take shape with them in mind.\n\nLooking ahead\n\nDesigning HTML email can be a tough pill for new designers and standardistas to swallow, especially given the fickle and retrospective nature of email clients today. With HTML5 just around the corner we are entering a new, uncertain phase. Will email client developers take the opportunity to repent on past mistakes and bring email clients into the present? The aim of groups such as the Email Standards Project is to make much of the above advice as redundant as the long-forgotten